Merge upstream

This commit is contained in:
S Gopal Rajagopal
2015-01-05 16:44:26 +05:30
169 changed files with 11377 additions and 7129 deletions
+1 -1
View File
@@ -19,7 +19,7 @@ __Windows__
* [Visual C++ Redistributable Packages for Visual Studio 2013](http://www.microsoft.com/en-us/download/details.aspx?id=40784) * [Visual C++ Redistributable Packages for Visual Studio 2013](http://www.microsoft.com/en-us/download/details.aspx?id=40784)
__Linux__ __Linux__
* Debian & Ubuntu: `sudo apt-get install libopenal-dev libwxgtk3.0-dev build-essential` * Debian & Ubuntu: `sudo apt-get install libopenal-dev libwxgtk3.0-dev build-essential libglew-dev`
__Mac OSX__ __Mac OSX__
* Install with Homebrew: `brew install glew wxwidgets` * Install with Homebrew: `brew install glew wxwidgets`
+9 -7
View File
@@ -11,13 +11,13 @@ using namespace Log;
LogManager *gLogManager = nullptr; LogManager *gLogManager = nullptr;
u32 LogMessage::size() u32 LogMessage::size() const
{ {
//1 byte for NULL terminator //1 byte for NULL terminator
return (u32)(sizeof(LogMessage::size_type) + sizeof(LogType) + sizeof(LogSeverity) + sizeof(std::string::value_type) * mText.size() + 1); return (u32)(sizeof(LogMessage::size_type) + sizeof(LogType) + sizeof(LogSeverity) + sizeof(std::string::value_type) * mText.size() + 1);
} }
void LogMessage::serialize(char *output) void LogMessage::serialize(char *output) const
{ {
LogMessage::size_type size = this->size(); LogMessage::size_type size = this->size();
memcpy(output, &size, sizeof(LogMessage::size_type)); memcpy(output, &size, sizeof(LogMessage::size_type));
@@ -60,7 +60,7 @@ LogChannel::LogChannel(const std::string& name) :
, mLogLevel(Warning) , mLogLevel(Warning)
{} {}
void LogChannel::log(LogMessage msg) void LogChannel::log(const LogMessage &msg)
{ {
std::lock_guard<std::mutex> lock(mListenerLock); std::lock_guard<std::mutex> lock(mListenerLock);
for (auto &listener : mListeners) for (auto &listener : mListeners)
@@ -82,7 +82,7 @@ void LogChannel::removeListener(std::shared_ptr<LogListener> listener)
struct CoutListener : LogListener struct CoutListener : LogListener
{ {
void log(LogMessage msg) void log(const LogMessage &msg)
{ {
std::cerr << msg.mText << std::endl; std::cerr << msg.mText << std::endl;
} }
@@ -103,13 +103,15 @@ struct FileListener : LogListener
} }
} }
void log(LogMessage msg) void log(const LogMessage &msg)
{ {
std::string text = msg.mText;
if (mPrependChannelName) if (mPrependChannelName)
{ {
msg.mText.insert(0, gTypeNameTable[static_cast<u32>(msg.mType)].mName); text.insert(0, gTypeNameTable[static_cast<u32>(msg.mType)].mName);
} }
mFile.Write(msg.mText); mFile.Write(text);
} }
}; };
+4 -4
View File
@@ -63,15 +63,15 @@ namespace Log
LogSeverity mServerity; LogSeverity mServerity;
std::string mText; std::string mText;
u32 size(); u32 size() const;
void serialize(char *output); void serialize(char *output) const;
static LogMessage deserialize(char *input, u32* size_out=nullptr); static LogMessage deserialize(char *input, u32* size_out=nullptr);
}; };
struct LogListener struct LogListener
{ {
virtual ~LogListener() {}; virtual ~LogListener() {};
virtual void log(LogMessage msg) = 0; virtual void log(const LogMessage &msg) = 0;
}; };
struct LogChannel struct LogChannel
@@ -80,7 +80,7 @@ namespace Log
LogChannel(const std::string& name); LogChannel(const std::string& name);
LogChannel(LogChannel& other) = delete; LogChannel(LogChannel& other) = delete;
LogChannel& operator = (LogChannel& other) = delete; LogChannel& operator = (LogChannel& other) = delete;
void log(LogMessage msg); void log(const LogMessage &msg);
void addListener(std::shared_ptr<LogListener> listener); void addListener(std::shared_ptr<LogListener> listener);
void removeListener(std::shared_ptr<LogListener> listener); void removeListener(std::shared_ptr<LogListener> listener);
std::string name; std::string name;
+3 -3
View File
@@ -30,7 +30,7 @@ public:
{ {
//wait until there's actually something to get //wait until there's actually something to get
//throwing an exception might be better, blocking here is a little awkward //throwing an exception might be better, blocking here is a little awkward
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
} }
size_t ret = mGet; size_t ret = mGet;
mGet = moveGet(); mGet = moveGet();
@@ -45,7 +45,7 @@ public:
{ {
//if this is reached a lot it's time to increase the buffer size //if this is reached a lot it's time to increase the buffer size
//or implement dynamic re-sizing //or implement dynamic re-sizing
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
} }
mBuffer[mPut] = std::forward(putEle); mBuffer[mPut] = std::forward(putEle);
mPut = movePut(); mPut = movePut();
@@ -94,7 +94,7 @@ public:
{ {
//if this is reached a lot it's time to increase the buffer size //if this is reached a lot it's time to increase the buffer size
//or implement dynamic re-sizing //or implement dynamic re-sizing
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
} }
if (mPut + length <= mBuffer.size()) if (mPut + length <= mBuffer.size())
{ {
-10
View File
@@ -1,10 +0,0 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/CPU/CPUThread.h"
#include "Utilities/SMutex.h"
bool SM_IsAborted()
{
return Emu.IsStopped();
}
-129
View File
@@ -1,129 +0,0 @@
#pragma once
#include "Emu/Memory/atomic_type.h"
bool SM_IsAborted();
enum SMutexResult
{
SMR_OK = 0, // succeeded (lock, trylock, unlock)
SMR_FAILED, // failed (trylock, unlock)
SMR_DEADLOCK, // mutex reached deadlock (lock, trylock)
SMR_SIGNAL = SMR_DEADLOCK, // unlock can be used for signaling specific thread
SMR_PERMITTED, // not owner of the mutex (unlock)
SMR_ABORT, // emulator has been stopped (lock, trylock, unlock)
SMR_DESTROYED, // mutex has been destroyed (lock, trylock, unlock)
SMR_TIMEOUT, // timed out (lock)
};
template
<
typename T,
const u64 free_value = 0,
const u64 dead_value = 0xffffffffffffffffull
>
class SMutexBase
{
static_assert(sizeof(T) == sizeof(atomic_le_t<T>), "Invalid SMutexBase type");
T owner;
typedef atomic_le_t<T> AT;
public:
static const T GetFreeValue()
{
static const u64 value = free_value;
return (T&)value;
}
static const T GetDeadValue()
{
static const u64 value = dead_value;
return (T&)value;
}
void initialize()
{
owner = GetFreeValue();
}
void finalize()
{
owner = GetDeadValue();
}
__forceinline T GetOwner() const
{
return (T&)owner;
}
SMutexResult trylock(T tid)
{
if (SM_IsAborted())
{
return SMR_ABORT;
}
T old = reinterpret_cast<AT&>(owner).compare_and_swap(GetFreeValue(), tid);
if (old != GetFreeValue())
{
if (old == tid)
{
return SMR_DEADLOCK;
}
if (old == GetDeadValue())
{
return SMR_DESTROYED;
}
return SMR_FAILED;
}
return SMR_OK;
}
SMutexResult unlock(T tid, T to = GetFreeValue())
{
if (SM_IsAborted())
{
return SMR_ABORT;
}
T old = reinterpret_cast<AT&>(owner).compare_and_swap(tid, to);
if (old != tid)
{
if (old == GetFreeValue())
{
return SMR_FAILED;
}
if (old == GetDeadValue())
{
return SMR_DESTROYED;
}
return SMR_PERMITTED;
}
return SMR_OK;
}
SMutexResult lock(T tid, u64 timeout = 0)
{
u64 counter = 0;
while (true)
{
switch (SMutexResult res = trylock(tid))
{
case SMR_FAILED: break;
default: return res;
}
std::this_thread::sleep_for(std::chrono::milliseconds(1));
if (timeout && counter++ > timeout)
{
return SMR_TIMEOUT;
}
}
}
};
typedef SMutexBase<u32> SMutex;
-118
View File
@@ -1,118 +0,0 @@
#pragma once
static const volatile bool sq_no_wait = true;
template<typename T, u32 SQSize = 666>
class SQueue
{
mutable std::mutex m_mutex;
u32 m_pos;
u32 m_count;
T m_data[SQSize];
public:
SQueue()
: m_pos(0)
, m_count(0)
{
}
u32 GetSize() const
{
return SQSize;
}
bool IsFull() const volatile
{
return m_count == SQSize;
}
bool Push(const T& data, const volatile bool* do_exit)
{
while (true)
{
if (m_count >= SQSize)
{
if (Emu.IsStopped() || (do_exit && *do_exit))
{
return false;
}
std::this_thread::sleep_for(std::chrono::milliseconds(1));
continue;
}
{
std::lock_guard<std::mutex> lock(m_mutex);
if (m_count >= SQSize) continue;
m_data[(m_pos + m_count++) % SQSize] = data;
return true;
}
}
}
bool Pop(T& data, const volatile bool* do_exit)
{
while (true)
{
if (!m_count)
{
if (Emu.IsStopped() || (do_exit && *do_exit))
{
return false;
}
std::this_thread::sleep_for(std::chrono::milliseconds(1));
continue;
}
{
std::lock_guard<std::mutex> lock(m_mutex);
if (!m_count) continue;
data = m_data[m_pos];
m_pos = (m_pos + 1) % SQSize;
m_count--;
return true;
}
}
}
void Clear()
{
std::lock_guard<std::mutex> lock(m_mutex);
m_count = 0;
}
bool Peek(T& data, const volatile bool* do_exit, u32 pos = 0)
{
while (true)
{
if (m_count <= pos)
{
if (Emu.IsStopped() || (do_exit && *do_exit))
{
return false;
}
std::this_thread::sleep_for(std::chrono::milliseconds(1));
continue;
}
{
std::lock_guard<std::mutex> lock(m_mutex);
if (m_count > pos)
{
break;
}
}
}
data = m_data[(m_pos + pos) % SQSize];
return true;
}
};
+25 -6
View File
@@ -137,23 +137,42 @@ std::vector<std::string> fmt::split(const std::string& source, std::initializer_
std::string fmt::merge(std::vector<std::string> source, const std::string& separator) std::string fmt::merge(std::vector<std::string> source, const std::string& separator)
{ {
std::string result; if (!source.size())
for (auto &s : source)
{ {
result += s + separator; return "";
} }
return result; std::string result;
for (int i = 0; i < source.size() - 1; ++i)
{
result += source[i] + separator;
}
return result + source[source.size() - 1];
} }
std::string fmt::merge(std::initializer_list<std::vector<std::string>> sources, const std::string& separator) std::string fmt::merge(std::initializer_list<std::vector<std::string>> sources, const std::string& separator)
{ {
if (!sources.size())
{
return "";
}
std::string result; std::string result;
bool first = true;
for (auto &v : sources) for (auto &v : sources)
{ {
result += fmt::merge(v, separator); if (first)
{
result = fmt::merge(v, separator);
first = false;
}
else
{
result += separator + fmt::merge(v, separator);
}
} }
return result; return result;
+15 -7
View File
@@ -249,7 +249,7 @@ bool waiter_map_t::is_stopped(u64 signal_id)
{ {
if (Emu.IsStopped()) if (Emu.IsStopped())
{ {
LOG_WARNING(Log::HLE, "%s.waiter_op() aborted (signal_id=0x%llx)", m_name.c_str(), signal_id); LOG_WARNING(Log::HLE, "%s: waiter_op() aborted (signal_id=0x%llx)", m_name.c_str(), signal_id);
return true; return true;
} }
return false; return false;
@@ -257,8 +257,8 @@ bool waiter_map_t::is_stopped(u64 signal_id)
void waiter_map_t::waiter_reg_t::init() void waiter_map_t::waiter_reg_t::init()
{ {
if (thread) return; if (!thread)
{
thread = GetCurrentNamedThread(); thread = GetCurrentNamedThread();
std::lock_guard<std::mutex> lock(map.m_mutex); std::lock_guard<std::mutex> lock(map.m_mutex);
@@ -266,11 +266,12 @@ void waiter_map_t::waiter_reg_t::init()
// add waiter // add waiter
map.m_waiters.push_back({ signal_id, thread }); map.m_waiters.push_back({ signal_id, thread });
} }
}
waiter_map_t::waiter_reg_t::~waiter_reg_t() waiter_map_t::waiter_reg_t::~waiter_reg_t()
{ {
if (!thread) return; if (thread)
{
std::lock_guard<std::mutex> lock(map.m_mutex); std::lock_guard<std::mutex> lock(map.m_mutex);
// remove waiter // remove waiter
@@ -286,11 +287,12 @@ waiter_map_t::waiter_reg_t::~waiter_reg_t()
LOG_ERROR(HLE, "%s(): waiter not found (signal_id=0x%llx, map='%s')", __FUNCTION__, signal_id, map.m_name.c_str()); LOG_ERROR(HLE, "%s(): waiter not found (signal_id=0x%llx, map='%s')", __FUNCTION__, signal_id, map.m_name.c_str());
Emu.Pause(); Emu.Pause();
} }
}
void waiter_map_t::notify(u64 signal_id) void waiter_map_t::notify(u64 signal_id)
{ {
if (!m_waiters.size()) return; if (m_waiters.size())
{
std::lock_guard<std::mutex> lock(m_mutex); std::lock_guard<std::mutex> lock(m_mutex);
// find waiter and signal // find waiter and signal
@@ -302,3 +304,9 @@ void waiter_map_t::notify(u64 signal_id)
} }
} }
} }
}
bool squeue_test_exit(const volatile bool* do_exit)
{
return Emu.IsStopped() || (do_exit && *do_exit);
}
+313 -29
View File
@@ -1,4 +1,5 @@
#pragma once #pragma once
#include "Emu/Memory/atomic_type.h"
static std::thread::id main_thread; static std::thread::id main_thread;
@@ -71,33 +72,6 @@ public:
bool joinable() const; 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_mutex_t
{ {
@@ -160,10 +134,10 @@ public:
// register waiter // register waiter
waiter_reg_t waiter(*this, signal_id); waiter_reg_t waiter(*this, signal_id);
// check condition or if emulator is stopped // check the condition or if the emulator is stopped
while (!waiter_func() && !is_stopped(signal_id)) while (!waiter_func() && !is_stopped(signal_id))
{ {
// initialize waiter (only first time) // initialize waiter (only once)
waiter.init(); waiter.init();
// wait for 1 ms or until signal arrived // wait for 1 ms or until signal arrived
waiter.thread->WaitForAnySignal(1); waiter.thread->WaitForAnySignal(1);
@@ -173,3 +147,313 @@ public:
// signal all threads waiting on waiter_op() with the same signal_id (signaling only hints those threads that corresponding conditions are *probably* met) // signal all threads waiting on waiter_op() with the same signal_id (signaling only hints those threads that corresponding conditions are *probably* met)
void notify(u64 signal_id); void notify(u64 signal_id);
}; };
bool squeue_test_exit(const volatile bool* do_exit);
template<typename T, u32 sq_size = 256>
class squeue_t
{
struct squeue_sync_var_t
{
struct
{
u32 position : 31;
u32 pop_lock : 1;
};
struct
{
u32 count : 31;
u32 push_lock : 1;
};
};
atomic_le_t<squeue_sync_var_t> m_sync;
mutable std::mutex m_rcv_mutex;
mutable std::mutex m_wcv_mutex;
mutable std::condition_variable m_rcv;
mutable std::condition_variable m_wcv;
T m_data[sq_size];
enum squeue_sync_var_result : u32
{
SQSVR_OK = 0,
SQSVR_LOCKED = 1,
SQSVR_FAILED = 2,
};
public:
squeue_t()
{
m_sync.write_relaxed({});
}
u32 get_max_size() const
{
return sq_size;
}
bool is_full() const volatile
{
return m_sync.read_relaxed().count == sq_size;
}
bool push(const T& data, const volatile bool* do_exit = nullptr)
{
u32 pos = 0;
while (u32 res = m_sync.atomic_op_sync(SQSVR_OK, [&pos](squeue_sync_var_t& sync) -> u32
{
assert(sync.count <= sq_size);
assert(sync.position < sq_size);
if (sync.push_lock)
{
return SQSVR_LOCKED;
}
if (sync.count == sq_size)
{
return SQSVR_FAILED;
}
sync.push_lock = 1;
pos = sync.position + sync.count;
return SQSVR_OK;
}))
{
if (res == SQSVR_FAILED && squeue_test_exit(do_exit))
{
return false;
}
std::unique_lock<std::mutex> wcv_lock(m_wcv_mutex);
m_wcv.wait_for(wcv_lock, std::chrono::milliseconds(1));
}
m_data[pos >= sq_size ? pos - sq_size : pos] = data;
m_sync.atomic_op([](squeue_sync_var_t& sync)
{
assert(sync.count <= sq_size);
assert(sync.position < sq_size);
assert(sync.push_lock);
sync.push_lock = 0;
sync.count++;
});
m_rcv.notify_one();
m_wcv.notify_one();
return true;
}
bool try_push(const T& data)
{
static const volatile bool no_wait = true;
return push(data, &no_wait);
}
bool pop(T& data, const volatile bool* do_exit = nullptr)
{
u32 pos = 0;
while (u32 res = m_sync.atomic_op_sync(SQSVR_OK, [&pos](squeue_sync_var_t& sync) -> u32
{
assert(sync.count <= sq_size);
assert(sync.position < sq_size);
if (!sync.count)
{
return SQSVR_FAILED;
}
if (sync.pop_lock)
{
return SQSVR_LOCKED;
}
sync.pop_lock = 1;
pos = sync.position;
return SQSVR_OK;
}))
{
if (res == SQSVR_FAILED && squeue_test_exit(do_exit))
{
return false;
}
std::unique_lock<std::mutex> rcv_lock(m_rcv_mutex);
m_rcv.wait_for(rcv_lock, std::chrono::milliseconds(1));
}
data = m_data[pos];
m_sync.atomic_op([](squeue_sync_var_t& sync)
{
assert(sync.count <= sq_size);
assert(sync.position < sq_size);
assert(sync.pop_lock);
sync.pop_lock = 0;
sync.position++;
sync.count--;
if (sync.position == sq_size)
{
sync.position = 0;
}
});
m_rcv.notify_one();
m_wcv.notify_one();
return true;
}
bool try_pop(T& data)
{
static const volatile bool no_wait = true;
return pop(data, &no_wait);
}
bool peek(T& data, u32 start_pos = 0, const volatile bool* do_exit = nullptr)
{
assert(start_pos < sq_size);
u32 pos = 0;
while (u32 res = m_sync.atomic_op_sync(SQSVR_OK, [&pos, start_pos](squeue_sync_var_t& sync) -> u32
{
assert(sync.count <= sq_size);
assert(sync.position < sq_size);
if (sync.count <= start_pos)
{
return SQSVR_FAILED;
}
if (sync.pop_lock)
{
return SQSVR_LOCKED;
}
sync.pop_lock = 1;
pos = sync.position + start_pos;
return SQSVR_OK;
}))
{
if (res == SQSVR_FAILED && squeue_test_exit(do_exit))
{
return false;
}
std::unique_lock<std::mutex> rcv_lock(m_rcv_mutex);
m_rcv.wait_for(rcv_lock, std::chrono::milliseconds(1));
}
data = m_data[pos >= sq_size ? pos - sq_size : pos];
m_sync.atomic_op([](squeue_sync_var_t& sync)
{
assert(sync.count <= sq_size);
assert(sync.position < sq_size);
assert(sync.pop_lock);
sync.pop_lock = 0;
});
m_rcv.notify_one();
return true;
}
bool try_peek(T& data, u32 start_pos = 0)
{
static const volatile bool no_wait = true;
return peek(data, start_pos, &no_wait);
}
class squeue_data_t
{
T* const m_data;
const u32 m_pos;
const u32 m_count;
squeue_data_t(T* data, u32 pos, u32 count)
: m_data(data)
, m_pos(pos)
, m_count(count)
{
}
public:
T& operator [] (u32 index)
{
assert(index < m_count);
index += m_pos;
index = index < sq_size ? index : index - sq_size;
return m_data[index];
}
};
void process(void(*proc)(squeue_data_t data))
{
u32 pos, count;
while (m_sync.atomic_op_sync(SQSVR_OK, [&pos, &count](squeue_sync_var_t& sync) -> u32
{
assert(sync.count <= sq_size);
assert(sync.position < sq_size);
if (sync.pop_lock || sync.push_lock)
{
return SQSVR_LOCKED;
}
pos = sync.position;
count = sync.count;
sync.pop_lock = 1;
sync.push_lock = 1;
return SQSVR_OK;
}))
{
std::unique_lock<std::mutex> rcv_lock(m_rcv_mutex);
m_rcv.wait_for(rcv_lock, std::chrono::milliseconds(1));
}
proc(squeue_data_t(m_data, pos, count));
m_sync.atomic_op([](squeue_sync_var_t& sync)
{
assert(sync.count <= sq_size);
assert(sync.position < sq_size);
assert(sync.pop_lock && sync.push_lock);
sync.pop_lock = 0;
sync.push_lock = 0;
});
m_wcv.notify_one();
m_rcv.notify_one();
}
void clear()
{
while (m_sync.atomic_op_sync(SQSVR_OK, [](squeue_sync_var_t& sync) -> u32
{
assert(sync.count <= sq_size);
assert(sync.position < sq_size);
if (sync.pop_lock || sync.push_lock)
{
return SQSVR_LOCKED;
}
sync.pop_lock = 1;
sync.push_lock = 1;
return SQSVR_OK;
}))
{
std::unique_lock<std::mutex> rcv_lock(m_rcv_mutex);
m_rcv.wait_for(rcv_lock, std::chrono::milliseconds(1));
}
m_sync.exchange({});
m_wcv.notify_one();
m_rcv.notify_one();
}
};
+1 -1
Submodule asmjit updated: 1318c9aff7...48da90ded7
+1 -1
Submodule ffmpeg updated: 352fdfbbfa...79a2d7a9f7
+4 -4
View File
@@ -43,13 +43,13 @@ bool CheckHeader(rFile& pkg_f, PKGHeader* m_header)
} }
if (m_header->pkg_size != pkg_f.Length()) { if (m_header->pkg_size != pkg_f.Length()) {
LOG_ERROR(LOADER, "PKG: File size mismatch."); LOG_WARNING(LOADER, "PKG: File size mismatch.");
return false; //return false;
} }
if (m_header->data_size + m_header->data_offset + 0x60 != pkg_f.Length()) { if (m_header->data_size + m_header->data_offset + 0x60 != pkg_f.Length()) {
LOG_ERROR(LOADER, "PKG: Data size mismatch."); LOG_WARNING(LOADER, "PKG: Data size mismatch.");
return false; //return false;
} }
return true; return true;
+26 -13
View File
@@ -1,35 +1,48 @@
#pragma once #pragma once
#include "Emu/CPU/CPUDecoder.h"
#include "ARMv7Opcodes.h"
#include "Emu/CPU/CPUDecoder.h"
#include "ARMv7Thread.h"
#include "ARMv7Interpreter.h"
#include "ARMv7Opcodes.h"
#include "Utilities/Log.h"
class ARMv7Decoder : public CPUDecoder class ARMv7Decoder : public CPUDecoder
{ {
ARMv7Opcodes& m_op; ARMv7Thread& m_thr;
u8 m_last_instr_size;
public: public:
ARMv7Decoder(ARMv7Opcodes& op) : m_op(op) ARMv7Decoder(ARMv7Thread& thr) : m_thr(thr)
{ {
} }
virtual u8 DecodeMemory(const u32 address) virtual u8 DecodeMemory(const u32 address)
{ {
const u32 code0 = vm::psv::read16(address & ~1); m_thr.update_code(address & ~1);
const u32 code1 = vm::psv::read16(address + 2 & ~1);
const u32 data = code0 << 16 | code1;
const u32 arg = address & 1 ? code1 << 16 | code0 : data;
// LOG_NOTICE(GENERAL, "code0 = 0x%04x, code1 = 0x%04x, data = 0x%08x", m_thr.code.code0, m_thr.code.code1, m_thr.code.data);
// LOG_NOTICE(GENERAL, "arg = 0x%08x", m_thr.m_arg);
// Emu.Pause();
// old decoding algorithm
/*
for (auto& opcode : ARMv7_opcode_table) for (auto& opcode : ARMv7_opcode_table)
{ {
if ((opcode.type < A1) == ((address & 1) == 0) && (arg & opcode.mask) == opcode.code) if ((opcode.type < A1) == ((address & 0x1) == 0) && (m_thr.m_arg & opcode.mask) == opcode.code)
{ {
(m_op.*opcode.func)(opcode.length == 2 ? code0 : arg, opcode.type); m_thr.code.data = opcode.length == 2 ? m_thr.code.code0 : m_thr.m_arg;
(*opcode.func)(&m_thr, opcode.type);
// LOG_NOTICE(GENERAL, "%s, %d \n\n", opcode.name, opcode.length);
return opcode.length; return opcode.length;
} }
} }
m_op.UNK(data); ARMv7_instrs::UNK(&m_thr);
return address & 1 ? 4 : 2; return address & 0x1 ? 4 : 2;
*/
execute_main_group(&m_thr);
// LOG_NOTICE(GENERAL, "%s, %d \n\n", m_thr.m_last_instr_name, m_thr.m_last_instr_size);
m_thr.m_last_instr_name = "Unknown";
return m_thr.m_last_instr_size;
} }
}; };
+1 -2
View File
@@ -12,10 +12,9 @@ static const char* g_arm_cond_name[16] =
class ARMv7DisAsm class ARMv7DisAsm
: public CPUDisAsm : public CPUDisAsm
, public ARMv7Opcodes
{ {
public: public:
ARMv7DisAsm(CPUDisAsmMode mode) : CPUDisAsm(mode) ARMv7DisAsm() : CPUDisAsm(CPUDisAsm_InterpreterMode)
{ {
} }
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+6 -2
View File
@@ -10,7 +10,11 @@
#include "ARMv7DisAsm.h" #include "ARMv7DisAsm.h"
#include "ARMv7Interpreter.h" #include "ARMv7Interpreter.h"
ARMv7Thread::ARMv7Thread() : CPUThread(CPU_THREAD_ARMv7) ARMv7Thread::ARMv7Thread()
: CPUThread(CPU_THREAD_ARMv7)
, m_arg(0)
, m_last_instr_size(0)
, m_last_instr_name("UNK")
{ {
} }
@@ -81,7 +85,7 @@ void ARMv7Thread::DoRun()
case 1: case 1:
case 2: case 2:
m_dec = new ARMv7Decoder(*new ARMv7Interpreter(*this)); m_dec = new ARMv7Decoder(*this);
break; break;
} }
} }
+26 -1
View File
@@ -1,17 +1,23 @@
#pragma once #pragma once
#include "Emu/CPU/CPUThread.h" #include "Emu/CPU/CPUThread.h"
#include "Emu/Memory/Memory.h"
enum ARMv7InstructionSet enum ARMv7InstructionSet
{ {
ARM, ARM,
Thumb, Thumb,
Jazelle, Jazelle,
ThumbEE, ThumbEE
}; };
class ARMv7Thread : public CPUThread class ARMv7Thread : public CPUThread
{ {
public: public:
u32 m_arg;
u8 m_last_instr_size;
const char* m_last_instr_name;
ARMv7Thread(); ARMv7Thread();
union union
@@ -61,6 +67,18 @@ public:
} IPSR; } IPSR;
union
{
struct
{
u32 code1 : 16;
u32 code0 : 16;
};
u32 data;
} code;
ARMv7InstructionSet ISET; ARMv7InstructionSet ISET;
union union
@@ -119,6 +137,13 @@ public:
return PC; return PC;
} }
void update_code(const u32 address)
{
code.code0 = vm::psv::read16(address & ~1);
code.code1 = vm::psv::read16(address + 2 & ~1);
m_arg = address & 0x1 ? code.code1 << 16 | code.code0 : code.data;
}
public: public:
virtual void InitRegs(); virtual void InitRegs();
virtual void InitStack(); virtual void InitStack();
+4 -4
View File
@@ -121,7 +121,7 @@ s32 sceKernelStartThread(s32 threadId, u32 argSize, vm::psv::ptr<const void> pAr
{ {
sceLibKernel.Error("sceKernelStartThread(threadId=%d, argSize=%d, pArgBlock_addr=0x%x)", threadId, argSize, pArgBlock.addr()); sceLibKernel.Error("sceKernelStartThread(threadId=%d, argSize=%d, pArgBlock_addr=0x%x)", threadId, argSize, pArgBlock.addr());
CPUThread* t = Emu.GetCPU().GetThread(threadId); std::shared_ptr<CPUThread> t = Emu.GetCPU().GetThread(threadId);
if (!t || t->GetType() != CPU_THREAD_ARMv7) if (!t || t->GetType() != CPU_THREAD_ARMv7)
{ {
@@ -129,12 +129,12 @@ s32 sceKernelStartThread(s32 threadId, u32 argSize, vm::psv::ptr<const void> pAr
} }
// push arg block onto the stack // push arg block onto the stack
u32 pos = (static_cast<ARMv7Thread*>(t)->SP -= argSize); u32 pos = (static_cast<ARMv7Thread*>(t.get())->SP -= argSize);
memcpy(vm::get_ptr<void>(pos), pArgBlock.get_ptr(), argSize); memcpy(vm::get_ptr<void>(pos), pArgBlock.get_ptr(), argSize);
// set SceKernelThreadEntry function arguments // set SceKernelThreadEntry function arguments
static_cast<ARMv7Thread*>(t)->write_gpr(0, argSize); static_cast<ARMv7Thread*>(t.get())->write_gpr(0, argSize);
static_cast<ARMv7Thread*>(t)->write_gpr(1, pos); static_cast<ARMv7Thread*>(t.get())->write_gpr(1, pos);
t->Exec(); t->Exec();
return SCE_OK; return SCE_OK;
+1
View File
@@ -1,4 +1,5 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Log.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/ARMv7/PSVFuncList.h" #include "Emu/ARMv7/PSVFuncList.h"
+1
View File
@@ -1,4 +1,5 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Log.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "PSVFuncList.h" #include "PSVFuncList.h"
+3
View File
@@ -82,6 +82,9 @@ struct AudioPortConfig
u64 attr; u64 attr;
u64 tag; u64 tag;
u64 counter; // copy of global counter u64 counter; // copy of global counter
u32 addr;
u32 read_index_addr;
u32 size;
}; };
struct AudioConfig //custom structure struct AudioConfig //custom structure
+3 -26
View File
@@ -21,8 +21,6 @@ CPUThread::CPUThread(CPUThreadType type)
, m_stack_addr(0) , m_stack_addr(0)
, m_offset(0) , m_offset(0)
, m_prio(0) , m_prio(0)
, m_sync_wait(false)
, m_wait_thread_id(-1)
, m_dec(nullptr) , m_dec(nullptr)
, m_is_step(false) , m_is_step(false)
, m_is_branch(false) , m_is_branch(false)
@@ -44,7 +42,7 @@ bool CPUThread::IsStopped() const { return m_status == Stopped; }
void CPUThread::Close() void CPUThread::Close()
{ {
ThreadBase::Stop(m_sync_wait); ThreadBase::Stop(false);
DoStop(); DoStop();
delete m_dec; delete m_dec;
@@ -55,9 +53,6 @@ void CPUThread::Reset()
{ {
CloseStack(); CloseStack();
m_sync_wait = 0;
m_wait_thread_id = -1;
SetPc(0); SetPc(0);
cycle = 0; cycle = 0;
m_is_branch = false; m_is_branch = false;
@@ -89,24 +84,6 @@ void CPUThread::SetName(const std::string& name)
NamedThreadBase::SetThreadName(name); NamedThreadBase::SetThreadName(name);
} }
void CPUThread::Wait(bool wait)
{
std::lock_guard<std::mutex> lock(m_cs_sync);
m_sync_wait = wait;
}
void CPUThread::Wait(const CPUThread& thr)
{
std::lock_guard<std::mutex> lock(m_cs_sync);
m_wait_thread_id = thr.GetId();
m_sync_wait = true;
}
bool CPUThread::Sync()
{
return m_sync_wait;
}
int CPUThread::ThreadStatus() int CPUThread::ThreadStatus()
{ {
if(Emu.IsStopped() || IsStopped() || IsPaused()) if(Emu.IsStopped() || IsStopped() || IsPaused())
@@ -124,7 +101,7 @@ int CPUThread::ThreadStatus()
return CPUThread_Step; return CPUThread_Step;
} }
if (Emu.IsPaused() || Sync()) if (Emu.IsPaused())
{ {
return CPUThread_Sleeping; return CPUThread_Sleeping;
} }
@@ -334,7 +311,7 @@ void CPUThread::Task()
if (status == CPUThread_Sleeping) if (status == CPUThread_Sleeping)
{ {
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
continue; continue;
} }
+1 -18
View File
@@ -136,23 +136,6 @@ protected:
public: public:
virtual ~CPUThread(); virtual ~CPUThread();
u32 m_wait_thread_id;
std::mutex m_cs_sync;
bool m_sync_wait;
void Wait(bool wait);
void Wait(const CPUThread& thr);
bool Sync();
template<typename T>
void WaitFor(T func)
{
while(func(ThreadStatus()))
{
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
}
int ThreadStatus(); int ThreadStatus();
void NextPc(u8 instr_size); void NextPc(u8 instr_size);
@@ -280,7 +263,7 @@ public:
thread->SetJoinable(false); thread->SetJoinable(false);
while (thread->IsRunning()) while (thread->IsRunning())
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
return thread->GetExitStatus(); return thread->GetExitStatus();
} }
+10 -16
View File
@@ -28,28 +28,28 @@ CPUThread& CPUThreadManager::AddThread(CPUThreadType type)
{ {
std::lock_guard<std::mutex> lock(m_mtx_thread); std::lock_guard<std::mutex> lock(m_mtx_thread);
CPUThread* new_thread; std::shared_ptr<CPUThread> new_thread;
switch(type) switch(type)
{ {
case CPU_THREAD_PPU: case CPU_THREAD_PPU:
{ {
new_thread = new PPUThread(); new_thread.reset(new PPUThread());
break; break;
} }
case CPU_THREAD_SPU: case CPU_THREAD_SPU:
{ {
new_thread = new SPUThread(); new_thread.reset(new SPUThread());
break; break;
} }
case CPU_THREAD_RAW_SPU: case CPU_THREAD_RAW_SPU:
{ {
new_thread = new RawSPUThread(); new_thread.reset(new RawSPUThread());
break; break;
} }
case CPU_THREAD_ARMv7: case CPU_THREAD_ARMv7:
{ {
new_thread = new ARMv7Thread(); new_thread.reset(new ARMv7Thread());
break; break;
} }
default: assert(0); default: assert(0);
@@ -58,7 +58,7 @@ CPUThread& CPUThreadManager::AddThread(CPUThreadType type)
new_thread->SetId(Emu.GetIdManager().GetNewID(fmt::Format("%s Thread", new_thread->GetTypeString().c_str()), new_thread)); new_thread->SetId(Emu.GetIdManager().GetNewID(fmt::Format("%s Thread", new_thread->GetTypeString().c_str()), new_thread));
m_threads.push_back(new_thread); m_threads.push_back(new_thread);
SendDbgCommand(DID_CREATE_THREAD, new_thread); SendDbgCommand(DID_CREATE_THREAD, new_thread.get());
return *new_thread; return *new_thread;
} }
@@ -67,17 +67,11 @@ void CPUThreadManager::RemoveThread(const u32 id)
{ {
std::lock_guard<std::mutex> lock(m_mtx_thread); std::lock_guard<std::mutex> lock(m_mtx_thread);
CPUThread* thr = nullptr; std::shared_ptr<CPUThread> thr;
u32 thread_index = 0; u32 thread_index = 0;
for (u32 i = 0; i < m_threads.size(); ++i) for (u32 i = 0; i < m_threads.size(); ++i)
{ {
if (m_threads[i]->m_wait_thread_id == id)
{
m_threads[i]->Wait(false);
m_threads[i]->m_wait_thread_id = -1;
}
if (m_threads[i]->GetId() != id) continue; if (m_threads[i]->GetId() != id) continue;
thr = m_threads[i]; thr = m_threads[i];
@@ -86,7 +80,7 @@ void CPUThreadManager::RemoveThread(const u32 id)
if (thr) if (thr)
{ {
SendDbgCommand(DID_REMOVE_THREAD, thr); SendDbgCommand(DID_REMOVE_THREAD, thr.get());
thr->Close(); thr->Close();
m_threads.erase(m_threads.begin() + thread_index); m_threads.erase(m_threads.begin() + thread_index);
@@ -112,9 +106,9 @@ s32 CPUThreadManager::GetThreadNumById(CPUThreadType type, u32 id)
return -1; return -1;
} }
CPUThread* CPUThreadManager::GetThread(u32 id) std::shared_ptr<CPUThread> CPUThreadManager::GetThread(u32 id)
{ {
CPUThread* res; std::shared_ptr<CPUThread> res;
if (!id) return nullptr; if (!id) return nullptr;
+3 -3
View File
@@ -6,7 +6,7 @@ enum CPUThreadType : unsigned char;
class CPUThreadManager class CPUThreadManager
{ {
std::vector<CPUThread*> m_threads; std::vector<std::shared_ptr<CPUThread>> m_threads;
std::mutex m_mtx_thread; std::mutex m_mtx_thread;
public: public:
@@ -18,9 +18,9 @@ public:
CPUThread& AddThread(CPUThreadType type); CPUThread& AddThread(CPUThreadType type);
void RemoveThread(const u32 id); void RemoveThread(const u32 id);
std::vector<CPUThread*>& GetThreads() { return m_threads; } //std::vector<std::shared_ptr<CPUThread>>& GetThreads() { return m_threads; }
s32 GetThreadNumById(CPUThreadType type, u32 id); s32 GetThreadNumById(CPUThreadType type, u32 id);
CPUThread* GetThread(u32 id); std::shared_ptr<CPUThread> GetThread(u32 id);
RawSPUThread* GetRawSPUThread(u32 num); RawSPUThread* GetRawSPUThread(u32 num);
void Exec(); void Exec();
+5 -6
View File
@@ -1030,14 +1030,13 @@ private:
Write(fmt::Format("bc [%x:%x:%x:%x:%x], cr%d[%x], 0x%x, %d, %d", bo0, bo1, bo2, bo3, bo4, bi/4, bi%4, bd, aa, lk)); Write(fmt::Format("bc [%x:%x:%x:%x:%x], cr%d[%x], 0x%x, %d, %d", bo0, bo1, bo2, bo3, bo4, bi/4, bi%4, bd, aa, lk));
} }
void SC(u32 sc_code) void SC(u32 lev)
{ {
switch(sc_code) switch (lev)
{ {
case 0x1: Write("HyperCall"); break; case 0x0: Write("sc"); break;
case 0x2: Write("sc"); break; case 0x1: Write("HyperCall LV1"); break;
case 0x22: Write("HyperCall LV1"); break; default: Write(fmt::Format("Unknown sc: 0x%x", lev));
default: Write(fmt::Format("Unknown sc: 0x%x", sc_code));
} }
} }
void B(s32 ll, u32 aa, u32 lk) void B(s32 ll, u32 aa, u32 lk)
+3 -3
View File
@@ -162,8 +162,8 @@ namespace PPU_instr
//This field mask is used to identify the CR fields that are to be updated by the mtcrf instruction. //This field mask is used to identify the CR fields that are to be updated by the mtcrf instruction.
static CodeField<12, 19> CRM; static CodeField<12, 19> CRM;
// // This field is used to identify the system call level
static CodeField<6, 31> SYS; static CodeField<20, 26> LEV;
//Immediate field specifying a 16-bit signed two's complement integer that is sign-extended to 64 bits //Immediate field specifying a 16-bit signed two's complement integer that is sign-extended to 64 bits
static CodeFieldSigned<16, 31> D; static CodeFieldSigned<16, 31> D;
@@ -238,7 +238,7 @@ namespace PPU_instr
bind_instr(main_list, ADDI, RD, RA, simm16); bind_instr(main_list, ADDI, RD, RA, simm16);
bind_instr(main_list, ADDIS, RD, RA, simm16); bind_instr(main_list, ADDIS, RD, RA, simm16);
bind_instr(main_list, BC, BO, BI, BD, AA, LK); bind_instr(main_list, BC, BO, BI, BD, AA, LK);
bind_instr(main_list, SC, SYS); bind_instr(main_list, SC, LEV);
bind_instr(main_list, B, LI, AA, LK); bind_instr(main_list, B, LI, AA, LK);
bind_instr(main_list, RLWIMI, RA, RS, SH, MB, ME, RC); bind_instr(main_list, RLWIMI, RA, RS, SH, MB, ME, RC);
bind_instr(main_list, RLWINM, RA, RS, SH, MB, ME, RC); bind_instr(main_list, RLWINM, RA, RS, SH, MB, ME, RC);
+15 -9
View File
@@ -2164,13 +2164,13 @@ private:
if(lk) CPU.LR = nextLR; if(lk) CPU.LR = nextLR;
} }
} }
void SC(u32 sc_code) void SC(u32 lev)
{ {
switch(sc_code) switch (lev)
{ {
case 0x1: UNK(fmt::Format("HyperCall %d", CPU.GPR[0])); break; case 0x0: SysCall(); break;
case 0x2: SysCall(); break; case 0x1: UNK("HyperCall LV1"); break;
case 0x3: case 0x2:
Emu.GetSFuncManager().StaticExecute(CPU, (u32)CPU.GPR[11]); Emu.GetSFuncManager().StaticExecute(CPU, (u32)CPU.GPR[11]);
if (Ini.HLELogging.GetValue()) if (Ini.HLELogging.GetValue())
{ {
@@ -2178,9 +2178,8 @@ private:
Emu.GetSFuncManager()[CPU.GPR[11]]->name, CPU.GPR[3], CPU.PC); Emu.GetSFuncManager()[CPU.GPR[11]]->name, CPU.GPR[3], CPU.PC);
} }
break; break;
case 0x4: CPU.FastStop(); break; case 0x3: CPU.FastStop(); break;
case 0x22: UNK("HyperCall LV1"); break; default: UNK(fmt::Format("Unknown sc: 0x%x", lev)); break;
default: UNK(fmt::Format("Unknown sc: 0x%x", sc_code));
} }
} }
void B(s32 ll, u32 aa, u32 lk) void B(s32 ll, u32 aa, u32 lk)
@@ -3665,7 +3664,14 @@ private:
void DCBZ(u32 ra, u32 rb) void DCBZ(u32 ra, u32 rb)
{ {
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
auto const cache_line = vm::get_ptr<u8>(addr & ~127); if ((u32)addr != addr)
{
LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr);
Emu.Pause();
return;
}
auto const cache_line = vm::get_ptr<u8>((u32)addr & ~127);
if (cache_line) if (cache_line)
memset(cache_line, 0, 128); memset(cache_line, 0, 128);
} }
+6 -6
View File
@@ -1995,20 +1995,20 @@ void Compiler::BC(u32 bo, u32 bi, s32 bd, u32 aa, u32 lk) {
CreateBranch(CheckBranchCondition(bo, bi), target_i32, lk ? true : false); CreateBranch(CheckBranchCondition(bo, bi), target_i32, lk ? true : false);
} }
void Compiler::SC(u32 sc_code) { void Compiler::SC(u32 lev) {
switch (sc_code) { switch (lev) {
case 2: case 0:
Call<void>("SysCalls.DoSyscall", SysCalls::DoSyscall, m_state.args[CompileTaskState::Args::State], GetGpr(11)); Call<void>("SysCalls.DoSyscall", SysCalls::DoSyscall, m_state.args[CompileTaskState::Args::State], GetGpr(11));
break; break;
case 3: case 2:
Call<void>("StaticFuncManager.StaticExecute", &StaticFuncManager::StaticExecute, Call<void>("StaticFuncManager.StaticExecute", &StaticFuncManager::StaticExecute,
m_ir_builder->getInt64((u64)&Emu.GetSFuncManager()), m_state.args[CompileTaskState::Args::State], GetGpr(11, 32)); m_ir_builder->getInt64((u64)&Emu.GetSFuncManager()), m_state.args[CompileTaskState::Args::State], GetGpr(11, 32));
break; break;
case 4: case 3:
Call<void>("PPUThread.FastStop", &PPUThread::FastStop, m_state.args[CompileTaskState::Args::State]); Call<void>("PPUThread.FastStop", &PPUThread::FastStop, m_state.args[CompileTaskState::Args::State]);
break; break;
default: default:
CompilationError(fmt::Format("SC %u", sc_code)); CompilationError(fmt::Format("SC %u", lev));
break; break;
} }
} }
+3 -1
View File
@@ -451,6 +451,8 @@ namespace PPU_opcodes
class PPUOpcodes class PPUOpcodes
{ {
public: public:
virtual ~PPUOpcodes() {}
static u32 branchTarget(const u32 pc, const u32 imm) static u32 branchTarget(const u32 pc, const u32 imm)
{ {
return pc + (imm & ~0x3ULL); return pc + (imm & ~0x3ULL);
@@ -628,7 +630,7 @@ public:
virtual void ADDI(u32 rd, u32 ra, s32 simm16) = 0; virtual void ADDI(u32 rd, u32 ra, s32 simm16) = 0;
virtual void ADDIS(u32 rd, u32 ra, s32 simm16) = 0; virtual void ADDIS(u32 rd, u32 ra, s32 simm16) = 0;
virtual void BC(u32 bo, u32 bi, s32 bd, u32 aa, u32 lk) = 0; virtual void BC(u32 bo, u32 bi, s32 bd, u32 aa, u32 lk) = 0;
virtual void SC(u32 sc_code) = 0; virtual void SC(u32 lev) = 0;
virtual void B(s32 ll, u32 aa, u32 lk) = 0; virtual void B(s32 ll, u32 aa, u32 lk) = 0;
virtual void MCRF(u32 crfd, u32 crfs) = 0; virtual void MCRF(u32 crfd, u32 crfs) = 0;
virtual void BCLR(u32 bo, u32 bi, u32 bh, u32 lk) = 0; virtual void BCLR(u32 bo, u32 bi, u32 bh, u32 lk) = 0;
+2
View File
@@ -229,6 +229,8 @@ namespace SPU_opcodes
class SPUOpcodes class SPUOpcodes
{ {
public: public:
virtual ~SPUOpcodes() {}
static u32 branchTarget(const u32 pc, const s32 imm) static u32 branchTarget(const u32 pc, const s32 imm)
{ {
return (pc + (imm << 2)) & 0x3fffc; return (pc + (imm << 2)) & 0x3fffc;
-2
View File
@@ -1,7 +1,5 @@
#pragma once #pragma once
#include "Emu/SysCalls/Modules/cellSpurs.h"
class SPURSManagerEventFlag class SPURSManagerEventFlag
{ {
public: public:
+1 -1
View File
@@ -25,7 +25,7 @@ SPURecompilerCore::SPURecompilerCore(SPUThread& cpu)
memset(entry, 0, sizeof(entry)); memset(entry, 0, sizeof(entry));
X86CpuInfo inf; X86CpuInfo inf;
X86CpuUtil::detect(&inf); X86CpuUtil::detect(&inf);
if (!inf.hasFeature(kX86CpuFeatureSse41)) if (!inf.hasFeature(kX86CpuFeatureSSE4_1))
{ {
LOG_ERROR(SPU, "SPU JIT requires SSE4.1 instruction set support"); LOG_ERROR(SPU, "SPU JIT requires SSE4.1 instruction set support");
Emu.Pause(); Emu.Pause();
+103 -70
View File
@@ -3,6 +3,7 @@
#include "Utilities/Log.h" #include "Utilities/Log.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/Memory/atomic_type.h"
#include "Emu/IdManager.h" #include "Emu/IdManager.h"
#include "Emu/CPU/CPUThreadManager.h" #include "Emu/CPU/CPUThreadManager.h"
@@ -37,6 +38,10 @@ SPUThread::SPUThread(CPUThreadType type) : PPCThread(type)
assert(type == CPU_THREAD_SPU || type == CPU_THREAD_RAW_SPU); assert(type == CPU_THREAD_SPU || type == CPU_THREAD_RAW_SPU);
group = nullptr; group = nullptr;
for (auto& p : SPUPs)
{
p.reset(new EventPort());
}
Reset(); Reset();
} }
@@ -136,12 +141,12 @@ void SPUThread::DoClose()
} }
for (u32 i = 0; i < 64; i++) for (u32 i = 0; i < 64; i++)
{ {
EventPort& port = SPUPs[i]; std::shared_ptr<EventPort> port = SPUPs[i];
std::lock_guard<std::mutex> lock(port.m_mutex); std::lock_guard<std::mutex> lock(port->m_mutex);
if (port.eq) if (port->eq)
{ {
port.eq->ports.remove(&port); port->eq->ports.remove(port);
port.eq = nullptr; port->eq = nullptr;
} }
} }
} }
@@ -208,17 +213,17 @@ void SPUThread::ProcessCmd(u32 cmd, u32 tag, u32 lsa, u64 ea, u32 size)
return; return;
} }
SPUThread* spu = (SPUThread*)Emu.GetCPU().GetThread(group->list[num]); std::shared_ptr<CPUThread> spu = Emu.GetCPU().GetThread(group->list[num]);
u32 addr = (ea & SYS_SPU_THREAD_BASE_MASK) % SYS_SPU_THREAD_OFFSET; u32 addr = (ea & SYS_SPU_THREAD_BASE_MASK) % SYS_SPU_THREAD_OFFSET;
if ((addr <= 0x3ffff) && (addr + size <= 0x40000)) if ((addr <= 0x3ffff) && (addr + size <= 0x40000))
{ {
// LS access // LS access
ea = spu->ls_offset + addr; ea = ((SPUThread*)spu.get())->ls_offset + addr;
} }
else if ((cmd & MFC_PUT_CMD) && size == 4 && (addr == SYS_SPU_THREAD_SNR1 || addr == SYS_SPU_THREAD_SNR2)) else if ((cmd & MFC_PUT_CMD) && size == 4 && (addr == SYS_SPU_THREAD_SNR1 || addr == SYS_SPU_THREAD_SNR2))
{ {
spu->WriteSNR(SYS_SPU_THREAD_SNR2 == addr, vm::read32(ls_offset + lsa)); ((SPUThread*)spu.get())->WriteSNR(SYS_SPU_THREAD_SNR2 == addr, vm::read32(ls_offset + lsa));
return; return;
} }
else else
@@ -587,7 +592,7 @@ void SPUThread::WriteChannel(u32 ch, const u128& r)
if (Ini.HLELogging.GetValue()) LOG_NOTICE(Log::SPU, "SPU_WrOutIntrMbox: interrupt(v=0x%x)", v); if (Ini.HLELogging.GetValue()) LOG_NOTICE(Log::SPU, "SPU_WrOutIntrMbox: interrupt(v=0x%x)", v);
while (!SPU.Out_IntrMBox.Push(v)) while (!SPU.Out_IntrMBox.Push(v))
{ {
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
if (Emu.IsStopped()) if (Emu.IsStopped())
{ {
LOG_WARNING(Log::SPU, "%s(%s) aborted", __FUNCTION__, spu_ch_name[ch]); LOG_WARNING(Log::SPU, "%s(%s) aborted", __FUNCTION__, spu_ch_name[ch]);
@@ -595,7 +600,7 @@ void SPUThread::WriteChannel(u32 ch, const u128& r)
} }
} }
m_intrtag[2].stat |= 1; m_intrtag[2].stat |= 1;
if (CPUThread* t = Emu.GetCPU().GetThread(m_intrtag[2].thread)) if (std::shared_ptr<CPUThread> t = Emu.GetCPU().GetThread(m_intrtag[2].thread))
{ {
if (t->GetType() == CPU_THREAD_PPU) if (t->GetType() == CPU_THREAD_PPU)
{ {
@@ -605,7 +610,7 @@ void SPUThread::WriteChannel(u32 ch, const u128& r)
Emu.Pause(); Emu.Pause();
return; return;
} }
PPUThread& ppu = *(PPUThread*)t; PPUThread& ppu = *(PPUThread*)t.get();
ppu.GPR[3] = ppu.m_interrupt_arg; ppu.GPR[3] = ppu.m_interrupt_arg;
ppu.FastCall2(vm::read32(ppu.entry), vm::read32(ppu.entry + 4)); ppu.FastCall2(vm::read32(ppu.entry), vm::read32(ppu.entry + 4));
} }
@@ -632,18 +637,18 @@ void SPUThread::WriteChannel(u32 ch, const u128& r)
LOG_NOTICE(Log::SPU, "sys_spu_thread_send_event(spup=%d, data0=0x%x, data1=0x%x)", spup, v & 0x00ffffff, data); LOG_NOTICE(Log::SPU, "sys_spu_thread_send_event(spup=%d, data0=0x%x, data1=0x%x)", spup, v & 0x00ffffff, data);
} }
EventPort& port = SPUPs[spup]; std::shared_ptr<EventPort> port = SPUPs[spup];
std::lock_guard<std::mutex> lock(port.m_mutex); std::lock_guard<std::mutex> lock(port->m_mutex);
if (!port.eq) if (!port->eq)
{ {
LOG_WARNING(Log::SPU, "sys_spu_thread_send_event(spup=%d, data0=0x%x, data1=0x%x): event queue not connected", spup, (v & 0x00ffffff), data); LOG_WARNING(Log::SPU, "sys_spu_thread_send_event(spup=%d, data0=0x%x, data1=0x%x): event queue not connected", spup, (v & 0x00ffffff), data);
SPU.In_MBox.PushUncond(CELL_ENOTCONN); // TODO: check error passing SPU.In_MBox.PushUncond(CELL_ENOTCONN); // TODO: check error passing
return; return;
} }
if (!port.eq->events.push(SYS_SPU_THREAD_EVENT_USER_KEY, GetId(), ((u64)spup << 32) | (v & 0x00ffffff), data)) if (!port->eq->events.push(SYS_SPU_THREAD_EVENT_USER_KEY, GetId(), ((u64)spup << 32) | (v & 0x00ffffff), data))
{ {
SPU.In_MBox.PushUncond(CELL_EBUSY); SPU.In_MBox.PushUncond(CELL_EBUSY);
return; return;
@@ -670,18 +675,18 @@ void SPUThread::WriteChannel(u32 ch, const u128& r)
LOG_WARNING(Log::SPU, "sys_spu_thread_throw_event(spup=%d, data0=0x%x, data1=0x%x)", spup, v & 0x00ffffff, data); LOG_WARNING(Log::SPU, "sys_spu_thread_throw_event(spup=%d, data0=0x%x, data1=0x%x)", spup, v & 0x00ffffff, data);
} }
EventPort& port = SPUPs[spup]; std::shared_ptr<EventPort> port = SPUPs[spup];
std::lock_guard<std::mutex> lock(port.m_mutex); std::lock_guard<std::mutex> lock(port->m_mutex);
if (!port.eq) if (!port->eq)
{ {
LOG_WARNING(Log::SPU, "sys_spu_thread_throw_event(spup=%d, data0=0x%x, data1=0x%x): event queue not connected", spup, (v & 0x00ffffff), data); LOG_WARNING(Log::SPU, "sys_spu_thread_throw_event(spup=%d, data0=0x%x, data1=0x%x): event queue not connected", spup, (v & 0x00ffffff), data);
return; return;
} }
// TODO: check passing spup value // TODO: check passing spup value
if (!port.eq->events.push(SYS_SPU_THREAD_EVENT_USER_KEY, GetId(), ((u64)spup << 32) | (v & 0x00ffffff), data)) if (!port->eq->events.push(SYS_SPU_THREAD_EVENT_USER_KEY, GetId(), ((u64)spup << 32) | (v & 0x00ffffff), data))
{ {
LOG_WARNING(Log::SPU, "sys_spu_thread_throw_event(spup=%d, data0=0x%x, data1=0x%x) failed (queue is full)", spup, (v & 0x00ffffff), data); LOG_WARNING(Log::SPU, "sys_spu_thread_throw_event(spup=%d, data0=0x%x, data1=0x%x) failed (queue is full)", spup, (v & 0x00ffffff), data);
return; return;
@@ -712,7 +717,7 @@ void SPUThread::WriteChannel(u32 ch, const u128& r)
LOG_WARNING(Log::SPU, "sys_event_flag_set_bit(id=%d, v=0x%x (flag=%d))", data, v, flag); LOG_WARNING(Log::SPU, "sys_event_flag_set_bit(id=%d, v=0x%x (flag=%d))", data, v, flag);
} }
EventFlag* ef; std::shared_ptr<EventFlag> ef;
if (!Emu.GetIdManager().GetIDData(data, ef)) if (!Emu.GetIdManager().GetIDData(data, ef))
{ {
LOG_ERROR(Log::SPU, "sys_event_flag_set_bit(id=%d, v=0x%x (flag=%d)): EventFlag not found", data, v, flag); LOG_ERROR(Log::SPU, "sys_event_flag_set_bit(id=%d, v=0x%x (flag=%d)): EventFlag not found", data, v, flag);
@@ -720,21 +725,13 @@ void SPUThread::WriteChannel(u32 ch, const u128& r)
return; return;
} }
const u32 tid = GetId(); std::lock_guard<std::mutex> lock(ef->mutex);
ef->m_mutex.lock(tid);
ef->flags |= (u64)1 << flag; ef->flags |= (u64)1 << flag;
if (u32 target = ef->check()) if (u32 target = ef->check())
{ {
// if signal, leave both mutexes locked... ef->signal.push(target);
ef->signal.lock(target);
ef->m_mutex.unlock(tid, target);
} }
else
{
ef->m_mutex.unlock(tid);
}
SPU.In_MBox.PushUncond(CELL_OK); SPU.In_MBox.PushUncond(CELL_OK);
return; return;
} }
@@ -761,28 +758,20 @@ void SPUThread::WriteChannel(u32 ch, const u128& r)
LOG_WARNING(Log::SPU, "sys_event_flag_set_bit_impatient(id=%d, v=0x%x (flag=%d))", data, v, flag); LOG_WARNING(Log::SPU, "sys_event_flag_set_bit_impatient(id=%d, v=0x%x (flag=%d))", data, v, flag);
} }
EventFlag* ef; std::shared_ptr<EventFlag> ef;
if (!Emu.GetIdManager().GetIDData(data, ef)) if (!Emu.GetIdManager().GetIDData(data, ef))
{ {
LOG_WARNING(Log::SPU, "sys_event_flag_set_bit_impatient(id=%d, v=0x%x (flag=%d)): EventFlag not found", data, v, flag); LOG_WARNING(Log::SPU, "sys_event_flag_set_bit_impatient(id=%d, v=0x%x (flag=%d)): EventFlag not found", data, v, flag);
return; return;
} }
const u32 tid = GetId(); std::lock_guard<std::mutex> lock(ef->mutex);
ef->m_mutex.lock(tid);
ef->flags |= (u64)1 << flag; ef->flags |= (u64)1 << flag;
if (u32 target = ef->check()) if (u32 target = ef->check())
{ {
// if signal, leave both mutexes locked... ef->signal.push(target);
ef->signal.lock(target);
ef->m_mutex.unlock(tid, target);
} }
else
{
ef->m_mutex.unlock(tid);
}
return; return;
} }
else else
@@ -805,7 +794,10 @@ void SPUThread::WriteChannel(u32 ch, const u128& r)
case SPU_WrOutMbox: case SPU_WrOutMbox:
{ {
while (!SPU.Out_MBox.Push(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1)); while (!SPU.Out_MBox.Push(v) && !Emu.IsStopped())
{
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
}
break; break;
} }
@@ -916,13 +908,19 @@ void SPUThread::ReadChannel(u128& r, u32 ch)
{ {
case SPU_RdInMbox: case SPU_RdInMbox:
{ {
while (!SPU.In_MBox.Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1)); while (!SPU.In_MBox.Pop(v) && !Emu.IsStopped())
{
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
}
break; break;
} }
case MFC_RdTagStat: case MFC_RdTagStat:
{ {
while (!MFC1.TagStatus.Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1)); while (!MFC1.TagStatus.Pop(v) && !Emu.IsStopped())
{
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
}
break; break;
} }
@@ -936,11 +934,17 @@ void SPUThread::ReadChannel(u128& r, u32 ch)
{ {
if (cfg.value & 1) if (cfg.value & 1)
{ {
while (!SPU.SNR[0].Pop_XCHG(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1)); while (!SPU.SNR[0].Pop_XCHG(v) && !Emu.IsStopped())
{
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
}
} }
else else
{ {
while (!SPU.SNR[0].Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1)); while (!SPU.SNR[0].Pop(v) && !Emu.IsStopped())
{
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
}
} }
break; break;
} }
@@ -949,24 +953,36 @@ void SPUThread::ReadChannel(u128& r, u32 ch)
{ {
if (cfg.value & 2) if (cfg.value & 2)
{ {
while (!SPU.SNR[1].Pop_XCHG(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1)); while (!SPU.SNR[1].Pop_XCHG(v) && !Emu.IsStopped())
{
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
}
} }
else else
{ {
while (!SPU.SNR[1].Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1)); while (!SPU.SNR[1].Pop(v) && !Emu.IsStopped())
{
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
}
} }
break; break;
} }
case MFC_RdAtomicStat: case MFC_RdAtomicStat:
{ {
while (!MFC1.AtomicStat.Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1)); while (!MFC1.AtomicStat.Pop(v) && !Emu.IsStopped())
{
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
}
break; break;
} }
case MFC_RdListStallStat: case MFC_RdListStallStat:
{ {
while (!StallStat.Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1)); while (!StallStat.Pop(v) && !Emu.IsStopped())
{
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
}
break; break;
} }
@@ -984,7 +1000,10 @@ void SPUThread::ReadChannel(u128& r, u32 ch)
case SPU_RdEventStat: case SPU_RdEventStat:
{ {
while (!CheckEvents() && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1)); while (!CheckEvents() && !Emu.IsStopped())
{
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
}
v = m_events & m_event_mask; v = m_events & m_event_mask;
break; break;
} }
@@ -1057,7 +1076,7 @@ void SPUThread::StopAndSignal(u32 code)
LOG_NOTICE(Log::SPU, "sys_spu_thread_receive_event(spuq=0x%x)", spuq); LOG_NOTICE(Log::SPU, "sys_spu_thread_receive_event(spuq=0x%x)", spuq);
} }
EventQueue* eq; std::shared_ptr<EventQueue> eq;
if (!SPUQs.GetEventQueue(FIX_SPUQ(spuq), eq)) if (!SPUQs.GetEventQueue(FIX_SPUQ(spuq), eq))
{ {
SPU.In_MBox.PushUncond(CELL_EINVAL); // TODO: check error value SPU.In_MBox.PushUncond(CELL_EINVAL); // TODO: check error value
@@ -1066,47 +1085,61 @@ void SPUThread::StopAndSignal(u32 code)
u32 tid = GetId(); u32 tid = GetId();
eq->sq.push(tid); // add thread to sleep queue eq->sq.push(tid, eq->protocol); // add thread to sleep queue
while (true) while (true)
{ {
switch (eq->owner.trylock(tid)) u32 old_owner = eq->owner.compare_and_swap(0, tid);
switch (s32 res = old_owner ? (old_owner == tid ? 1 : 2) : 0)
{ {
case SMR_OK: case 0:
if (!eq->events.count())
{ {
eq->owner.unlock(tid); const u32 next = eq->events.count() ? eq->sq.signal(eq->protocol) : 0;
break;
}
else
{
u32 next = (eq->protocol == SYS_SYNC_FIFO) ? eq->sq.pop() : eq->sq.pop_prio();
if (next != tid) if (next != tid)
{ {
eq->owner.unlock(tid, next); if (!eq->owner.compare_and_swap_test(tid, next))
{
assert(!"sys_spu_thread_receive_event() failed (I)");
}
break; break;
} }
// fallthrough
} }
case SMR_SIGNAL: case 1:
{ {
sys_event_data event; sys_event_data event;
eq->events.pop(event); eq->events.pop(event);
eq->owner.unlock(tid); if (!eq->owner.compare_and_swap_test(tid, 0))
{
assert(!"sys_spu_thread_receive_event() failed (II)");
}
SPU.In_MBox.PushUncond(CELL_OK); SPU.In_MBox.PushUncond(CELL_OK);
SPU.In_MBox.PushUncond((u32)event.data1); SPU.In_MBox.PushUncond((u32)event.data1);
SPU.In_MBox.PushUncond((u32)event.data2); SPU.In_MBox.PushUncond((u32)event.data2);
SPU.In_MBox.PushUncond((u32)event.data3); SPU.In_MBox.PushUncond((u32)event.data3);
if (!eq->sq.invalidate(tid, eq->protocol) && !eq->sq.pop(tid, eq->protocol))
{
assert(!"sys_spu_thread_receive_event() failed (receiving)");
}
return; return;
} }
case SMR_FAILED: break;
default: eq->sq.invalidate(tid); SPU.In_MBox.PushUncond(CELL_ECANCELED); return;
} }
std::this_thread::sleep_for(std::chrono::milliseconds(1)); if (!~old_owner)
{
if (!eq->sq.invalidate(tid, eq->protocol))
{
assert(!"sys_spu_thread_receive_event() failed (cancelling)");
}
SPU.In_MBox.PushUncond(CELL_ECANCELED);
return;
}
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
if (Emu.IsStopped()) if (Emu.IsStopped())
{ {
LOG_WARNING(Log::SPU, "sys_spu_thread_receive_event(spuq=0x%x) aborted", spuq); LOG_WARNING(Log::SPU, "sys_spu_thread_receive_event(spuq=0x%x) aborted", spuq);
eq->sq.invalidate(tid);
return; return;
} }
} }
@@ -1135,7 +1168,7 @@ void SPUThread::StopAndSignal(u32 code)
group->m_exit_status = SPU.Out_MBox.GetValue(); group->m_exit_status = SPU.Out_MBox.GetValue();
for (auto& v : group->list) for (auto& v : group->list)
{ {
if (CPUThread* t = Emu.GetCPU().GetThread(v)) if (std::shared_ptr<CPUThread> t = Emu.GetCPU().GetThread(v))
{ {
t->Stop(); t->Stop();
} }
+4 -2
View File
@@ -1,6 +1,8 @@
#pragma once #pragma once
#include "Emu/Memory/atomic_type.h" #include "Emu/Memory/atomic_type.h"
#include "PPCThread.h" #include "PPCThread.h"
#include "Emu/SysCalls/lv2/sleep_queue_type.h"
#include "Emu/SysCalls/lv2/sys_event.h"
#include "Emu/Event.h" #include "Emu/Event.h"
#include "MFC.h" #include "MFC.h"
@@ -281,9 +283,9 @@ public:
u64 R_ADDR; // reservation address u64 R_ADDR; // reservation address
u64 R_DATA[16]; // lock line data (BE) u64 R_DATA[16]; // lock line data (BE)
EventPort SPUPs[64]; // SPU Thread Event Ports std::shared_ptr<EventPort> SPUPs[64]; // SPU Thread Event Ports
EventManager SPUQs; // SPU Queue Mapping EventManager SPUQs; // SPU Queue Mapping
SpuGroupInfo* group; // associated SPU Thread Group (null for raw spu) std::shared_ptr<SpuGroupInfo> group; // associated SPU Thread Group (null for raw spu)
u64 m_dec_start; // timestamp of writing decrementer value u64 m_dec_start; // timestamp of writing decrementer value
u32 m_dec_value; // written decrementer value u32 m_dec_value; // written decrementer value
+7 -5
View File
@@ -1,6 +1,9 @@
#include "stdafx.h" #include "stdafx.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
//#include "Emu/System.h" #include "Emu/Memory/atomic_type.h"
#include "Emu/SysCalls/lv2/sleep_queue_type.h"
#include "Emu/SysCalls/lv2/sys_event.h"
#include "Event.h" #include "Event.h"
void EventManager::Init() void EventManager::Init()
@@ -20,7 +23,7 @@ bool EventManager::CheckKey(u64 key)
return key_map.find(key) != key_map.end(); return key_map.find(key) != key_map.end();
} }
bool EventManager::RegisterKey(EventQueue* data, u64 key) bool EventManager::RegisterKey(std::shared_ptr<EventQueue>& data, u64 key)
{ {
if (!key) return true; if (!key) return true;
std::lock_guard<std::mutex> lock(m_lock); std::lock_guard<std::mutex> lock(m_lock);
@@ -37,7 +40,7 @@ bool EventManager::RegisterKey(EventQueue* data, u64 key)
return true; return true;
} }
bool EventManager::GetEventQueue(u64 key, EventQueue*& data) bool EventManager::GetEventQueue(u64 key, std::shared_ptr<EventQueue>& data)
{ {
data = nullptr; data = nullptr;
if (!key) return false; if (!key) return false;
@@ -76,8 +79,7 @@ bool EventManager::SendEvent(u64 key, u64 source, u64 d1, u64 d2, u64 d3)
{ {
return false; return false;
} }
EventQueue* eq = f->second;
eq->events.push(source, d1, d2, d3); f->second->events.push(source, d1, d2, d3);
return true; return true;
} }
+5 -4
View File
@@ -1,18 +1,19 @@
#pragma once #pragma once
#include "Emu/SysCalls/lv2/sys_event.h"
#include <unordered_map> #include <unordered_map>
struct EventQueue;
class EventManager class EventManager
{ {
std::mutex m_lock; std::mutex m_lock;
std::unordered_map<u64, EventQueue*> key_map; std::unordered_map<u64, std::shared_ptr<EventQueue>> key_map;
public: public:
void Init(); void Init();
void Clear(); void Clear();
bool CheckKey(u64 key); bool CheckKey(u64 key);
bool RegisterKey(EventQueue* data, u64 key); bool RegisterKey(std::shared_ptr<EventQueue>& data, u64 key);
bool GetEventQueue(u64 key, EventQueue*& data); bool GetEventQueue(u64 key, std::shared_ptr<EventQueue>& data);
bool UnregisterKey(u64 key); bool UnregisterKey(u64 key);
bool SendEvent(u64 key, u64 source, u64 d1, u64 d2, u64 d3); bool SendEvent(u64 key, u64 source, u64 d1, u64 d2, u64 d3);
}; };
+3 -12
View File
@@ -32,21 +32,12 @@ std::string simplify_path(const std::string& path, bool is_dir)
{ {
std::vector<std::string> path_blocks = simplify_path_blocks(path); std::vector<std::string> path_blocks = simplify_path_blocks(path);
std::string result;
if (path_blocks.empty()) if (path_blocks.empty())
return result; return "";
if (is_dir) std::string result = fmt::merge(path_blocks, "/");
{
result = fmt::merge(path_blocks, "/");
}
else
{
result = fmt::merge(std::vector<std::string>(path_blocks.begin(), path_blocks.end() - 1), "/") + path_blocks[path_blocks.size() - 1];
}
return result; return is_dir ? result + "/" : result;
} }
VFS::~VFS() VFS::~VFS()
+6 -1
View File
@@ -75,7 +75,12 @@ bool vfsLocalFile::Create(const std::string& path)
if(m != '/' && m != '\\' && !rExists(path)) // ??? if(m != '/' && m != '\\' && !rExists(path)) // ???
{ {
rFile f; rFile f;
return f.Create(path); if (!f.Create(path)) {
LOG_NOTICE(HLE, "vfsLocalFile::Create: couldn't create file");
return false;
}
else
return true;
} }
return true; return true;
+1
View File
@@ -4,6 +4,7 @@ struct GameInfo
{ {
std::string root; std::string root;
std::string icon_path;
std::string name; std::string name;
std::string serial; std::string serial;
std::string app_ver; std::string app_ver;
+30 -12
View File
@@ -48,14 +48,14 @@ public:
m_destr(m_ptr); m_destr(m_ptr);
} }
template<typename T> T* get() template<typename T> std::shared_ptr<T> get()
{ {
return (T*)m_ptr; return *(std::shared_ptr<T>*)m_ptr;
} }
template<typename T> const T* get() const template<typename T> std::shared_ptr<const T> get() const
{ {
return (const T*)m_ptr; return *(std::shared_ptr<const T>*)m_ptr;
} }
}; };
@@ -67,11 +67,11 @@ class ID
public: public:
template<typename T> template<typename T>
ID(const std::string& name, T* data, const IDType type) ID(const std::string& name, std::shared_ptr<T>& data, const IDType type)
: m_name(name) : m_name(name)
, m_type(type) , m_type(type)
{ {
m_data = new IDData(data, [](void *ptr) -> void { delete (T*)ptr; }); m_data = new IDData(new std::shared_ptr<T>(data), [](void *ptr) -> void { delete (std::shared_ptr<T>*)ptr; });
} }
ID() : m_data(nullptr) ID() : m_data(nullptr)
@@ -85,6 +85,7 @@ public:
m_data = other.m_data; m_data = other.m_data;
other.m_data = nullptr; other.m_data = nullptr;
} }
ID& operator=(ID&& other) ID& operator=(ID&& other)
{ {
std::swap(m_name,other.m_name); std::swap(m_name,other.m_name);
@@ -159,7 +160,7 @@ public:
= char = char
#endif #endif
> >
u32 GetNewID(const std::string& name = "", T* data = nullptr, const IDType type = TYPE_OTHER) u32 GetNewID(const std::string& name = "", std::shared_ptr<T>& data = nullptr, const IDType type = TYPE_OTHER)
{ {
std::lock_guard<std::mutex> lock(m_mtx_main); std::lock_guard<std::mutex> lock(m_mtx_main);
@@ -179,7 +180,7 @@ public:
} }
template<typename T> template<typename T>
bool GetIDData(const u32 id, T*& result) bool GetIDData(const u32 id, std::shared_ptr<T>& result)
{ {
std::lock_guard<std::mutex> lock(m_mtx_main); std::lock_guard<std::mutex> lock(m_mtx_main);
@@ -226,15 +227,32 @@ public:
u32 GetTypeCount(IDType type) u32 GetTypeCount(IDType type)
{ {
if (type < TYPE_OTHER) { std::lock_guard<std::mutex> lock(m_mtx_main);
if (type < TYPE_OTHER)
{
return (u32)m_types[type].size(); return (u32)m_types[type].size();
} }
return 1; else
{
assert(!"Invalid ID type");
return 0;
}
} }
const std::set<u32>& GetTypeIDs(IDType type) std::set<u32> GetTypeIDs(IDType type)
{
// you cannot simply return reference to existing set
std::lock_guard<std::mutex> lock(m_mtx_main);
if (type < TYPE_OTHER)
{ {
assert(type < TYPE_OTHER);
return m_types[type]; return m_types[type];
} }
else
{
assert(!"Invalid ID type");
return{};
}
}
}; };
+8 -16
View File
@@ -170,36 +170,28 @@ void MemoryBase::Close()
MemoryBlocks.clear(); MemoryBlocks.clear();
} }
void MemoryBase::WriteMMIO32(u32 addr, const u32 data) bool MemoryBase::WriteMMIO32(u32 addr, const u32 data)
{
{ {
LV2_LOCK(0); LV2_LOCK(0);
if (RawSPUMem[(addr - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET] && if (RawSPUMem[(addr - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET] && ((RawSPUThread*)RawSPUMem[(addr - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET])->Write32(addr, data))
((RawSPUThread*)RawSPUMem[(addr - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET])->Write32(addr, data))
{ {
return; return true;
}
} }
*(u32*)((u8*)GetBaseAddr() + addr) = re32(data); // provoke error return false;
} }
u32 MemoryBase::ReadMMIO32(u32 addr) bool MemoryBase::ReadMMIO32(u32 addr, u32& res)
{
u32 res;
{ {
LV2_LOCK(0); LV2_LOCK(0);
if (RawSPUMem[(addr - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET] && if (RawSPUMem[(addr - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET] && ((RawSPUThread*)RawSPUMem[(addr - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET])->Read32(addr, &res))
((RawSPUThread*)RawSPUMem[(addr - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET])->Read32(addr, &res))
{ {
return res; return true;
}
} }
res = re32(*(u32*)((u8*)GetBaseAddr() + addr)); // provoke error return false;
return res;
} }
bool MemoryBase::Map(const u64 addr, const u32 size) bool MemoryBase::Map(const u64 addr, const u32 size)
+2 -2
View File
@@ -127,9 +127,9 @@ public:
void Close(); void Close();
__noinline void WriteMMIO32(u32 addr, const u32 data); __noinline bool WriteMMIO32(u32 addr, const u32 data);
__noinline u32 ReadMMIO32(u32 addr); __noinline bool ReadMMIO32(u32 addr, u32& res);
u32 GetUserMemTotalSize() u32 GetUserMemTotalSize()
{ {
+5 -11
View File
@@ -64,26 +64,20 @@ namespace vm
static u32 read32(u32 addr) static u32 read32(u32 addr)
{ {
if (addr < RAW_SPU_BASE_ADDR || (addr % RAW_SPU_OFFSET) < RAW_SPU_PROB_OFFSET) u32 res;
if (addr < RAW_SPU_BASE_ADDR || (addr % RAW_SPU_OFFSET) < RAW_SPU_PROB_OFFSET || !Memory.ReadMMIO32((u32)addr, res))
{ {
return re32(*(u32*)((u8*)g_base_addr + addr)); res = re32(*(u32*)((u8*)g_base_addr + addr));
}
else
{
return Memory.ReadMMIO32((u32)addr);
} }
return res;
} }
static void write32(u32 addr, be_t<u32> value) static void write32(u32 addr, be_t<u32> value)
{ {
if (addr < RAW_SPU_BASE_ADDR || (addr % RAW_SPU_OFFSET) < RAW_SPU_PROB_OFFSET) if (addr < RAW_SPU_BASE_ADDR || (addr % RAW_SPU_OFFSET) < RAW_SPU_PROB_OFFSET || !Memory.WriteMMIO32((u32)addr, value))
{ {
*(be_t<u32>*)((u8*)g_base_addr + addr) = value; *(be_t<u32>*)((u8*)g_base_addr + addr) = value;
} }
else
{
Memory.WriteMMIO32((u32)addr, value);
}
} }
static u64 read64(u32 addr) static u64 read64(u32 addr)
+8 -8
View File
@@ -67,12 +67,12 @@ namespace vm
__forceinline _ptr_base<T, lvl - 1, std::conditional<is_be_t<T>::value, typename to_be_t<AT>::type, AT>>& operator *() const __forceinline _ptr_base<T, lvl - 1, std::conditional<is_be_t<T>::value, typename to_be_t<AT>::type, AT>>& operator *() const
{ {
return vm::get_ref<_ptr_base<T, lvl - 1, std::conditional<is_be_t<T>::value, typename to_be_t<AT>::type, AT>>>(m_addr); return vm::get_ref<_ptr_base<T, lvl - 1, std::conditional<is_be_t<T>::value, typename to_be_t<AT>::type, AT>>>((u32)m_addr);
} }
__forceinline _ptr_base<T, lvl - 1, std::conditional<is_be_t<T>::value, typename to_be_t<AT>::type, AT>>& operator [](AT index) const __forceinline _ptr_base<T, lvl - 1, std::conditional<is_be_t<T>::value, typename to_be_t<AT>::type, AT>>& operator [](AT index) const
{ {
return vm::get_ref<_ptr_base<T, lvl - 1, std::conditional<is_be_t<T>::value, typename to_be_t<AT>::type, AT>>>(m_addr + sizeof(AT)* index); return vm::get_ref<_ptr_base<T, lvl - 1, std::conditional<is_be_t<T>::value, typename to_be_t<AT>::type, AT>>>((u32)(m_addr + sizeof(AT)* index));
} }
//typedef typename invert_be_t<AT>::type AT2; //typedef typename invert_be_t<AT>::type AT2;
@@ -160,17 +160,17 @@ namespace vm
__forceinline T& operator *() const __forceinline T& operator *() const
{ {
return vm::get_ref<T>(m_addr); return vm::get_ref<T>((u32)m_addr);
} }
__forceinline T& operator [](typename remove_be_t<AT>::type index) const __forceinline T& operator [](typename remove_be_t<AT>::type index) const
{ {
return vm::get_ref<T>(m_addr + sizeof(T)* index); return vm::get_ref<T>((u32)(m_addr + sizeof(T) * index));
} }
__forceinline T& operator [](typename to_be_t<AT>::forced_type index) const __forceinline T& operator [](typename to_be_t<AT>::forced_type index) const
{ {
return vm::get_ref<T>(m_addr + sizeof(T)* index); return vm::get_ref<T>((u32)(m_addr + sizeof(T)* index));
} }
__forceinline bool operator <(const _ptr_base& right) const { return m_addr < right.m_addr; } __forceinline bool operator <(const _ptr_base& right) const { return m_addr < right.m_addr; }
@@ -224,7 +224,7 @@ namespace vm
T* get_ptr() const T* get_ptr() const
{ {
return vm::get_ptr<T>(m_addr); return vm::get_ptr<T>((u32)m_addr);
} }
static _ptr_base make(AT addr) static _ptr_base make(AT addr)
@@ -356,9 +356,9 @@ namespace vm
public: public:
typedef RT(*type)(T...); typedef RT(*type)(T...);
RT call(CPUThread& CPU, T... args) const; // call using specified CPU thread context, defined in CB_FUNC.h RT call(CPUThread& CPU, T... args) const; // defined in CB_FUNC.h, call using specified CPU thread context
RT operator()(T... args) const; // call using current CPU thread context, defined in CB_FUNC.h RT operator()(T... args) const; // defined in CB_FUNC.h, call using current CPU thread context
AT addr() const AT addr() const
{ {
+274 -108
View File
@@ -29,19 +29,31 @@ void GLFragmentDecompilerThread::SetDst(std::string code, bool append_mask)
code = "clamp(" + code + ", 0.0, 1.0)"; code = "clamp(" + code + ", 0.0, 1.0)";
} }
std::string dest; code += (append_mask ? "$m" : "");
if (dst.no_dest)
{
if (dst.set_cond)
{
AddCode("$ifcond " + m_parr.AddParam(PARAM_NONE, "vec4", "cc" + std::to_string(src0.cond_mod_reg_index)) + "$m = " + code + ";");
}
else
{
AddCode("$ifcond " + code + ";");
}
return;
}
std::string dest = AddReg(dst.dest_reg, dst.fp16) + "$m";
AddCodeCond(Format(dest), code);
//AddCode("$ifcond " + dest + code + (append_mask ? "$m;" : ";"));
if (dst.set_cond) if (dst.set_cond)
{ {
dest += m_parr.AddParam(PARAM_NONE, "vec4", "cc" + std::to_string(src0.cond_mod_reg_index)) + "$m = "; AddCode(m_parr.AddParam(PARAM_NONE, "vec4", "cc" + std::to_string(src0.cond_mod_reg_index)) + "$m = " + dest + ";");
} }
if (!dst.no_dest)
{
dest += AddReg(dst.dest_reg, dst.fp16) + "$m = ";
}
AddCode("$ifcond " + dest + code + (append_mask ? "$m;" : ";"));
} }
void GLFragmentDecompilerThread::AddCode(const std::string& code) void GLFragmentDecompilerThread::AddCode(const std::string& code)
@@ -68,7 +80,7 @@ std::string GLFragmentDecompilerThread::GetMask()
std::string GLFragmentDecompilerThread::AddReg(u32 index, int fp16) std::string GLFragmentDecompilerThread::AddReg(u32 index, int fp16)
{ {
return m_parr.AddParam(PARAM_NONE, "vec4", std::string(fp16 ? "h" : "r") + std::to_string(index), "vec4(0.0, 0.0, 0.0, 0.0)"); return m_parr.AddParam(PARAM_NONE, "vec4", std::string(fp16 ? "h" : "r") + std::to_string(index), "vec4(0.0)");
} }
bool GLFragmentDecompilerThread::HasReg(u32 index, int fp16) bool GLFragmentDecompilerThread::HasReg(u32 index, int fp16)
@@ -179,6 +191,74 @@ std::string GLFragmentDecompilerThread::GetCond()
return "any(" + cond + "(" + AddCond() + swizzle + ", vec4(0.0)))"; return "any(" + cond + "(" + AddCond() + swizzle + ", vec4(0.0)))";
} }
void GLFragmentDecompilerThread::AddCodeCond(const std::string& dst, const std::string& src)
{
if (src0.exec_if_gr && src0.exec_if_lt && src0.exec_if_eq)
{
AddCode(dst + " = " + src + ";");
return;
}
if (!src0.exec_if_gr && !src0.exec_if_lt && !src0.exec_if_eq)
{
AddCode("//" + dst + " = " + src + ";");
return;
}
static const char f[4] = { 'x', 'y', 'z', 'w' };
std::string swizzle, cond;
swizzle += f[src0.cond_swizzle_x];
swizzle += f[src0.cond_swizzle_y];
swizzle += f[src0.cond_swizzle_z];
swizzle += f[src0.cond_swizzle_w];
swizzle = swizzle == "xyzw" ? "" : "." + swizzle;
if (src0.exec_if_gr && src0.exec_if_eq)
{
cond = "greaterThanEqual";
}
else if (src0.exec_if_lt && src0.exec_if_eq)
{
cond = "lessThanEqual";
}
else if (src0.exec_if_gr && src0.exec_if_lt)
{
cond = "notEqual";
}
else if (src0.exec_if_gr)
{
cond = "greaterThan";
}
else if (src0.exec_if_lt)
{
cond = "lessThan";
}
else //if(src0.exec_if_eq)
{
cond = "equal";
}
cond = cond + "(" + AddCond() + swizzle + ", vec4(0.0))";
ShaderVar dst_var(dst);
dst_var.symplify();
//const char *c_mask = f;
if (dst_var.swizzles[0].length() == 1)
{
AddCode("if (" + cond + ".x) " + dst + " = vec4(" + src + ").x;");
}
else
{
for (int i = 0; i < dst_var.swizzles[0].length(); ++i)
{
AddCode("if (" + cond + "." + f[i] + ") " + dst + "." + f[i] + " = " + src + "." + f[i] + ";");
}
}
}
template<typename T> std::string GLFragmentDecompilerThread::GetSRC(T src) template<typename T> std::string GLFragmentDecompilerThread::GetSRC(T src)
{ {
std::string ret; std::string ret;
@@ -251,10 +331,9 @@ std::string GLFragmentDecompilerThread::BuildCode()
const std::pair<std::string, std::string> table[] = const std::pair<std::string, std::string> table[] =
{ {
{ "ocol0", m_ctrl & 0x40 ? "r0" : "h0" }, { "ocol0", m_ctrl & 0x40 ? "r0" : "h0" },
{ "ocol1", m_ctrl & 0x40 ? "r2" : "h2" }, { "ocol1", m_ctrl & 0x40 ? "r2" : "h4" },
{ "ocol2", m_ctrl & 0x40 ? "r3" : "h4" }, { "ocol2", m_ctrl & 0x40 ? "r3" : "h6" },
{ "ocol3", m_ctrl & 0x40 ? "r4" : "h6" }, { "ocol3", m_ctrl & 0x40 ? "r4" : "h8" },
{ "ocol4", m_ctrl & 0x40 ? "r5" : "h8" },
}; };
for (int i = 0; i < sizeof(table) / sizeof(*table); ++i) for (int i = 0; i < sizeof(table) / sizeof(*table); ++i)
@@ -263,7 +342,7 @@ std::string GLFragmentDecompilerThread::BuildCode()
AddCode(m_parr.AddParam(PARAM_OUT, "vec4", table[i].first, i) + " = " + table[i].second + ";"); AddCode(m_parr.AddParam(PARAM_OUT, "vec4", table[i].first, i) + " = " + table[i].second + ";");
} }
if (m_ctrl & 0xe) main += "\tgl_FragDepth = r1.z;\n"; if (m_ctrl & 0xe) main += m_ctrl & 0x40 ? "\tgl_FragDepth = r1.z;\n" : "\tgl_FragDepth = h2.z;\n";
std::string p; std::string p;
@@ -285,6 +364,15 @@ void GLFragmentDecompilerThread::Task()
m_loop_count = 0; m_loop_count = 0;
m_code_level = 1; m_code_level = 1;
enum
{
FORCE_NONE,
FORCE_SCT,
FORCE_SCB,
};
int forced_unit = FORCE_NONE;
while (true) while (true)
{ {
for (auto finded = std::find(m_end_offsets.begin(), m_end_offsets.end(), m_size); for (auto finded = std::find(m_end_offsets.begin(), m_end_offsets.end(), m_size);
@@ -318,75 +406,122 @@ void GLFragmentDecompilerThread::Task()
const u32 opcode = dst.opcode | (src1.opcode_is_branch << 6); const u32 opcode = dst.opcode | (src1.opcode_is_branch << 6);
auto SCT = [&]()
{
switch (opcode) switch (opcode)
{ {
case RSX_FP_OPCODE_NOP: break;
case RSX_FP_OPCODE_MOV: SetDst("$0"); break;
case RSX_FP_OPCODE_MUL: SetDst("($0 * $1)"); break;
case RSX_FP_OPCODE_ADD: SetDst("($0 + $1)"); break; case RSX_FP_OPCODE_ADD: SetDst("($0 + $1)"); break;
case RSX_FP_OPCODE_MAD: SetDst("($0 * $1 + $2)"); break;
case RSX_FP_OPCODE_DP3: SetDst("vec4(dot($0.xyz, $1.xyz))"); break;
case RSX_FP_OPCODE_DP4: SetDst("vec4(dot($0, $1))"); break;
case RSX_FP_OPCODE_DST: SetDst("vec4(distance($0, $1))"); break;
case RSX_FP_OPCODE_MIN: SetDst("min($0, $1)"); break;
case RSX_FP_OPCODE_MAX: SetDst("max($0, $1)"); break;
case RSX_FP_OPCODE_SLT: SetDst("vec4(lessThan($0, $1))"); break;
case RSX_FP_OPCODE_SGE: SetDst("vec4(greaterThanEqual($0, $1))"); break;
case RSX_FP_OPCODE_SLE: SetDst("vec4(lessThanEqual($0, $1))"); break;
case RSX_FP_OPCODE_SGT: SetDst("vec4(greaterThan($0, $1))"); break;
case RSX_FP_OPCODE_SNE: SetDst("vec4(notEqual($0, $1))"); break;
case RSX_FP_OPCODE_SEQ: SetDst("vec4(equal($0, $1))"); break;
case RSX_FP_OPCODE_FRC: SetDst("fract($0)"); break;
case RSX_FP_OPCODE_FLR: SetDst("floor($0)"); break;
case RSX_FP_OPCODE_KIL: SetDst("discard", false); break;
//case RSX_FP_OPCODE_PK4: break;
//case RSX_FP_OPCODE_UP4: break;
case RSX_FP_OPCODE_DDX: SetDst("dFdx($0)"); break;
case RSX_FP_OPCODE_DDY: SetDst("dFdy($0)"); break;
case RSX_FP_OPCODE_TEX: SetDst("texture($t, $0.xy)"); break;
//case RSX_FP_OPCODE_TXP: break;
//case RSX_FP_OPCODE_TXD: break;
case RSX_FP_OPCODE_RCP: SetDst("(1 / $0)"); break;
case RSX_FP_OPCODE_RSQ: SetDst("inversesqrt(abs($0))"); break;
case RSX_FP_OPCODE_EX2: SetDst("exp2($0)"); break;
case RSX_FP_OPCODE_LG2: SetDst("log2($0)"); break;
case RSX_FP_OPCODE_LIT: SetDst("vec4(1.0, $0.x, ($0.x > 0 ? exp2($0.w * log2($0.y)) : 0.0), 1.0)"); break;
case RSX_FP_OPCODE_LRP: SetDst("($0 * ($1 - $2) + $2)"); break;
case RSX_FP_OPCODE_STR: SetDst("vec4(equal($0, vec4(1.0)))"); break;
case RSX_FP_OPCODE_SFL: SetDst("vec4(equal($0, vec4(0.0)))"); break;
case RSX_FP_OPCODE_COS: SetDst("cos($0)"); break;
case RSX_FP_OPCODE_SIN: SetDst("sin($0)"); break;
//case RSX_FP_OPCODE_PK2: break;
//case RSX_FP_OPCODE_UP2: break;
case RSX_FP_OPCODE_POW: SetDst("pow($0, $1)"); break;
//case RSX_FP_OPCODE_PKB: break;
//case RSX_FP_OPCODE_UPB: break;
//case RSX_FP_OPCODE_PK16: break;
//case RSX_FP_OPCODE_UP16: break;
//case RSX_FP_OPCODE_BEM: break;
//case RSX_FP_OPCODE_PKG: break;
//case RSX_FP_OPCODE_UPG: break;
case RSX_FP_OPCODE_DP2A: SetDst("($0.x * $1.x + $0.y * $1.y + $2.x)"); break;
//case RSX_FP_OPCODE_TXL: break;
//case RSX_FP_OPCODE_TXB: break;
//case RSX_FP_OPCODE_TEXBEM: break;
//case RSX_FP_OPCODE_TXPBEM: break;
//case RSX_FP_OPCODE_BEMLUM: break;
case RSX_FP_OPCODE_REFL: SetDst("($0 - 2.0 * $1 * dot($0, $1))"); break;
//case RSX_FP_OPCODE_TIMESWTEX: break;
case RSX_FP_OPCODE_DP2: SetDst("vec4(dot($0.xy, $1.xy))"); break;
case RSX_FP_OPCODE_NRM: SetDst("normalize($0.xyz)"); break;
case RSX_FP_OPCODE_DIV: SetDst("($0 / $1)"); break; case RSX_FP_OPCODE_DIV: SetDst("($0 / $1)"); break;
case RSX_FP_OPCODE_DIVSQ: SetDst("($0 / sqrt($1))"); break; case RSX_FP_OPCODE_DIVSQ: SetDst("($0 / sqrt($1))"); break;
case RSX_FP_OPCODE_LIF: SetDst("vec4(1.0, $0.y, ($0.y > 0 ? pow(2.0, $0.w) : 0.0), 1.0)"); break; case RSX_FP_OPCODE_DP2: SetDst("vec4(dot($0.xy, $1.xy))"); break;
case RSX_FP_OPCODE_FENCT: break; case RSX_FP_OPCODE_DP3: SetDst("vec4(dot($0.xyz, $1.xyz))"); break;
case RSX_FP_OPCODE_FENCB: break; case RSX_FP_OPCODE_DP4: SetDst("vec4(dot($0, $1))"); break;
case RSX_FP_OPCODE_DP2A: SetDst("vec4($0.x * $1.x + $0.y * $1.y + $2.x)"); break;
case RSX_FP_OPCODE_MAD: SetDst("($0 * $1 + $2)"); break;
case RSX_FP_OPCODE_MAX: SetDst("max($0, $1)"); break;
case RSX_FP_OPCODE_MIN: SetDst("min($0, $1)"); break;
case RSX_FP_OPCODE_MOV: SetDst("$0"); break;
case RSX_FP_OPCODE_MUL: SetDst("($0 * $1)"); break;
case RSX_FP_OPCODE_RCP: SetDst("1 / $0"); break;
case RSX_FP_OPCODE_RSQ: SetDst("inversesqrt(abs($0))"); break;
case RSX_FP_OPCODE_SEQ: SetDst("vec4(equal($0, $1))"); break;
case RSX_FP_OPCODE_SFL: SetDst("vec4(0.0)"); break;
case RSX_FP_OPCODE_SGE: SetDst("vec4(greaterThanEqual($0, $1))"); break;
case RSX_FP_OPCODE_SGT: SetDst("vec4(greaterThan($0, $1))"); break;
case RSX_FP_OPCODE_SLE: SetDst("vec4(lessThanEqual($0, $1))"); break;
case RSX_FP_OPCODE_SLT: SetDst("vec4(lessThan($0, $1))"); break;
case RSX_FP_OPCODE_SNE: SetDst("vec4(notEqual($0, $1))"); break;
case RSX_FP_OPCODE_STR: SetDst("vec4(1.0)"); break;
default:
return false;
}
return true;
};
auto SCB = [&]()
{
switch (opcode)
{
case RSX_FP_OPCODE_ADD: SetDst("($0 + $1)"); break;
case RSX_FP_OPCODE_COS: SetDst("cos($0)"); break;
case RSX_FP_OPCODE_DP2: SetDst("vec4(dot($0.xy, $1.xy))"); break;
case RSX_FP_OPCODE_DP3: SetDst("vec4(dot($0.xyz, $1.xyz))"); break;
case RSX_FP_OPCODE_DP4: SetDst("vec4(dot($0, $1))"); break;
case RSX_FP_OPCODE_DP2A: SetDst("vec4($0.x * $1.x + $0.y * $1.y + $2.x)"); break;
case RSX_FP_OPCODE_DST: SetDst("vec4(distance($0, $1))"); break;
case RSX_FP_OPCODE_REFL: LOG_ERROR(RSX, "Unimplemented SCB instruction: REFL"); break; // TODO: Is this in the right category?
case RSX_FP_OPCODE_EX2: SetDst("exp2($0)"); break;
case RSX_FP_OPCODE_FLR: SetDst("floor($0)"); break;
case RSX_FP_OPCODE_FRC: SetDst("fract($0)"); break;
case RSX_FP_OPCODE_LIT: SetDst("vec4(1.0, $0.x, ($0.x > 0.0 ? exp($0.w * log2($0.y)) : 0.0), 1.0)"); break;
case RSX_FP_OPCODE_LIF: SetDst("vec4(1.0, $0.y, ($0.y > 0 ? pow(2.0, $0.w) : 0.0), 1.0)"); break;
case RSX_FP_OPCODE_LRP: LOG_ERROR(RSX, "Unimplemented SCB instruction: LRP"); break; // TODO: Is this in the right category?
case RSX_FP_OPCODE_LG2: SetDst("log2($0)"); break;
case RSX_FP_OPCODE_MAD: SetDst("($0 * $1 + $2)"); break;
case RSX_FP_OPCODE_MAX: SetDst("max($0, $1)"); break;
case RSX_FP_OPCODE_MIN: SetDst("min($0, $1)"); break;
case RSX_FP_OPCODE_MOV: SetDst("$0"); break;
case RSX_FP_OPCODE_MUL: SetDst("($0 * $1)"); break;
case RSX_FP_OPCODE_PK2: SetDst("packSnorm2x16($0)"); break; // TODO: More testing (Sonic The Hedgehog (NPUB-30442/NPEB-00478))
case RSX_FP_OPCODE_PK4: SetDst("packSnorm4x8($0)"); break; // TODO: More testing (Sonic The Hedgehog (NPUB-30442/NPEB-00478))
case RSX_FP_OPCODE_PK16: LOG_ERROR(RSX, "Unimplemented SCB instruction: PK16"); break;
case RSX_FP_OPCODE_PKB: LOG_ERROR(RSX, "Unimplemented SCB instruction: PKB"); break;
case RSX_FP_OPCODE_PKG: LOG_ERROR(RSX, "Unimplemented SCB instruction: PKG"); break;
case RSX_FP_OPCODE_SEQ: SetDst("vec4(equal($0, $1))"); break;
case RSX_FP_OPCODE_SFL: SetDst("vec4(0.0)"); break;
case RSX_FP_OPCODE_SGE: SetDst("vec4(greaterThanEqual($0, $1))"); break;
case RSX_FP_OPCODE_SGT: SetDst("vec4(greaterThan($0, $1))"); break;
case RSX_FP_OPCODE_SIN: SetDst("sin($0)"); break;
case RSX_FP_OPCODE_SLE: SetDst("vec4(lessThanEqual($0, $1))"); break;
case RSX_FP_OPCODE_SLT: SetDst("vec4(lessThan($0, $1))"); break;
case RSX_FP_OPCODE_SNE: SetDst("vec4(notEqual($0, $1))"); break;
case RSX_FP_OPCODE_STR: SetDst("vec4(1.0)"); break;
default:
return false;
}
return true;
};
auto TEX_SRB = [&]()
{
switch (opcode)
{
case RSX_FP_OPCODE_DDX: SetDst("dFdx($0)"); break;
case RSX_FP_OPCODE_DDY: SetDst("dFdy($0)"); break;
case RSX_FP_OPCODE_NRM: SetDst("normalize($0)"); break;
case RSX_FP_OPCODE_BEM: LOG_ERROR(RSX, "Unimplemented TEX_SRB instruction: BEM"); break;
case RSX_FP_OPCODE_TEX: SetDst("texture($t, $0.xy)"); break;
case RSX_FP_OPCODE_TEXBEM: LOG_ERROR(RSX, "Unimplemented TEX_SRB instruction: TEXBEM"); break;
case RSX_FP_OPCODE_TXP: SetDst("textureProj($t, $0.xy, $1)"); break; //TODO: More testing (Sonic The Hedgehog (NPUB-30442/NPEB-00478) and The Simpsons Arcade Game (NPUB30563))
case RSX_FP_OPCODE_TXPBEM: LOG_ERROR(RSX, "Unimplemented TEX_SRB instruction: TXPBEM"); break;
case RSX_FP_OPCODE_TXD: LOG_ERROR(RSX, "Unimplemented TEX_SRB instruction: TXD"); break;
case RSX_FP_OPCODE_TXB: SetDst("texture($t, $0.xy, $1.x)"); break;
case RSX_FP_OPCODE_TXL: SetDst("textureLod($t, $0.xy, $1.x)"); break;
case RSX_FP_OPCODE_UP2: SetDst("unpackSnorm2x16($0)"); break; // TODO: More testing (Sonic The Hedgehog (NPUB-30442/NPEB-00478))
case RSX_FP_OPCODE_UP4: SetDst("unpackSnorm4x8($0)"); break; // TODO: More testing (Sonic The Hedgehog (NPUB-30442/NPEB-00478))
case RSX_FP_OPCODE_UP16: LOG_ERROR(RSX, "Unimplemented TEX_SRB instruction: UP16"); break;
case RSX_FP_OPCODE_UPB: LOG_ERROR(RSX, "Unimplemented TEX_SRB instruction: UPB"); break;
case RSX_FP_OPCODE_UPG: LOG_ERROR(RSX, "Unimplemented TEX_SRB instruction: UPG"); break;
default:
return false;
}
return true;
};
auto SIP = [&]()
{
switch (opcode)
{
case RSX_FP_OPCODE_BRK: SetDst("break"); break; case RSX_FP_OPCODE_BRK: SetDst("break"); break;
//case RSX_FP_OPCODE_CAL: break; case RSX_FP_OPCODE_CAL: LOG_ERROR(RSX, "Unimplemented SIP instruction: CAL"); break;
case RSX_FP_OPCODE_FENCT: forced_unit = FORCE_SCT; break;
case RSX_FP_OPCODE_FENCB: forced_unit = FORCE_SCB; break;
case RSX_FP_OPCODE_IFE: case RSX_FP_OPCODE_IFE:
AddCode("if($cond)"); AddCode("if($cond)");
m_else_offsets.push_back(src1.else_offset << 2); m_else_offsets.push_back(src1.else_offset << 2);
@@ -394,7 +529,6 @@ void GLFragmentDecompilerThread::Task()
AddCode("{"); AddCode("{");
m_code_level++; m_code_level++;
break; break;
case RSX_FP_OPCODE_LOOP: case RSX_FP_OPCODE_LOOP:
if (!src0.exec_if_eq && !src0.exec_if_gr && !src0.exec_if_lt) if (!src0.exec_if_eq && !src0.exec_if_gr && !src0.exec_if_lt)
{ {
@@ -427,11 +561,40 @@ void GLFragmentDecompilerThread::Task()
m_code_level++; m_code_level++;
} }
break; break;
//case RSX_FP_OPCODE_RET: SetDst("return"); break; case RSX_FP_OPCODE_RET: SetDst("return"); break;
default: default:
LOG_ERROR(RSX, "Unknown fp opcode 0x%x (inst %d)", opcode, m_size / (4 * 4)); return false;
//Emu.Pause(); }
return true;
};
switch (opcode)
{
case RSX_FP_OPCODE_NOP: break;
case RSX_FP_OPCODE_KIL: SetDst("discard", false); break;
default:
if (forced_unit == FORCE_NONE)
{
if (SIP()) break;
if (SCT()) break;
if (TEX_SRB()) break;
if (SCB()) break;
}
else if (forced_unit == FORCE_SCT)
{
forced_unit = FORCE_NONE;
if (SCT()) break;
}
else if (forced_unit == FORCE_SCB)
{
forced_unit = FORCE_NONE;
if (SCB()) break;
}
LOG_ERROR(RSX, "Unknown/illegal instruction: 0x%x (forced unit %d)", opcode, forced_unit);
break; break;
} }
@@ -450,13 +613,13 @@ void GLFragmentDecompilerThread::Task()
m_parr.params.clear(); m_parr.params.clear();
} }
GLShaderProgram::GLShaderProgram() GLFragmentProgram::GLFragmentProgram()
: m_decompiler_thread(nullptr) : m_decompiler_thread(nullptr)
, m_id(0) , id(0)
{ {
} }
GLShaderProgram::~GLShaderProgram() GLFragmentProgram::~GLFragmentProgram()
{ {
if (m_decompiler_thread) if (m_decompiler_thread)
{ {
@@ -473,7 +636,7 @@ GLShaderProgram::~GLShaderProgram()
Delete(); Delete();
} }
void GLShaderProgram::Wait() void GLFragmentProgram::Wait()
{ {
if (m_decompiler_thread && m_decompiler_thread->IsAlive()) if (m_decompiler_thread && m_decompiler_thread->IsAlive())
{ {
@@ -481,13 +644,13 @@ void GLShaderProgram::Wait()
} }
} }
void GLShaderProgram::Decompile(RSXShaderProgram& prog) void GLFragmentProgram::Decompile(RSXFragmentProgram& prog)
{ {
GLFragmentDecompilerThread decompiler(m_shader, m_parr, prog.addr, prog.size, prog.ctrl); GLFragmentDecompilerThread decompiler(shader, parr, prog.addr, prog.size, prog.ctrl);
decompiler.Task(); decompiler.Task();
} }
void GLShaderProgram::DecompileAsync(RSXShaderProgram& prog) void GLFragmentProgram::DecompileAsync(RSXFragmentProgram& prog)
{ {
if (m_decompiler_thread) if (m_decompiler_thread)
{ {
@@ -501,65 +664,68 @@ void GLShaderProgram::DecompileAsync(RSXShaderProgram& prog)
m_decompiler_thread = nullptr; m_decompiler_thread = nullptr;
} }
m_decompiler_thread = new GLFragmentDecompilerThread(m_shader, m_parr, prog.addr, prog.size, prog.ctrl); m_decompiler_thread = new GLFragmentDecompilerThread(shader, parr, prog.addr, prog.size, prog.ctrl);
m_decompiler_thread->Start(); m_decompiler_thread->Start();
} }
void GLShaderProgram::Compile() void GLFragmentProgram::Compile()
{ {
if (m_id) glDeleteShader(m_id); if (id)
{
glDeleteShader(id);
}
m_id = glCreateShader(GL_FRAGMENT_SHADER); id = glCreateShader(GL_FRAGMENT_SHADER);
const char* str = m_shader.c_str(); const char* str = shader.c_str();
const int strlen = m_shader.length(); const int strlen = shader.length();
glShaderSource(m_id, 1, &str, &strlen); glShaderSource(id, 1, &str, &strlen);
glCompileShader(m_id); glCompileShader(id);
GLint compileStatus = GL_FALSE; GLint compileStatus = GL_FALSE;
glGetShaderiv(m_id, GL_COMPILE_STATUS, &compileStatus); // Determine the result of the glCompileShader call glGetShaderiv(id, GL_COMPILE_STATUS, &compileStatus); // Determine the result of the glCompileShader call
if (compileStatus != GL_TRUE) // If the shader failed to compile... if (compileStatus != GL_TRUE) // If the shader failed to compile...
{ {
GLint infoLength; GLint infoLength;
glGetShaderiv(m_id, GL_INFO_LOG_LENGTH, &infoLength); // Retrieve the length in bytes (including trailing NULL) of the shader info log glGetShaderiv(id, GL_INFO_LOG_LENGTH, &infoLength); // Retrieve the length in bytes (including trailing NULL) of the shader info log
if (infoLength > 0) if (infoLength > 0)
{ {
GLsizei len; GLsizei len;
char* buf = new char[infoLength]; // Buffer to store infoLog char* buf = new char[infoLength]; // Buffer to store infoLog
glGetShaderInfoLog(m_id, infoLength, &len, buf); // Retrieve the shader info log into our buffer glGetShaderInfoLog(id, infoLength, &len, buf); // Retrieve the shader info log into our buffer
LOG_ERROR(RSX, "Failed to compile shader: %s", buf); // Write log to the console LOG_ERROR(RSX, "Failed to compile shader: %s", buf); // Write log to the console
delete[] buf; delete[] buf;
} }
LOG_NOTICE(RSX, m_shader.c_str()); // Log the text of the shader that failed to compile LOG_NOTICE(RSX, shader.c_str()); // Log the text of the shader that failed to compile
Emu.Pause(); // Pause the emulator, we can't really continue from here Emu.Pause(); // Pause the emulator, we can't really continue from here
} }
} }
void GLShaderProgram::Delete() void GLFragmentProgram::Delete()
{ {
for (auto& param : m_parr.params) { for (auto& param : parr.params) {
param.items.clear(); param.items.clear();
param.type.clear(); param.type.clear();
} }
m_parr.params.clear(); parr.params.clear();
m_shader.clear(); shader.clear();
if (m_id) if (id)
{ {
if (Emu.IsStopped()) if (Emu.IsStopped())
{ {
LOG_WARNING(RSX, "GLShaderProgram::Delete(): glDeleteShader(%d) avoided", m_id); LOG_WARNING(RSX, "GLFragmentProgram::Delete(): glDeleteShader(%d) avoided", id);
} }
else else
{ {
glDeleteShader(m_id); glDeleteShader(id);
} }
m_id = 0; id = 0;
} }
} }
+10 -32
View File
@@ -155,6 +155,7 @@ struct GLFragmentDecompilerThread : public ThreadBase
std::string AddTex(); std::string AddTex();
std::string Format(const std::string& code); std::string Format(const std::string& code);
void AddCodeCond(const std::string& dst, const std::string& src);
std::string GetCond(); std::string GetCond();
template<typename T> std::string GetSRC(T src); template<typename T> std::string GetSRC(T src);
std::string BuildCode(); std::string BuildCode();
@@ -167,24 +168,28 @@ struct GLFragmentDecompilerThread : public ThreadBase
/** Storage for an Fragment Program in the process of of recompilation. /** Storage for an Fragment Program in the process of of recompilation.
* This class calls OpenGL functions and should only be used from the RSX/Graphics thread. * This class calls OpenGL functions and should only be used from the RSX/Graphics thread.
*/ */
class GLShaderProgram class GLFragmentProgram
{ {
public: public:
GLShaderProgram(); GLFragmentProgram();
~GLShaderProgram(); ~GLFragmentProgram();
GLParamArray parr;
u32 id;
std::string shader;
/** /**
* Decompile a fragment shader located in the PS3's Memory. This function operates synchronously. * Decompile a fragment shader located in the PS3's Memory. This function operates synchronously.
* @param prog RSXShaderProgram specifying the location and size of the shader in memory * @param prog RSXShaderProgram specifying the location and size of the shader in memory
*/ */
void Decompile(RSXShaderProgram& prog); void Decompile(RSXFragmentProgram& prog);
/** /**
* Asynchronously decompile a fragment shader located in the PS3's Memory. * Asynchronously decompile a fragment shader located in the PS3's Memory.
* When this function is called you must call Wait() before GetShaderText() will return valid data. * When this function is called you must call Wait() before GetShaderText() will return valid data.
* @param prog RSXShaderProgram specifying the location and size of the shader in memory * @param prog RSXShaderProgram specifying the location and size of the shader in memory
*/ */
void DecompileAsync(RSXShaderProgram& prog); void DecompileAsync(RSXFragmentProgram& prog);
/** Wait for the decompiler task to complete decompilation. */ /** Wait for the decompiler task to complete decompilation. */
void Wait(); void Wait();
@@ -192,37 +197,10 @@ public:
/** Compile the decompiled fragment shader into a format we can use with OpenGL. */ /** Compile the decompiled fragment shader into a format we can use with OpenGL. */
void Compile(); void Compile();
/** Get the source text for this shader */
inline const std::string& GetShaderText() const { return m_shader; }
/**
* Set the source text for this shader
* @param shaderText supplied shader text
*/
inline void SetShaderText(const std::string& shaderText) { m_shader = shaderText; }
/** Get the OpenGL id this shader is bound to */
inline u32 GetId() const { return m_id; }
/**
* Set the OpenGL id this shader is bound to
* @param id supplied id
*/
inline void SetId(const u32 id) { m_id = id; }
private: private:
/** Threaded fragment shader decompiler responsible for decompiling this program */ /** Threaded fragment shader decompiler responsible for decompiling this program */
GLFragmentDecompilerThread* m_decompiler_thread; GLFragmentDecompilerThread* m_decompiler_thread;
/** Shader parameter storage */
GLParamArray m_parr;
/** Text of our decompiler shader */
std::string m_shader;
/** OpenGL id this shader is bound to */
u32 m_id;
/** Deletes the shader and any stored information */ /** Deletes the shader and any stored information */
void Delete(); void Delete();
}; };
File diff suppressed because it is too large Load Diff
+31 -4
View File
@@ -67,7 +67,7 @@ public:
class PostDrawObj class PostDrawObj
{ {
protected: protected:
GLShaderProgram m_fp; GLFragmentProgram m_fp;
GLVertexProgram m_vp; GLVertexProgram m_vp;
GLProgram m_program; GLProgram m_program;
GLfbo m_fbo; GLfbo m_fbo;
@@ -144,10 +144,11 @@ private:
int m_vp_buf_num; int m_vp_buf_num;
GLProgramBuffer m_prog_buffer; GLProgramBuffer m_prog_buffer;
GLShaderProgram m_shader_prog; GLFragmentProgram m_fragment_prog;
GLVertexProgram m_vertex_prog; GLVertexProgram m_vertex_prog;
GLTexture m_gl_textures[m_textures_count]; GLTexture m_gl_textures[m_textures_count];
GLTexture m_gl_vertex_textures[m_textures_count];
GLvao m_vao; GLvao m_vao;
GLvbo m_vbo; GLvbo m_vbo;
@@ -170,7 +171,6 @@ private:
void InitVertexData(); void InitVertexData();
void InitFragmentData(); void InitFragmentData();
void Enable(bool enable, const u32 cap);
virtual void Close(); virtual void Close();
bool LoadProgram(); bool LoadProgram();
void WriteBuffers(); void WriteBuffers();
@@ -189,7 +189,34 @@ protected:
virtual void OnInitThread(); virtual void OnInitThread();
virtual void OnExitThread(); virtual void OnExitThread();
virtual void OnReset(); virtual void OnReset();
virtual void ExecCMD(u32 cmd);
virtual void ExecCMD(); virtual void ExecCMD();
virtual void Enable(u32 cmd, u32 enable);
virtual void ClearColor(u32 a, u32 r, u32 g, u32 b);
virtual void ClearStencil(u32 stencil);
virtual void ClearDepth(u32 depth);
virtual void ClearSurface(u32 mask);
virtual void ColorMask(bool a, bool r, bool g, bool b);
virtual void AlphaFunc(u32 func, float ref);
virtual void DepthFunc(u32 func);
virtual void DepthMask(u32 flag);
virtual void PolygonMode(u32 face, u32 mode);
virtual void PointSize(float size);
virtual void LogicOp(u32 opcdoe);
virtual void LineWidth(float width);
virtual void LineStipple(u16 factor, u16 pattern);
virtual void PrimitiveRestartIndex(u32 index);
virtual void CullFace(u32 mode);
virtual void FrontFace(u32 mode);
virtual void Fogi(u32 mode);
virtual void Fogf(float start, float end);
virtual void PolygonOffset(float factor, float bias);
virtual void DepthRangef(float min, float max);
virtual void BlendEquationSeparate(u16 rgb, u16 a);
virtual void BlendFuncSeparate(u16 srcRGB, u16 dstRGB, u16 srcAlpha, u16 dstAlpha);
virtual void BlendColor(u8 r, u8 g, u8 b, u8 a);
virtual void LightModeli(u32 enable);
virtual void ShadeModel(u32 mode);
virtual void DepthBoundsEXT(float min, float max);
virtual void Scissor(u16 x, u16 y, u16 width, u16 height);
virtual void Flip(); virtual void Flip();
}; };
+7
View File
@@ -98,6 +98,13 @@ void GLProgram::SetTex(u32 index)
checkForGlError(fmt::Format("SetTex(%u - %d - %d)", id, index, loc)); checkForGlError(fmt::Format("SetTex(%u - %d - %d)", id, index, loc));
} }
void GLProgram::SetVTex(u32 index)
{
int loc = GetLocation(fmt::Format("vtex%u", index));
glProgramUniform1i(id, loc, index);
checkForGlError(fmt::Format("SetVTex(%u - %d - %d)", id, index, loc));
}
void GLProgram::Delete() void GLProgram::Delete()
{ {
if(!IsCreated()) return; if(!IsCreated()) return;
+1
View File
@@ -24,5 +24,6 @@ public:
void Use(); void Use();
void UnUse(); void UnUse();
void SetTex(u32 index); void SetTex(u32 index);
void SetVTex(u32 index);
void Delete(); void Delete();
}; };
+8 -8
View File
@@ -4,14 +4,14 @@
#include "GLProgramBuffer.h" #include "GLProgramBuffer.h"
int GLProgramBuffer::SearchFp(const RSXShaderProgram& rsx_fp, GLShaderProgram& gl_fp) int GLProgramBuffer::SearchFp(const RSXFragmentProgram& rsx_fp, GLFragmentProgram& gl_fp)
{ {
for(u32 i=0; i<m_buf.size(); ++i) for(u32 i=0; i<m_buf.size(); ++i)
{ {
if(memcmp(&m_buf[i].fp_data[0], vm::get_ptr<void>(rsx_fp.addr), m_buf[i].fp_data.size()) != 0) continue; if(memcmp(&m_buf[i].fp_data[0], vm::get_ptr<void>(rsx_fp.addr), m_buf[i].fp_data.size()) != 0) continue;
gl_fp.SetId(m_buf[i].fp_id); gl_fp.id = m_buf[i].fp_id;
gl_fp.SetShaderText(m_buf[i].fp_shader); gl_fp.shader = m_buf[i].fp_shader.c_str();
return i; return i;
} }
@@ -85,30 +85,30 @@ u32 GLProgramBuffer::GetProg(u32 fp, u32 vp) const
return 0; return 0;
} }
void GLProgramBuffer::Add(GLProgram& prog, GLShaderProgram& gl_fp, RSXShaderProgram& rsx_fp, GLVertexProgram& gl_vp, RSXVertexProgram& rsx_vp) void GLProgramBuffer::Add(GLProgram& prog, GLFragmentProgram& gl_fp, RSXFragmentProgram& rsx_fp, GLVertexProgram& gl_vp, RSXVertexProgram& rsx_vp)
{ {
GLBufferInfo new_buf; GLBufferInfo new_buf;
LOG_NOTICE(RSX, "Add program (%d):", m_buf.size()); LOG_NOTICE(RSX, "Add program (%d):", m_buf.size());
LOG_NOTICE(RSX, "*** prog id = %d", prog.id); LOG_NOTICE(RSX, "*** prog id = %d", prog.id);
LOG_NOTICE(RSX, "*** vp id = %d", gl_vp.id); LOG_NOTICE(RSX, "*** vp id = %d", gl_vp.id);
LOG_NOTICE(RSX, "*** fp id = %d", gl_fp.GetId()); LOG_NOTICE(RSX, "*** fp id = %d", gl_fp.id);
LOG_NOTICE(RSX, "*** vp data size = %d", rsx_vp.data.size() * 4); LOG_NOTICE(RSX, "*** vp data size = %d", rsx_vp.data.size() * 4);
LOG_NOTICE(RSX, "*** fp data size = %d", rsx_fp.size); LOG_NOTICE(RSX, "*** fp data size = %d", rsx_fp.size);
LOG_NOTICE(RSX, "*** vp shader = \n%s", gl_vp.shader.c_str()); LOG_NOTICE(RSX, "*** vp shader = \n%s", gl_vp.shader.c_str());
LOG_NOTICE(RSX, "*** fp shader = \n%s", gl_fp.GetShaderText().c_str()); LOG_NOTICE(RSX, "*** fp shader = \n%s", gl_fp.shader.c_str());
new_buf.prog_id = prog.id; new_buf.prog_id = prog.id;
new_buf.vp_id = gl_vp.id; new_buf.vp_id = gl_vp.id;
new_buf.fp_id = gl_fp.GetId(); new_buf.fp_id = gl_fp.id;
new_buf.fp_data.insert(new_buf.fp_data.end(), vm::get_ptr<u8>(rsx_fp.addr), vm::get_ptr<u8>(rsx_fp.addr + rsx_fp.size)); new_buf.fp_data.insert(new_buf.fp_data.end(), vm::get_ptr<u8>(rsx_fp.addr), vm::get_ptr<u8>(rsx_fp.addr + rsx_fp.size));
new_buf.vp_data = rsx_vp.data; new_buf.vp_data = rsx_vp.data;
new_buf.vp_shader = gl_vp.shader; new_buf.vp_shader = gl_vp.shader;
new_buf.fp_shader = gl_fp.GetShaderText(); new_buf.fp_shader = gl_fp.shader;
m_buf.push_back(new_buf); m_buf.push_back(new_buf);
} }
+2 -2
View File
@@ -16,7 +16,7 @@ struct GLProgramBuffer
{ {
std::vector<GLBufferInfo> m_buf; std::vector<GLBufferInfo> m_buf;
int SearchFp(const RSXShaderProgram& rsx_fp, GLShaderProgram& gl_fp); int SearchFp(const RSXFragmentProgram& rsx_fp, GLFragmentProgram& gl_fp);
int SearchVp(const RSXVertexProgram& rsx_vp, GLVertexProgram& gl_vp); int SearchVp(const RSXVertexProgram& rsx_vp, GLVertexProgram& gl_vp);
bool CmpVP(const u32 a, const u32 b) const; bool CmpVP(const u32 a, const u32 b) const;
@@ -24,6 +24,6 @@ struct GLProgramBuffer
u32 GetProg(u32 fp, u32 vp) const; u32 GetProg(u32 fp, u32 vp) const;
void Add(GLProgram& prog, GLShaderProgram& gl_fp, RSXShaderProgram& rsx_fp, GLVertexProgram& gl_vp, RSXVertexProgram& rsx_vp); void Add(GLProgram& prog, GLFragmentProgram& gl_fp, RSXFragmentProgram& rsx_fp, GLVertexProgram& gl_vp, RSXVertexProgram& rsx_vp);
void Clear(); void Clear();
}; };
+88
View File
@@ -1,5 +1,6 @@
#pragma once #pragma once
#include "OpenGL.h" #include "OpenGL.h"
#include <unordered_map>
enum GLParamFlag enum GLParamFlag
{ {
@@ -139,3 +140,90 @@ struct GLParamArray
return name; return name;
} }
}; };
class ShaderVar
{
public:
std::string name;
std::vector<std::string> swizzles;
ShaderVar() = default;
ShaderVar(const std::string& var)
{
auto var_blocks = fmt::split(var, { "." });
if (var_blocks.size() == 0)
{
assert(0);
}
name = var_blocks[0];
if (var_blocks.size() == 1)
{
swizzles.push_back("xyzw");
}
else
{
swizzles = std::vector<std::string>(var_blocks.begin() + 1, var_blocks.end());
}
}
int get_vector_size() const
{
return swizzles[swizzles.size() - 1].length();
}
ShaderVar& symplify()
{
std::unordered_map<char, char> swizzle;
static std::unordered_map<int, char> pos_to_swizzle =
{
{ 0, 'x' },
{ 1, 'y' },
{ 2, 'z' },
{ 3, 'w' }
};
for (auto &i : pos_to_swizzle)
{
swizzle[i.second] = swizzles[0].length() > i.first ? swizzles[0][i.first] : 0;
}
for (int i = 1; i < swizzles.size(); ++i)
{
std::unordered_map<char, char> new_swizzle;
for (auto &sw : pos_to_swizzle)
{
new_swizzle[sw.second] = swizzle[swizzles[i].length() <= sw.first ? '\0' : swizzles[i][sw.first]];
}
swizzle = new_swizzle;
}
swizzles.clear();
std::string new_swizzle;
for (auto &i : pos_to_swizzle)
{
if (swizzle[i.second] != '\0')
new_swizzle += swizzle[i.second];
}
swizzles.push_back(new_swizzle);
return *this;
}
std::string get() const
{
if (swizzles.size() == 1 && swizzles[0] == "xyzw")
{
return name;
}
return name + "." + fmt::merge({ swizzles }, ".");
}
};
+300 -98
View File
@@ -140,7 +140,7 @@ void GLVertexDecompilerThread::SetDST(bool is_sca, std::string value)
if (is_sca && d0.vec_result) if (is_sca && d0.vec_result)
{ {
value = "vec4(" + value + ")" + mask; //value = "vec4(" + value + ")";
} }
if (d0.staturate) if (d0.staturate)
@@ -152,22 +152,20 @@ void GLVertexDecompilerThread::SetDST(bool is_sca, std::string value)
if (d0.cond_update_enable_0 && d0.cond_update_enable_1) if (d0.cond_update_enable_0 && d0.cond_update_enable_1)
{ {
dest += m_parr.AddParam(PARAM_NONE, "vec4", "cc" + std::to_string(d0.cond_reg_sel_1), "vec4(0.0)") + mask + " = "; dest = m_parr.AddParam(PARAM_NONE, "vec4", "cc" + std::to_string(d0.cond_reg_sel_1), "vec4(0.0)") + mask;
} }
else if (d3.dst != 0x1f || (is_sca ? d3.sca_dst_tmp != 0x3f : d0.dst_tmp != 0x3f))
if (d3.dst != 0x1f || (is_sca ? d3.sca_dst_tmp != 0x3f : d0.dst_tmp != 0x3f))
{ {
dest += GetDST(is_sca) + mask + " = "; dest = GetDST(is_sca) + mask;
} }
std::string code; //std::string code;
//if (d0.cond_test_enable)
// code += "$ifcond ";
//code += dest + value;
//AddCode(code + ";");
if (d0.cond_test_enable) AddCodeCond(Format(dest), value);
code += "$ifcond ";
code += dest + value;
AddCode(code + ";");
} }
std::string GLVertexDecompilerThread::GetFunc() std::string GLVertexDecompilerThread::GetFunc()
@@ -188,6 +186,11 @@ std::string GLVertexDecompilerThread::GetFunc()
return name + "()"; return name + "()";
} }
std::string GLVertexDecompilerThread::GetTex()
{
return m_parr.AddParam(PARAM_UNIFORM, "sampler2D", std::string("vtex") + std::to_string(/*?.tex_num*/0));
}
std::string GLVertexDecompilerThread::Format(const std::string& code) std::string GLVertexDecompilerThread::Format(const std::string& code)
{ {
const std::pair<std::string, std::function<std::string()>> repl_list[] = const std::pair<std::string, std::function<std::string()>> repl_list[] =
@@ -200,6 +203,8 @@ std::string GLVertexDecompilerThread::Format(const std::string& code)
{ "$am", std::bind(std::mem_fn(&GLVertexDecompilerThread::AddAddrMask), this) }, { "$am", std::bind(std::mem_fn(&GLVertexDecompilerThread::AddAddrMask), this) },
{ "$a", std::bind(std::mem_fn(&GLVertexDecompilerThread::AddAddrReg), this) }, { "$a", std::bind(std::mem_fn(&GLVertexDecompilerThread::AddAddrReg), this) },
{ "$t", std::bind(std::mem_fn(&GLVertexDecompilerThread::GetTex), this) },
{ "$fa", [this]()->std::string { return std::to_string(GetAddr()); } }, { "$fa", [this]()->std::string { return std::to_string(GetAddr()); } },
{ "$f()", std::bind(std::mem_fn(&GLVertexDecompilerThread::GetFunc), this) }, { "$f()", std::bind(std::mem_fn(&GLVertexDecompilerThread::GetFunc), this) },
{ "$ifcond ", [this]() -> std::string { "$ifcond ", [this]() -> std::string
@@ -252,6 +257,70 @@ std::string GLVertexDecompilerThread::GetCond()
return fmt::Format("any(%s(cc%d%s, vec4(0.0)%s))", cond_string_table[d0.cond], d0.cond_reg_sel_1, swizzle.c_str(), swizzle.c_str()); return fmt::Format("any(%s(cc%d%s, vec4(0.0)%s))", cond_string_table[d0.cond], d0.cond_reg_sel_1, swizzle.c_str(), swizzle.c_str());
} }
void GLVertexDecompilerThread::AddCodeCond(const std::string& dst, const std::string& src)
{
enum
{
lt = 0x1,
eq = 0x2,
gt = 0x4,
};
if (!d0.cond_test_enable || d0.cond == (lt | gt | eq))
{
AddCode(dst + " = " + src + ";");
return;
}
if (d0.cond == 0)
{
AddCode("//" + dst + " = " + src + ";");
return;
}
static const char* cond_string_table[(lt | gt | eq) + 1] =
{
"error",
"lessThan",
"equal",
"lessThanEqual",
"greaterThan",
"notEqual",
"greaterThanEqual",
"error"
};
static const char f[4] = { 'x', 'y', 'z', 'w' };
std::string swizzle;
swizzle += f[d0.mask_x];
swizzle += f[d0.mask_y];
swizzle += f[d0.mask_z];
swizzle += f[d0.mask_w];
swizzle = swizzle == "xyzw" ? "" : "." + swizzle;
std::string cond = fmt::Format("%s(cc%d%s, vec4(0.0))", cond_string_table[d0.cond], d0.cond_reg_sel_1, swizzle.c_str());
ShaderVar dst_var(dst);
dst_var.symplify();
//const char *c_mask = f;
if (dst_var.swizzles[0].length() == 1)
{
AddCode("if (" + cond + ".x) " + dst + " = vec4(" + src + ").x;");
}
else
{
for (int i = 0; i < dst_var.swizzles[0].length(); ++i)
{
AddCode("if (" + cond + "." + f[i] + ") " + dst + "." + f[i] + " = " + src + "." + f[i] + ";");
}
}
}
std::string GLVertexDecompilerThread::AddAddrMask() std::string GLVertexDecompilerThread::AddAddrMask()
{ {
@@ -445,120 +514,250 @@ void GLVertexDecompilerThread::Task()
m_instr_count = 0; m_instr_count = 0;
for (int i = 0; i < m_max_instr_count; ++i) for (int i = 0; i < m_max_instr_count; ++i)
{
m_instructions[i].reset(); m_instructions[i].reset();
}
for (u32 i = 0; m_instr_count < m_max_instr_count; m_instr_count++) bool is_has_BRA = false;
for (u32 i = 1; m_instr_count < m_max_instr_count; m_instr_count++)
{ {
m_cur_instr = &m_instructions[m_instr_count]; m_cur_instr = &m_instructions[m_instr_count];
d0.HEX = m_data[i++]; if (is_has_BRA)
d1.HEX = m_data[i++];
d2.HEX = m_data[i++];
d3.HEX = m_data[i++];
src[0].src0l = d2.src0l;
src[0].src0h = d1.src0h;
src[1].src1 = d2.src1;
src[2].src2l = d3.src2l;
src[2].src2h = d2.src2h;
if(!d1.sca_opcode && !d1.vec_opcode)
{ {
m_body.push_back("//nop"); d3.HEX = m_data[i];
} i += 4;
switch(d1.sca_opcode)
{
case 0x00: break; // NOP
case 0x01: SetDSTSca("$s"); break; // MOV
case 0x02: SetDSTSca("(1.0 / $s)"); break; // RCP
case 0x03: SetDSTSca("clamp(1.0 / $s, 5.42101e-20, 1.884467e19)"); break; // RCC
case 0x04: SetDSTSca("inversesqrt(abs($s))"); break; // RSQ
case 0x05: SetDSTSca("exp($s)"); break; // EXP
case 0x06: SetDSTSca("log($s)"); break; // LOG
case 0x07: SetDSTSca("vec4(1.0, $s.x, ($s.x > 0 ? exp2($s.w * log2($s.y)) : 0.0), 1.0)"); break; // LIT
//case 0x08: break; // BRA
case 0x09: // BRI : works differently (BRI o[1].x(TR) L0;)
//AddCode("$ifcond { $f(); return; }");
if (GetAddr() > m_instr_count)
{
AddCode("if(!$cond)");
AddCode("{");
m_cur_instr->open_scopes++;
m_instructions[GetAddr()].put_close_scopes++;
} }
else else
{ {
AddCode("} while ($cond);"); d1.HEX = m_data[i++];
m_cur_instr->close_scopes++;
m_instructions[GetAddr()].do_count++;
}
break;
//case 0x0a: AddCode("$ifcond $f(); //CAL"); break; // CAL : works same as BRI
case 0x0b: AddCode("$ifcond $f(); //CLI"); break; // CLI : works same as BRI
case 0x0c: AddCode("$ifcond return;"); break; // RET : works like BRI but shorter (RET o[1].x(TR);)
case 0x0d: SetDSTSca("log2($s)"); break; // LG2
case 0x0e: SetDSTSca("exp2($s)"); break; // EX2
case 0x0f: SetDSTSca("sin($s)"); break; // SIN
case 0x10: SetDSTSca("cos($s)"); break; // COS
//case 0x11: break; // BRB : works differently (BRB o[1].x !b0, L0;)
//case 0x12: break; // CLB : works same as BRB
//case 0x13: break; // PSH : works differently (PSH o[1].x A0;)
//case 0x14: break; // POP : works differently (POP o[1].x;)
default: switch (d1.sca_opcode)
m_body.push_back(fmt::Format("//Unknown vp sca_opcode 0x%x", fmt::by_value(d1.sca_opcode)));
LOG_ERROR(RSX, "Unknown vp sca_opcode 0x%x", fmt::by_value(d1.sca_opcode));
Emu.Pause();
break;
}
switch(d1.vec_opcode)
{ {
case 0x00: break; //NOP case 0x08: //BRA
case 0x01: SetDSTVec("$0"); break; //MOV LOG_WARNING(RSX, "BRA found. Please report to RPCS3 team.");
case 0x02: SetDSTVec("($0 * $1)"); break; //MUL is_has_BRA = true;
case 0x03: SetDSTVec("($0 + $2)"); break; //ADD m_jump_lvls.clear();
case 0x04: SetDSTVec("($0 * $1 + $2)"); break; //MAD d3.HEX = m_data[++i];
case 0x05: SetDSTVec("vec4(dot($0.xyz, $1.xyz))"); break; //DP3 i += 4;
case 0x06: SetDSTVec("vec4(dot(vec4($0.xyz, 1.0), $1))"); break; //DPH break;
case 0x07: SetDSTVec("vec4(dot($0, $1))"); break; //DP4
case 0x08: SetDSTVec("vec4(distance($0, $1))"); break; //DST case 0x09: //BRI
case 0x09: SetDSTVec("min($0, $1)"); break; //MIN d2.HEX = m_data[i++];
case 0x0a: SetDSTVec("max($0, $1)"); break; //MAX d3.HEX = m_data[i];
case 0x0b: SetDSTVec("vec4(lessThan($0, $1))"); break; //SLT i += 2;
case 0x0c: SetDSTVec("vec4(greaterThanEqual($0, $1))"); break; //SGE m_jump_lvls.emplace(GetAddr());
case 0x0d: AddCode("$ifcond $a = ivec4($0)$am;"); break; //ARL break;
case 0x0e: SetDSTVec("fract($0)"); break; //FRC
case 0x0f: SetDSTVec("floor($0)"); break; //FLR
case 0x10: SetDSTVec("vec4(equal($0, $1))"); break; //SEQ
case 0x11: SetDSTVec("vec4(equal($0, vec4(0.0)))"); break; //SFL
case 0x12: SetDSTVec("vec4(greaterThan($0, $1))"); break; //SGT
case 0x13: SetDSTVec("vec4(lessThanEqual($0, $1))"); break; //SLE
case 0x14: SetDSTVec("vec4(notEqual($0, $1))"); break; //SNE
case 0x15: SetDSTVec("vec4(equal($0, vec4(1.0)))"); break; //STR
case 0x16: SetDSTVec("sign($0)"); break; //SSG
default: default:
m_body.push_back(fmt::Format("//Unknown vp opcode 0x%x", fmt::by_value(d1.vec_opcode))); d3.HEX = m_data[++i];
LOG_ERROR(RSX, "Unknown vp opcode 0x%x", fmt::by_value(d1.vec_opcode)); i += 2;
Emu.Pause();
break; break;
} }
}
if (d3.end) if (d3.end)
{ {
m_instr_count++; m_instr_count++;
if (i < m_data.size()) if (i < m_data.size())
{
LOG_ERROR(RSX, "Program end before buffer end."); LOG_ERROR(RSX, "Program end before buffer end.");
}
break; break;
} }
} }
uint jump_position = 0;
if (is_has_BRA || !m_jump_lvls.empty())
{
m_cur_instr = &m_instructions[0];
AddCode("int jump_position = 0;");
AddCode("while (true)");
AddCode("{");
m_cur_instr->open_scopes++;
AddCode(fmt::Format("if (jump_position <= %u)", jump_position++));
AddCode("{");
m_cur_instr->open_scopes++;
}
for (u32 i = 0; i < m_instr_count; ++i)
{
m_cur_instr = &m_instructions[i];
d0.HEX = m_data[i * 4 + 0];
d1.HEX = m_data[i * 4 + 1];
d2.HEX = m_data[i * 4 + 2];
d3.HEX = m_data[i * 4 + 3];
src[0].src0l = d2.src0l;
src[0].src0h = d1.src0h;
src[1].src1 = d2.src1;
src[2].src2l = d3.src2l;
src[2].src2h = d2.src2h;
if (i && (is_has_BRA || std::find(m_jump_lvls.begin(), m_jump_lvls.end(), i) != m_jump_lvls.end()))
{
m_cur_instr->close_scopes++;
AddCode("}");
AddCode("");
AddCode(fmt::Format("if (jump_position <= %u)", jump_position++));
AddCode("{");
m_cur_instr->open_scopes++;
}
if (!d1.sca_opcode && !d1.vec_opcode)
{
AddCode("//nop");
}
switch (d1.sca_opcode)
{
case RSX_SCA_OPCODE_NOP: break;
case RSX_SCA_OPCODE_MOV: SetDSTSca("$s"); break;
case RSX_SCA_OPCODE_RCP: SetDSTSca("(1.0 / $s)"); break;
case RSX_SCA_OPCODE_RCC: SetDSTSca("clamp(1.0 / $s, 5.42101e-20, 1.884467e19)"); break;
case RSX_SCA_OPCODE_RSQ: SetDSTSca("inversesqrt(abs($s))"); break;
case RSX_SCA_OPCODE_EXP: SetDSTSca("exp($s)"); break;
case RSX_SCA_OPCODE_LOG: SetDSTSca("log($s)"); break;
case RSX_SCA_OPCODE_LIT: SetDSTSca("vec4(1.0, $s.x, ($s.x > 0.0 ? exp($s.w * log2($s.y)) : 0.0), 1.0)"); break;
case RSX_SCA_OPCODE_BRA:
{
AddCode("$if ($cond)");
AddCode("{");
m_cur_instr->open_scopes++;
AddCode("jump_position = $a$am;");
AddCode("continue;");
m_cur_instr->close_scopes++;
AddCode("}");
}
break;
/* This triggers opengl driver lost connection error code 7
case RSX_SCA_OPCODE_BRI: // works differently (BRI o[1].x(TR) L0;)
{
uint jump_position;
if (is_has_BRA)
{
jump_position = GetAddr();
}
else
{
int addr = GetAddr();
jump_position = 0;
for (auto pos : m_jump_lvls)
{
if (addr == pos)
break;
++jump_position;
}
}
AddCode("$ifcond ");
AddCode("{");
m_cur_instr->open_scopes++;
AddCode(fmt::Format("jump_position = %u;", jump_position));
AddCode("continue;");
m_cur_instr->close_scopes++;
AddCode("}");
}
break;
*/
case RSX_SCA_OPCODE_CAL:
// works same as BRI
AddCode("$ifcond $f(); //CAL");
break;
case RSX_SCA_OPCODE_CLI:
// works same as BRI
AddCode("$ifcond $f(); //CLI");
break;
case RSX_SCA_OPCODE_RET:
// works like BRI but shorter (RET o[1].x(TR);)
AddCode("$ifcond return;");
break;
case RSX_SCA_OPCODE_LG2: SetDSTSca("log2($s)"); break;
case RSX_SCA_OPCODE_EX2: SetDSTSca("exp2($s)"); break;
case RSX_SCA_OPCODE_SIN: SetDSTSca("sin($s)"); break;
case RSX_SCA_OPCODE_COS: SetDSTSca("cos($s)"); break;
case RSX_SCA_OPCODE_BRB:
// works differently (BRB o[1].x !b0, L0;)
LOG_ERROR(RSX, "Unimplemented sca_opcode BRB");
break;
case RSX_SCA_OPCODE_CLB: break;
// works same as BRB
LOG_ERROR(RSX, "Unimplemented sca_opcode CLB");
break;
case RSX_SCA_OPCODE_PSH: break;
// works differently (PSH o[1].x A0;)
LOG_ERROR(RSX, "Unimplemented sca_opcode PSH");
break;
case RSX_SCA_OPCODE_POP: break;
// works differently (POP o[1].x;)
LOG_ERROR(RSX, "Unimplemented sca_opcode POP");
break;
default:
AddCode(fmt::Format("//Unknown vp sca_opcode 0x%x", fmt::by_value(d1.sca_opcode)));
LOG_ERROR(RSX, "Unknown vp sca_opcode 0x%x", fmt::by_value(d1.sca_opcode));
Emu.Pause();
break;
}
switch (d1.vec_opcode)
{
case RSX_VEC_OPCODE_NOP: break;
case RSX_VEC_OPCODE_MOV: SetDSTVec("$0"); break;
case RSX_VEC_OPCODE_MUL: SetDSTVec("($0 * $1)"); break;
case RSX_VEC_OPCODE_ADD: SetDSTVec("($0 + $2)"); break;
case RSX_VEC_OPCODE_MAD: SetDSTVec("($0 * $1 + $2)"); break;
case RSX_VEC_OPCODE_DP3: SetDSTVec("vec4(dot($0.xyz, $1.xyz))"); break;
case RSX_VEC_OPCODE_DPH: SetDSTVec("vec4(dot(vec4($0.xyz, 1.0), $1))"); break;
case RSX_VEC_OPCODE_DP4: SetDSTVec("vec4(dot($0, $1))"); break;
case RSX_VEC_OPCODE_DST: SetDSTVec("vec4(distance($0, $1))"); break;
case RSX_VEC_OPCODE_MIN: SetDSTVec("min($0, $1)"); break;
case RSX_VEC_OPCODE_MAX: SetDSTVec("max($0, $1)"); break;
case RSX_VEC_OPCODE_SLT: SetDSTVec("vec4(lessThan($0, $1))"); break;
case RSX_VEC_OPCODE_SGE: SetDSTVec("vec4(greaterThanEqual($0, $1))"); break;
case RSX_VEC_OPCODE_ARL: AddCode("$ifcond $a = ivec4($0)$am;"); break;
case RSX_VEC_OPCODE_FRC: SetDSTVec("fract($0)"); break;
case RSX_VEC_OPCODE_FLR: SetDSTVec("floor($0)"); break;
case RSX_VEC_OPCODE_SEQ: SetDSTVec("vec4(equal($0, $1))"); break;
case RSX_VEC_OPCODE_SFL: SetDSTVec("vec4(equal($0, vec4(0.0)))"); break;
case RSX_VEC_OPCODE_SGT: SetDSTVec("vec4(greaterThan($0, $1))"); break;
case RSX_VEC_OPCODE_SLE: SetDSTVec("vec4(lessThanEqual($0, $1))"); break;
case RSX_VEC_OPCODE_SNE: SetDSTVec("vec4(notEqual($0, $1))"); break;
case RSX_VEC_OPCODE_STR: SetDSTVec("vec4(equal($0, vec4(1.0)))"); break;
case RSX_VEC_OPCODE_SSG: SetDSTVec("sign($0)"); break;
case RSX_VEC_OPCODE_TEX: SetDSTVec("texture($t, $0.xy)"); break;
default:
AddCode(fmt::Format("//Unknown vp opcode 0x%x", fmt::by_value(d1.vec_opcode)));
LOG_ERROR(RSX, "Unknown vp opcode 0x%x", fmt::by_value(d1.vec_opcode));
Emu.Pause();
break;
}
}
if (is_has_BRA || !m_jump_lvls.empty())
{
m_cur_instr = &m_instructions[m_instr_count - 1];
m_cur_instr->close_scopes++;
AddCode("}");
AddCode("break;");
m_cur_instr->close_scopes++;
AddCode("}");
}
m_shader = BuildCode(); m_shader = BuildCode();
m_jump_lvls.clear();
m_body.clear(); m_body.clear();
if (m_funcs.size() > 2) if (m_funcs.size() > 2)
{ {
@@ -623,7 +822,10 @@ void GLVertexProgram::DecompileAsync(RSXVertexProgram& prog)
void GLVertexProgram::Compile() void GLVertexProgram::Compile()
{ {
if(id) glDeleteShader(id); if (id)
{
glDeleteShader(id);
}
id = glCreateShader(GL_VERTEX_SHADER); id = glCreateShader(GL_VERTEX_SHADER);
+57 -1
View File
@@ -2,6 +2,60 @@
#include "GLShaderParam.h" #include "GLShaderParam.h"
#include "Emu/RSX/RSXVertexProgram.h" #include "Emu/RSX/RSXVertexProgram.h"
#include "Utilities/Thread.h" #include "Utilities/Thread.h"
#include <set>
enum sca_opcode
{
RSX_SCA_OPCODE_NOP = 0x00,
RSX_SCA_OPCODE_MOV = 0x01,
RSX_SCA_OPCODE_RCP = 0x02,
RSX_SCA_OPCODE_RCC = 0x03,
RSX_SCA_OPCODE_RSQ = 0x04,
RSX_SCA_OPCODE_EXP = 0x05,
RSX_SCA_OPCODE_LOG = 0x06,
RSX_SCA_OPCODE_LIT = 0x07,
RSX_SCA_OPCODE_BRA = 0x08,
RSX_SCA_OPCODE_BRI = 0x09,
RSX_SCA_OPCODE_CAL = 0x0a,
RSX_SCA_OPCODE_CLI = 0x0b,
RSX_SCA_OPCODE_RET = 0x0c,
RSX_SCA_OPCODE_LG2 = 0x0d,
RSX_SCA_OPCODE_EX2 = 0x0e,
RSX_SCA_OPCODE_SIN = 0x0f,
RSX_SCA_OPCODE_COS = 0x10,
RSX_SCA_OPCODE_BRB = 0x11,
RSX_SCA_OPCODE_CLB = 0x12,
RSX_SCA_OPCODE_PSH = 0x13,
RSX_SCA_OPCODE_POP = 0x14,
};
enum vec_opcode
{
RSX_VEC_OPCODE_NOP = 0x00,
RSX_VEC_OPCODE_MOV = 0x01,
RSX_VEC_OPCODE_MUL = 0x02,
RSX_VEC_OPCODE_ADD = 0x03,
RSX_VEC_OPCODE_MAD = 0x04,
RSX_VEC_OPCODE_DP3 = 0x05,
RSX_VEC_OPCODE_DPH = 0x06,
RSX_VEC_OPCODE_DP4 = 0x07,
RSX_VEC_OPCODE_DST = 0x08,
RSX_VEC_OPCODE_MIN = 0x09,
RSX_VEC_OPCODE_MAX = 0x0a,
RSX_VEC_OPCODE_SLT = 0x0b,
RSX_VEC_OPCODE_SGE = 0x0c,
RSX_VEC_OPCODE_ARL = 0x0d,
RSX_VEC_OPCODE_FRC = 0x0e,
RSX_VEC_OPCODE_FLR = 0x0f,
RSX_VEC_OPCODE_SEQ = 0x10,
RSX_VEC_OPCODE_SFL = 0x11,
RSX_VEC_OPCODE_SGT = 0x12,
RSX_VEC_OPCODE_SLE = 0x13,
RSX_VEC_OPCODE_SNE = 0x14,
RSX_VEC_OPCODE_STR = 0x15,
RSX_VEC_OPCODE_SSG = 0x16,
RSX_VEC_OPCODE_TEX = 0x19,
};
struct GLVertexDecompilerThread : public ThreadBase struct GLVertexDecompilerThread : public ThreadBase
{ {
@@ -154,8 +208,8 @@ struct GLVertexDecompilerThread : public ThreadBase
Instruction* m_cur_instr; Instruction* m_cur_instr;
size_t m_instr_count; size_t m_instr_count;
std::set<int> m_jump_lvls;
std::vector<std::string> m_body; std::vector<std::string> m_body;
std::vector<FuncInfo> m_funcs; std::vector<FuncInfo> m_funcs;
//wxString main; //wxString main;
@@ -184,12 +238,14 @@ struct GLVertexDecompilerThread : public ThreadBase
std::string GetDST(bool is_sca = false); std::string GetDST(bool is_sca = false);
std::string GetSRC(const u32 n); std::string GetSRC(const u32 n);
std::string GetFunc(); std::string GetFunc();
std::string GetTex();
std::string GetCond(); std::string GetCond();
std::string AddAddrMask(); std::string AddAddrMask();
std::string AddAddrReg(); std::string AddAddrReg();
u32 GetAddr(); u32 GetAddr();
std::string Format(const std::string& code); std::string Format(const std::string& code);
void AddCodeCond(const std::string& dst, const std::string& src);
void AddCode(const std::string& code); void AddCode(const std::string& code);
void SetDST(bool is_sca, std::string value); void SetDST(bool is_sca, std::string value);
void SetDSTVec(const std::string& code); void SetDSTVec(const std::string& code);
+37 -38
View File
@@ -6,44 +6,43 @@ class NullGSRender
{ {
public: public:
NullGSRender() NullGSRender() {}
{ virtual ~NullGSRender() {}
}
virtual ~NullGSRender()
{
}
private: private:
virtual void OnInit() virtual void OnInit() {}
{ virtual void OnInitThread() {}
} virtual void OnExitThread() {}
virtual void OnReset() {}
virtual void OnInitThread() virtual void Enable(u32 cmd, u32 enable) {}
{ virtual void ClearColor(u32 a, u32 r, u32 g, u32 b) {}
} virtual void ClearStencil(u32 stencil) {}
virtual void ClearDepth(u32 depth) {}
virtual void OnExitThread() virtual void ClearSurface(u32 mask) {}
{ virtual void ColorMask(bool a, bool r, bool g, bool b) {}
} virtual void ExecCMD() {}
virtual void AlphaFunc(u32 func, float ref) {}
virtual void OnReset() virtual void DepthFunc(u32 func) {}
{ virtual void DepthMask(u32 flag) {}
} virtual void PolygonMode(u32 face, u32 mode) {}
virtual void PointSize(float size) {}
virtual void ExecCMD(u32 cmd) virtual void LogicOp(u32 opcdoe) {}
{ virtual void LineWidth(float width) {}
} virtual void LineStipple(u16 factor, u16 pattern) {}
virtual void PrimitiveRestartIndex(u32 index) {}
virtual void ExecCMD() virtual void CullFace(u32 mode) {}
{ virtual void FrontFace(u32 mode) {}
} virtual void Fogi(u32 mode) {}
virtual void Fogf(float start, float end) {}
virtual void Flip() virtual void PolygonOffset(float factor, float bias) {}
{ virtual void DepthRangef(float min, float max) {}
} virtual void BlendEquationSeparate(u16 rgb, u16 a) {}
virtual void BlendFuncSeparate(u16 srcRGB, u16 dstRGB, u16 srcAlpha, u16 dstAlpha) {}
virtual void Close() virtual void BlendColor(u8 r, u8 g, u8 b, u8 a) {}
{ virtual void LightModeli(u32 enable) {}
} virtual void ShadeModel(u32 mode) {}
virtual void DepthBoundsEXT(float min, float max) {}
virtual void Scissor(u16 x, u16 y, u16 width, u16 height) {}
virtual void Flip() {}
virtual void Close() {}
}; };
+3 -3
View File
@@ -49,7 +49,7 @@ enum
RSX_FP_OPCODE_PKG = 0x2C, // Pack with sRGB transformation RSX_FP_OPCODE_PKG = 0x2C, // Pack with sRGB transformation
RSX_FP_OPCODE_UPG = 0x2D, // Unpack gamma RSX_FP_OPCODE_UPG = 0x2D, // Unpack gamma
RSX_FP_OPCODE_DP2A = 0x2E, // 2-component dot product with scalar addition RSX_FP_OPCODE_DP2A = 0x2E, // 2-component dot product with scalar addition
RSX_FP_OPCODE_TXL = 0x2F, // Texture sample with LOD RSX_FP_OPCODE_TXL = 0x2F, // Texture sample with explicit LOD
RSX_FP_OPCODE_TXB = 0x31, // Texture sample with bias RSX_FP_OPCODE_TXB = 0x31, // Texture sample with bias
RSX_FP_OPCODE_TEXBEM = 0x33, RSX_FP_OPCODE_TEXBEM = 0x33,
RSX_FP_OPCODE_TXPBEM = 0x34, RSX_FP_OPCODE_TXPBEM = 0x34,
@@ -71,14 +71,14 @@ enum
RSX_FP_OPCODE_RET = 0x45, // Return RSX_FP_OPCODE_RET = 0x45, // Return
}; };
struct RSXShaderProgram struct RSXFragmentProgram
{ {
u32 size; u32 size;
u32 addr; u32 addr;
u32 offset; u32 offset;
u32 ctrl; u32 ctrl;
RSXShaderProgram() RSXFragmentProgram()
: size(0) : size(0)
, addr(0) , addr(0)
, offset(0) , offset(0)
+203
View File
@@ -210,3 +210,206 @@ void RSXTexture::SetControl3(u16 depth, u32 pitch)
m_depth = depth; m_depth = depth;
m_pitch = pitch; m_pitch = pitch;
} }
RSXVertexTexture::RSXVertexTexture() : RSXTexture()
{
}
RSXVertexTexture::RSXVertexTexture(u8 index) : RSXTexture(index)
{
}
void RSXVertexTexture::Init()
{
// Offset
methodRegisters[NV4097_SET_VERTEX_TEXTURE_OFFSET + (m_index * 32)] = 0;
// Format
methodRegisters[NV4097_SET_VERTEX_TEXTURE_FORMAT + (m_index * 32)] = 0;
// Address
methodRegisters[NV4097_SET_VERTEX_TEXTURE_ADDRESS + (m_index * 32)] =
((/*wraps*/1) | ((/*anisoBias*/0) << 4) | ((/*wrapt*/1) << 8) | ((/*unsignedRemap*/0) << 12) |
((/*wrapr*/3) << 16) | ((/*gamma*/0) << 20) | ((/*signedRemap*/0) << 24) | ((/*zfunc*/0) << 28));
// Control0
methodRegisters[NV4097_SET_VERTEX_TEXTURE_CONTROL0 + (m_index * 32)] =
(((/*alphakill*/0) << 2) | (/*maxaniso*/0) << 4) | ((/*maxlod*/0xc00) << 7) | ((/*minlod*/0) << 19) | ((/*enable*/0) << 31);
// Control1
//methodRegisters[NV4097_SET_VERTEX_TEXTURE_CONTROL1 + (m_index * 32)] = 0xE4;
// Filter
methodRegisters[NV4097_SET_VERTEX_TEXTURE_FILTER + (m_index * 32)] =
((/*bias*/0) | ((/*conv*/1) << 13) | ((/*min*/5) << 16) | ((/*mag*/2) << 24)
| ((/*as*/0) << 28) | ((/*rs*/0) << 29) | ((/*gs*/0) << 30) | ((/*bs*/0) << 31));
// Image Rect
methodRegisters[NV4097_SET_VERTEX_TEXTURE_IMAGE_RECT + (m_index * 32)] = (/*height*/1) | ((/*width*/1) << 16);
// Border Color
methodRegisters[NV4097_SET_VERTEX_TEXTURE_BORDER_COLOR + (m_index * 32)] = 0;
}
u32 RSXVertexTexture::GetOffset() const
{
return methodRegisters[NV4097_SET_VERTEX_TEXTURE_OFFSET + (m_index * 32)];
}
u8 RSXVertexTexture::GetLocation() const
{
return (methodRegisters[NV4097_SET_VERTEX_TEXTURE_FORMAT + (m_index * 32)] & 0x3) - 1;
}
bool RSXVertexTexture::isCubemap() const
{
return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_FORMAT + (m_index * 32)] >> 2) & 0x1);
}
u8 RSXVertexTexture::GetBorderType() const
{
return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_FORMAT + (m_index * 32)] >> 3) & 0x1);
}
u8 RSXVertexTexture::GetDimension() const
{
return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_FORMAT + (m_index * 32)] >> 4) & 0xf);
}
u8 RSXVertexTexture::GetFormat() const
{
return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_FORMAT + (m_index * 32)] >> 8) & 0xff);
}
u16 RSXVertexTexture::GetMipmap() const
{
return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_FORMAT + (m_index * 32)] >> 16) & 0xffff);
}
u8 RSXVertexTexture::GetWrapS() const
{
return 1;
return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_ADDRESS + (m_index * 32)]) & 0xf);
}
u8 RSXVertexTexture::GetWrapT() const
{
return 1;
return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_ADDRESS + (m_index * 32)] >> 8) & 0xf);
}
u8 RSXVertexTexture::GetWrapR() const
{
return 1;
return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_ADDRESS + (m_index * 32)] >> 16) & 0xf);
}
u8 RSXVertexTexture::GetUnsignedRemap() const
{
return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_ADDRESS + (m_index * 32)] >> 12) & 0xf);
}
u8 RSXVertexTexture::GetZfunc() const
{
return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_ADDRESS + (m_index * 32)] >> 28) & 0xf);
}
u8 RSXVertexTexture::GetGamma() const
{
return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_ADDRESS + (m_index * 32)] >> 20) & 0xf);
}
u8 RSXVertexTexture::GetAnisoBias() const
{
return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_ADDRESS + (m_index * 32)] >> 4) & 0xf);
}
u8 RSXVertexTexture::GetSignedRemap() const
{
return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_ADDRESS + (m_index * 32)] >> 24) & 0xf);
}
bool RSXVertexTexture::IsEnabled() const
{
return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_CONTROL0 + (m_index * 32)] >> 31) & 0x1);
}
u16 RSXVertexTexture::GetMinLOD() const
{
return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_CONTROL0 + (m_index * 32)] >> 19) & 0xfff);
}
u16 RSXVertexTexture::GetMaxLOD() const
{
return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_CONTROL0 + (m_index * 32)] >> 7) & 0xfff);
}
u8 RSXVertexTexture::GetMaxAniso() const
{
return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_CONTROL0 + (m_index * 32)] >> 4) & 0x7);
}
bool RSXVertexTexture::IsAlphaKillEnabled() const
{
return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_CONTROL0 + (m_index * 32)] >> 2) & 0x1);
}
u32 RSXVertexTexture::GetRemap() const
{
return 0 | (1 << 2) | (2 << 4) | (3 << 6);//(methodRegisters[NV4097_SET_VERTEX_TEXTURE_CONTROL1 + (m_index * 32)]);
}
u16 RSXVertexTexture::GetBias() const
{
return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_FILTER + (m_index * 32)]) & 0x1fff);
}
u8 RSXVertexTexture::GetMinFilter() const
{
return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_FILTER + (m_index * 32)] >> 16) & 0x7);
}
u8 RSXVertexTexture::GetMagFilter() const
{
return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_FILTER + (m_index * 32)] >> 24) & 0x7);
}
u8 RSXVertexTexture::GetConvolutionFilter() const
{
return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_FILTER + (m_index * 32)] >> 13) & 0xf);
}
bool RSXVertexTexture::isASigned() const
{
return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_FILTER + (m_index * 32)] >> 28) & 0x1);
}
bool RSXVertexTexture::isRSigned() const
{
return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_FILTER + (m_index * 32)] >> 29) & 0x1);
}
bool RSXVertexTexture::isGSigned() const
{
return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_FILTER + (m_index * 32)] >> 30) & 0x1);
}
bool RSXVertexTexture::isBSigned() const
{
return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_FILTER + (m_index * 32)] >> 31) & 0x1);
}
u16 RSXVertexTexture::GetWidth() const
{
return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_IMAGE_RECT + (m_index * 32)] >> 16) & 0xffff);
}
u16 RSXVertexTexture::GetHeight() const
{
return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_IMAGE_RECT + (m_index * 32)]) & 0xffff);
}
u32 RSXVertexTexture::GetBorderColor() const
{
return methodRegisters[NV4097_SET_VERTEX_TEXTURE_BORDER_COLOR + (m_index * 32)];
}
+59 -2
View File
@@ -2,6 +2,7 @@
class RSXTexture class RSXTexture
{ {
protected:
u8 m_index; u8 m_index;
public: public:
@@ -11,6 +12,64 @@ public:
public: public:
RSXTexture(); RSXTexture();
RSXTexture(u8 index); RSXTexture(u8 index);
virtual void Init();
// Offset
virtual u32 GetOffset() const;
// Format
virtual u8 GetLocation() const;
virtual bool isCubemap() const;
virtual u8 GetBorderType() const;
virtual u8 GetDimension() const;
virtual u8 GetFormat() const;
virtual u16 GetMipmap() const;
// Address
virtual u8 GetWrapS() const;
virtual u8 GetWrapT() const;
virtual u8 GetWrapR() const;
virtual u8 GetUnsignedRemap() const;
virtual u8 GetZfunc() const;
virtual u8 GetGamma() const;
virtual u8 GetAnisoBias() const;
virtual u8 GetSignedRemap() const;
// Control0
virtual bool IsEnabled() const;
virtual u16 GetMinLOD() const;
virtual u16 GetMaxLOD() const;
virtual u8 GetMaxAniso() const;
virtual bool IsAlphaKillEnabled() const;
// Control1
virtual u32 GetRemap() const;
// Filter
virtual u16 GetBias() const;
virtual u8 GetMinFilter() const;
virtual u8 GetMagFilter() const;
virtual u8 GetConvolutionFilter() const;
virtual bool isASigned() const;
virtual bool isRSigned() const;
virtual bool isGSigned() const;
virtual bool isBSigned() const;
// Image Rect
virtual u16 GetWidth() const;
virtual u16 GetHeight() const;
// Border Color
virtual u32 GetBorderColor() const;
void SetControl3(u16 depth, u32 pitch);
};
class RSXVertexTexture : public RSXTexture
{
public:
RSXVertexTexture();
RSXVertexTexture(u8 index);
void Init(); void Init();
// Offset // Offset
@@ -60,6 +119,4 @@ public:
// Border Color // Border Color
u32 GetBorderColor() const; u32 GetBorderColor() const;
void SetControl3(u16 depth, u32 pitch);
}; };
File diff suppressed because it is too large Load Diff
+41 -7
View File
@@ -7,6 +7,7 @@
#include <stack> #include <stack>
#include "Utilities/SSemaphore.h" #include "Utilities/SSemaphore.h"
#include "Utilities/Thread.h" #include "Utilities/Thread.h"
#include "Utilities/Timer.h"
enum Method enum Method
{ {
@@ -101,19 +102,22 @@ public:
protected: protected:
std::stack<u32> m_call_stack; std::stack<u32> m_call_stack;
CellGcmControl* m_ctrl; CellGcmControl* m_ctrl;
Timer m_timer_sync;
double m_fps_limit = 59.94;
public: public:
GcmTileInfo m_tiles[m_tiles_count]; GcmTileInfo m_tiles[m_tiles_count];
GcmZcullInfo m_zculls[m_zculls_count]; GcmZcullInfo m_zculls[m_zculls_count];
RSXTexture m_textures[m_textures_count]; RSXTexture m_textures[m_textures_count];
RSXVertexTexture m_vertex_textures[m_textures_count];
RSXVertexData m_vertex_data[m_vertex_count]; RSXVertexData m_vertex_data[m_vertex_count];
RSXIndexArrayData m_indexed_array; RSXIndexArrayData m_indexed_array;
std::vector<RSXTransformConstant> m_fragment_constants; std::vector<RSXTransformConstant> m_fragment_constants;
std::vector<RSXTransformConstant> m_transform_constants; std::vector<RSXTransformConstant> m_transform_constants;
u32 m_shader_ctrl, m_cur_shader_prog_num; u32 m_shader_ctrl, m_cur_fragment_prog_num;
RSXShaderProgram m_shader_progs[m_fragment_count]; RSXFragmentProgram m_fragment_progs[m_fragment_count];
RSXShaderProgram* m_cur_shader_prog; RSXFragmentProgram* m_cur_fragment_prog;
RSXVertexProgram m_vertex_progs[m_vertex_count]; RSXVertexProgram m_vertex_progs[m_vertex_count];
RSXVertexProgram* m_cur_vertex_prog; RSXVertexProgram* m_cur_vertex_prog;
@@ -492,7 +496,7 @@ protected:
m_front_face = 0x0901; // GL_CCW m_front_face = 0x0901; // GL_CCW
m_cull_face = 0x0405; // GL_BACK m_cull_face = 0x0405; // GL_BACK
m_alpha_func = 0x0207; // GL_ALWAYS m_alpha_func = 0x0207; // GL_ALWAYS
m_alpha_ref = 0; m_alpha_ref = 0.0;
m_logic_op = 0x1503; // GL_COPY m_logic_op = 0x1503; // GL_COPY
m_shade_mode = 0x1D01; // GL_SMOOTH m_shade_mode = 0x1D01; // GL_SMOOTH
m_depth_mask = 1; m_depth_mask = 1;
@@ -515,7 +519,10 @@ protected:
m_line_stipple_factor = 1; m_line_stipple_factor = 1;
m_vertex_data_base_offset = 0; m_vertex_data_base_offset = 0;
m_vertex_data_base_index = 0; m_vertex_data_base_index = 0;
for (size_t i = 0; i < 32; i++) {
// Construct Stipple Pattern
for (size_t i = 0; i < 32; i++)
{
m_polygon_stipple_pattern[i] = 0xFFFFFFFF; m_polygon_stipple_pattern[i] = 0xFFFFFFFF;
} }
@@ -618,14 +625,41 @@ protected:
u32 OutOfArgsCount(const uint x, const u32 cmd, const u32 count, const u32 args_addr); u32 OutOfArgsCount(const uint x, const u32 cmd, const u32 count, const u32 args_addr);
void DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const u32 count); void DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const u32 count);
void nativeRescale(float width, float height); void NativeRescale(float width, float height);
virtual void OnInit() = 0; virtual void OnInit() = 0;
virtual void OnInitThread() = 0; virtual void OnInitThread() = 0;
virtual void OnExitThread() = 0; virtual void OnExitThread() = 0;
virtual void OnReset() = 0; virtual void OnReset() = 0;
virtual void ExecCMD() = 0; virtual void ExecCMD() = 0;
virtual void ExecCMD(u32 cmd) = 0; virtual void Enable(u32 cmd, u32 enable) = 0;
virtual void ClearColor(u32 a, u32 r, u32 g, u32 b) = 0;
virtual void ClearStencil(u32 stencil) = 0;
virtual void ClearDepth(u32 depth) = 0;
virtual void ClearSurface(u32 mask) = 0;
virtual void ColorMask(bool a, bool r, bool g, bool b) = 0;
virtual void AlphaFunc(u32 func, float ref) = 0;
virtual void DepthFunc(u32 func) = 0;
virtual void DepthMask(u32 flag) = 0;
virtual void PolygonMode(u32 face, u32 mode) = 0;
virtual void PointSize(float size) = 0;
virtual void LogicOp(u32 opcdoe) = 0;
virtual void LineWidth(float width) = 0;
virtual void LineStipple(u16 factor, u16 pattern) = 0;
virtual void PrimitiveRestartIndex(u32 index) = 0;
virtual void CullFace(u32 mode) = 0;
virtual void FrontFace(u32 mode) = 0;
virtual void Fogi(u32 mode) = 0;
virtual void Fogf(float start, float end) = 0;
virtual void PolygonOffset(float factor, float bias) = 0;
virtual void DepthRangef(float min, float max) = 0;
virtual void BlendEquationSeparate(u16 rgb, u16 a) = 0;
virtual void BlendFuncSeparate(u16 srcRGB, u16 dstRGB, u16 srcAlpha, u16 dstAlpha) = 0;
virtual void BlendColor(u8 r, u8 g, u8 b, u8 a) = 0;
virtual void LightModeli(u32 enable) = 0;
virtual void ShadeModel(u32 mode) = 0;
virtual void DepthBoundsEXT(float min, float max) = 0;
virtual void Scissor(u16 x, u16 y, u16 width, u16 height) = 0;
virtual void Flip() = 0; virtual void Flip() = 0;
void LoadVertexData(u32 first, u32 count) void LoadVertexData(u32 first, u32 count)
+1
View File
@@ -36,6 +36,7 @@ enum CellVideoOutResolutionId
CELL_VIDEO_OUT_RESOLUTION_960x720_3D_FRAME_PACKING = 0x89, CELL_VIDEO_OUT_RESOLUTION_960x720_3D_FRAME_PACKING = 0x89,
CELL_VIDEO_OUT_RESOLUTION_800x720_3D_FRAME_PACKING = 0x8a, CELL_VIDEO_OUT_RESOLUTION_800x720_3D_FRAME_PACKING = 0x8a,
CELL_VIDEO_OUT_RESOLUTION_640x720_3D_FRAME_PACKING = 0x8b, CELL_VIDEO_OUT_RESOLUTION_640x720_3D_FRAME_PACKING = 0x8b,
CELL_VIDEO_OUT_RESOLUTION_720_SIMULVIEW_FRAME_PACKING = 0x91,
}; };
enum CellVideoOutScanMode enum CellVideoOutScanMode
+1
View File
@@ -3783,6 +3783,7 @@ std::string SysCalls::GetHLEFuncName(const u32 fid)
case 0x8bb03ab8: return "sys_game_board_storage_write"; case 0x8bb03ab8: return "sys_game_board_storage_write";
case 0x8c2bb498: return "sys_spinlock_initialize"; case 0x8c2bb498: return "sys_spinlock_initialize";
case 0x96328741: return "_sys_process_at_Exitspawn"; case 0x96328741: return "_sys_process_at_Exitspawn";
case 0x4f7172c9: return "sys_process_is_stack";
case 0x996f7cf8: return "_sys_strncat"; case 0x996f7cf8: return "_sys_strncat";
case 0x99c88692: return "_sys_strcpy"; case 0x99c88692: return "_sys_strcpy";
case 0x9d3c0f81: return "sys_mempool_destroy"; case 0x9d3c0f81: return "sys_mempool_destroy";
+2 -1
View File
@@ -38,6 +38,7 @@ extern void cellRtc_init(Module *pxThis);
extern void cellSail_init(Module *pxThis); extern void cellSail_init(Module *pxThis);
extern void cellSpurs_init(Module *pxThis); extern void cellSpurs_init(Module *pxThis);
extern void cellSpursJq_init(Module *pxThis); extern void cellSpursJq_init(Module *pxThis);
extern void cellSubdisplay_init(Module *pxThis);
extern void cellSync_init(Module *pxThis); extern void cellSync_init(Module *pxThis);
extern void cellSync2_init(Module *pxThis); extern void cellSync2_init(Module *pxThis);
extern void cellSysutil_init(Module *pxThis); extern void cellSysutil_init(Module *pxThis);
@@ -125,7 +126,7 @@ static const g_modules_list[] =
{ 0x0031, "cellAvconfExt", cellAvconfExt_init, nullptr, nullptr }, { 0x0031, "cellAvconfExt", cellAvconfExt_init, nullptr, nullptr },
{ 0x0032, "cellUserInfo", cellUserInfo_init, nullptr, nullptr }, { 0x0032, "cellUserInfo", cellUserInfo_init, nullptr, nullptr },
{ 0x0033, "cellSysutilSavedata", nullptr, nullptr, nullptr }, { 0x0033, "cellSysutilSavedata", nullptr, nullptr, nullptr },
{ 0x0034, "cellSubdisplay", nullptr, nullptr, nullptr }, { 0x0034, "cellSubdisplay", cellSubdisplay_init, nullptr, nullptr },
{ 0x0035, "cellSysutilRec", nullptr, nullptr, nullptr }, { 0x0035, "cellSysutilRec", nullptr, nullptr, nullptr },
{ 0x0036, "cellVideoExport", nullptr, nullptr, nullptr }, { 0x0036, "cellVideoExport", nullptr, nullptr, nullptr },
{ 0x0037, "cellGameExec", nullptr, nullptr, nullptr }, { 0x0037, "cellGameExec", nullptr, nullptr, nullptr },
+1 -1
View File
@@ -188,7 +188,7 @@ void fix_import(Module* module, u32 func, u32 addr)
*ptr++ = ORI(11, 11, func & 0xffff); *ptr++ = ORI(11, 11, func & 0xffff);
*ptr++ = NOP(); *ptr++ = NOP();
++ptr; ++ptr;
*ptr++ = SC(2); *ptr++ = SC(0);
*ptr++ = BLR(); *ptr++ = BLR();
*ptr++ = NOP(); *ptr++ = NOP();
*ptr++ = NOP(); *ptr++ = NOP();
+5 -3
View File
@@ -95,7 +95,8 @@ public:
public: public:
bool CheckID(u32 id) const; bool CheckID(u32 id) const;
template<typename T> bool CheckId(u32 id, T*& data)
template<typename T> bool CheckId(u32 id, std::shared_ptr<T>& data)
{ {
ID* id_data; ID* id_data;
@@ -106,7 +107,7 @@ public:
return true; return true;
} }
template<typename T> bool CheckId(u32 id, T*& data, IDType& type) template<typename T> bool CheckId(u32 id, std::shared_ptr<T>& data, IDType& type)
{ {
ID* id_data; ID* id_data;
@@ -117,10 +118,11 @@ public:
return true; return true;
} }
bool CheckID(u32 id, ID*& _id) const; bool CheckID(u32 id, ID*& _id) const;
template<typename T> template<typename T>
u32 GetNewId(T* data, IDType type = TYPE_OTHER) u32 GetNewId(std::shared_ptr<T>& data, IDType type = TYPE_OTHER)
{ {
return GetIdManager().GetNewID<T>(GetName(), data, type); return GetIdManager().GetNewID<T>(GetName(), data, type);
} }
+206 -114
View File
@@ -19,6 +19,8 @@ extern "C"
Module *cellAdec = nullptr; Module *cellAdec = nullptr;
#define ADEC_ERROR(...) { cellAdec->Error(__VA_ARGS__); Emu.Pause(); return; } // only for decoder thread
AudioDecoder::AudioDecoder(AudioCodecType type, u32 addr, u32 size, vm::ptr<CellAdecCbMsg> func, u32 arg) AudioDecoder::AudioDecoder(AudioCodecType type, u32 addr, u32 size, vm::ptr<CellAdecCbMsg> func, u32 arg)
: type(type) : type(type)
, memAddr(addr) , memAddr(addr)
@@ -31,33 +33,55 @@ AudioDecoder::AudioDecoder(AudioCodecType type, u32 addr, u32 size, vm::ptr<Cell
, is_finished(false) , is_finished(false)
, just_started(false) , just_started(false)
, just_finished(false) , just_finished(false)
, codec(nullptr)
, input_format(nullptr)
, ctx(nullptr) , ctx(nullptr)
, fmt(nullptr) , fmt(nullptr)
{ {
av_register_all(); av_register_all();
avcodec_register_all(); avcodec_register_all();
AVCodec* codec = avcodec_find_decoder(AV_CODEC_ID_ATRAC3P); switch (type)
{
case CELL_ADEC_TYPE_ATRACX:
case CELL_ADEC_TYPE_ATRACX_2CH:
case CELL_ADEC_TYPE_ATRACX_6CH:
case CELL_ADEC_TYPE_ATRACX_8CH:
{
codec = avcodec_find_decoder(AV_CODEC_ID_ATRAC3P);
input_format = av_find_input_format("oma");
break;
}
case CELL_ADEC_TYPE_MP3:
{
codec = avcodec_find_decoder(AV_CODEC_ID_MP3);
input_format = av_find_input_format("mp3");
break;
}
default:
{
ADEC_ERROR("AudioDecoder(): unknown type (0x%x)", type);
}
}
if (!codec) if (!codec)
{ {
cellAdec->Error("AudioDecoder(): avcodec_find_decoder(ATRAC3P) failed"); ADEC_ERROR("AudioDecoder(): avcodec_find_decoder() failed");
Emu.Pause(); }
return; if (!input_format)
{
ADEC_ERROR("AudioDecoder(): av_find_input_format() failed");
} }
fmt = avformat_alloc_context(); fmt = avformat_alloc_context();
if (!fmt) if (!fmt)
{ {
cellAdec->Error("AudioDecoder(): avformat_alloc_context failed"); ADEC_ERROR("AudioDecoder(): avformat_alloc_context() failed");
Emu.Pause();
return;
} }
io_buf = (u8*)av_malloc(4096); io_buf = (u8*)av_malloc(4096);
fmt->pb = avio_alloc_context(io_buf, 256, 0, this, adecRead, NULL, NULL); fmt->pb = avio_alloc_context(io_buf, 256, 0, this, adecRead, NULL, NULL);
if (!fmt->pb) if (!fmt->pb)
{ {
cellAdec->Error("AudioDecoder(): avio_alloc_context failed"); ADEC_ERROR("AudioDecoder(): avio_alloc_context() failed");
Emu.Pause();
return;
} }
} }
@@ -65,7 +89,7 @@ AudioDecoder::~AudioDecoder()
{ {
// TODO: check finalization // TODO: check finalization
AdecFrame af; AdecFrame af;
while (frames.Pop(af, &sq_no_wait)) while (frames.try_pop(af))
{ {
av_frame_unref(af.data); av_frame_unref(af.data);
av_frame_free(&af.data); av_frame_free(&af.data);
@@ -93,11 +117,11 @@ int adecRead(void* opaque, u8* buf, int buf_size)
int res = 0; int res = 0;
next: next:
if (adec.reader.has_ats) if (adecIsAtracX(adec.type) && adec.reader.has_ats)
{ {
u8 code1 = vm::read8(adec.reader.addr + 2); u8 code1 = vm::read8(adec.reader.addr + 2);
u8 code2 = vm::read8(adec.reader.addr + 3); u8 code2 = vm::read8(adec.reader.addr + 3);
adec.channels = (code1 >> 2) & 0x7; adec.ch_cfg = (code1 >> 2) & 0x7;
adec.frame_size = ((((u32)code1 & 0x3) << 8) | (u32)code2) * 8 + 8; adec.frame_size = ((((u32)code1 & 0x3) << 8) | (u32)code2) * 8 + 8;
adec.sample_rate = at3freq[code1 >> 5]; adec.sample_rate = at3freq[code1 >> 5];
@@ -106,9 +130,9 @@ next:
adec.reader.has_ats = false; adec.reader.has_ats = false;
} }
if (!adec.reader.init) if (adecIsAtracX(adec.type) && !adec.reader.init)
{ {
OMAHeader oma(1 /* atrac3p id */, adec.sample_rate, adec.channels, adec.frame_size); OMAHeader oma(1 /* atrac3p id */, adec.sample_rate, adec.ch_cfg, adec.frame_size);
if (buf_size < sizeof(oma)) if (buf_size < sizeof(oma))
{ {
cellAdec->Error("adecRead(): OMAHeader writing failed"); cellAdec->Error("adecRead(): OMAHeader writing failed");
@@ -127,7 +151,7 @@ next:
if (adec.reader.size < (u32)buf_size /*&& !adec.just_started*/) if (adec.reader.size < (u32)buf_size /*&& !adec.just_started*/)
{ {
AdecTask task; AdecTask task;
if (!adec.job.Peek(task, &adec.is_closed)) if (!adec.job.peek(task, 0, &adec.is_closed))
{ {
if (Emu.IsStopped()) cellAdec->Warning("adecRawRead() aborted"); if (Emu.IsStopped()) cellAdec->Warning("adecRawRead() aborted");
return 0; return 0;
@@ -152,7 +176,7 @@ next:
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.addr = adec.task.au.addr;
adec.reader.size = adec.task.au.size; adec.reader.size = adec.task.au.size;
@@ -190,11 +214,12 @@ next:
} }
} }
u32 adecOpen(AudioDecoder* data) u32 adecOpen(AudioDecoder* adec_ptr)
{ {
AudioDecoder& adec = *data; std::shared_ptr<AudioDecoder> sptr(adec_ptr);
AudioDecoder& adec = *adec_ptr;
u32 adec_id = cellAdec->GetNewId(data); u32 adec_id = cellAdec->GetNewId(sptr);
adec.id = adec_id; adec.id = adec_id;
@@ -207,8 +232,9 @@ u32 adecOpen(AudioDecoder* data)
adec.adecCb->InitRegs(); adec.adecCb->InitRegs();
adec.adecCb->DoRun(); adec.adecCb->DoRun();
thread t("Audio Decoder[" + std::to_string(adec_id) + "] Thread", [&]() thread t("Audio Decoder[" + std::to_string(adec_id) + "] Thread", [adec_ptr, sptr]()
{ {
AudioDecoder& adec = *adec_ptr;
cellAdec->Notice("Audio Decoder thread started"); cellAdec->Notice("Audio Decoder thread started");
AdecTask& task = adec.task; AdecTask& task = adec.task;
@@ -220,13 +246,7 @@ u32 adecOpen(AudioDecoder* data)
break; break;
} }
//if (!adec.job.GetCountUnsafe() && adec.is_running) if (!adec.job.pop(task, &adec.is_closed))
//{
// std::this_thread::sleep_for(std::chrono::milliseconds(1));
// continue;
//}
if (!adec.job.Pop(task, &adec.is_closed))
{ {
break; break;
} }
@@ -244,12 +264,16 @@ u32 adecOpen(AudioDecoder* data)
adec.reader.has_ats = false; adec.reader.has_ats = false;
adec.just_started = true; adec.just_started = true;
adec.channels = task.at3p.channels; if (adecIsAtracX(adec.type))
{
adec.ch_cfg = task.at3p.channel_config;
adec.ch_out = task.at3p.channels;
adec.frame_size = task.at3p.frame_size; adec.frame_size = task.at3p.frame_size;
adec.sample_rate = task.at3p.sample_rate; adec.sample_rate = task.at3p.sample_rate;
adec.use_ats_headers = task.at3p.ats_header == 1; adec.use_ats_headers = task.at3p.ats_header == 1;
} }
break; break;
}
case adecEndSeq: case adecEndSeq:
{ {
@@ -258,8 +282,8 @@ u32 adecOpen(AudioDecoder* data)
adec.cbFunc.call(*adec.adecCb, adec.id, CELL_ADEC_MSG_TYPE_SEQDONE, CELL_OK, adec.cbArg); adec.cbFunc.call(*adec.adecCb, adec.id, CELL_ADEC_MSG_TYPE_SEQDONE, CELL_OK, adec.cbArg);
adec.just_finished = true; adec.just_finished = true;
}
break; break;
}
case adecDecodeAu: case adecDecodeAu:
{ {
@@ -273,7 +297,8 @@ u32 adecOpen(AudioDecoder* data)
if (adec.just_started) if (adec.just_started)
{ {
adec.first_pts = task.au.pts; adec.first_pts = task.au.pts;
adec.last_pts = task.au.pts - 0x10000; // hack? adec.last_pts = task.au.pts;
if (adecIsAtracX(adec.type)) adec.last_pts -= 0x10000; // hack
} }
struct AVPacketHolder : AVPacket struct AVPacketHolder : AVPacket
@@ -313,39 +338,19 @@ u32 adecOpen(AudioDecoder* data)
{ {
AVDictionary* opts = nullptr; AVDictionary* opts = nullptr;
av_dict_set(&opts, "probesize", "96", 0); av_dict_set(&opts, "probesize", "96", 0);
err = avformat_open_input(&adec.fmt, NULL, av_find_input_format("oma"), &opts); err = avformat_open_input(&adec.fmt, NULL, adec.input_format, &opts);
if (err || opts) if (err || opts)
{ {
cellAdec->Error("adecDecodeAu: avformat_open_input() failed (err=0x%x, opts=%d)", err, opts ? 1 : 0); ADEC_ERROR("adecDecodeAu: avformat_open_input() failed (err=0x%x, opts=%d)", err, opts ? 1 : 0);
Emu.Pause();
break;
}
AVCodec* codec = avcodec_find_decoder(AV_CODEC_ID_ATRAC3P); // ???
if (!codec)
{
cellAdec->Error("adecDecodeAu: avcodec_find_decoder() failed");
Emu.Pause();
break;
} }
//err = avformat_find_stream_info(adec.fmt, NULL); //err = avformat_find_stream_info(adec.fmt, NULL);
//if (err) //if (err || !adec.fmt->nb_streams)
//{ //{
// cellAdec->Error("adecDecodeAu: avformat_find_stream_info() failed"); // ADEC_ERROR("adecDecodeAu: avformat_find_stream_info() failed (err=0x%x, nb_streams=%d)", err, adec.fmt->nb_streams);
// Emu.Pause();
// break;
//} //}
//if (!adec.fmt->nb_streams) if (!avformat_new_stream(adec.fmt, adec.codec))
//{
// cellAdec->Error("adecDecodeAu: no stream found");
// Emu.Pause();
// break;
//}
if (!avformat_new_stream(adec.fmt, codec))
{ {
cellAdec->Error("adecDecodeAu: avformat_new_stream() failed"); ADEC_ERROR("adecDecodeAu: avformat_new_stream() failed");
Emu.Pause();
break;
} }
adec.ctx = adec.fmt->streams[0]->codec; // TODO: check data adec.ctx = adec.fmt->streams[0]->codec; // TODO: check data
@@ -354,13 +359,11 @@ u32 adecOpen(AudioDecoder* data)
{ {
std::lock_guard<std::mutex> lock(g_mutex_avcodec_open2); std::lock_guard<std::mutex> lock(g_mutex_avcodec_open2);
// not multithread-safe (???) // not multithread-safe (???)
err = avcodec_open2(adec.ctx, codec, &opts); err = avcodec_open2(adec.ctx, adec.codec, &opts);
} }
if (err || opts) if (err || opts)
{ {
cellAdec->Error("adecDecodeAu: avcodec_open2() failed"); ADEC_ERROR("adecDecodeAu: avcodec_open2() failed (err=0x%x, opts=%d)", err, opts ? 1 : 0);
Emu.Pause();
break;
} }
adec.just_started = false; adec.just_started = false;
} }
@@ -404,9 +407,7 @@ u32 adecOpen(AudioDecoder* data)
if (!frame.data) if (!frame.data)
{ {
cellAdec->Error("adecDecodeAu: av_frame_alloc() failed"); ADEC_ERROR("adecDecodeAu: av_frame_alloc() failed");
Emu.Pause();
break;
} }
int got_frame = 0; int got_frame = 0;
@@ -415,7 +416,7 @@ u32 adecOpen(AudioDecoder* data)
if (decode <= 0) if (decode <= 0)
{ {
if (!last_frame && decode < 0) if (decode < 0)
{ {
cellAdec->Error("adecDecodeAu: AU decoding error(0x%x)", decode); cellAdec->Error("adecDecodeAu: AU decoding error(0x%x)", decode);
} }
@@ -424,36 +425,34 @@ u32 adecOpen(AudioDecoder* data)
if (got_frame) if (got_frame)
{ {
u64 ts = av_frame_get_best_effort_timestamp(frame.data); //u64 ts = av_frame_get_best_effort_timestamp(frame.data);
if (ts != AV_NOPTS_VALUE) //if (ts != AV_NOPTS_VALUE)
{ //{
frame.pts = ts/* - adec.first_pts*/; // frame.pts = ts/* - adec.first_pts*/;
adec.last_pts = frame.pts; // adec.last_pts = frame.pts;
} //}
else
{
adec.last_pts += ((u64)frame.data->nb_samples) * 90000 / frame.data->sample_rate; adec.last_pts += ((u64)frame.data->nb_samples) * 90000 / frame.data->sample_rate;
frame.pts = adec.last_pts; frame.pts = adec.last_pts;
s32 nbps = av_get_bytes_per_sample((AVSampleFormat)frame.data->format);
switch (frame.data->format)
{
case AV_SAMPLE_FMT_FLTP: break;
case AV_SAMPLE_FMT_S16P: break;
default:
{
ADEC_ERROR("adecDecodeAu: unsupported frame format(%d)", frame.data->format);
}
} }
//frame.pts = adec.last_pts;
//adec.last_pts += ((u64)frame.data->nb_samples) * 90000 / 48000; // ???
frame.auAddr = task.au.addr; frame.auAddr = task.au.addr;
frame.auSize = task.au.size; frame.auSize = task.au.size;
frame.userdata = task.au.userdata; frame.userdata = task.au.userdata;
frame.size = frame.data->nb_samples * frame.data->channels * sizeof(float); frame.size = frame.data->nb_samples * frame.data->channels * nbps;
if (frame.data->format != AV_SAMPLE_FMT_FLTP)
{
cellAdec->Error("adecDecodeaAu: unsupported frame format(%d)", frame.data->format);
Emu.Pause();
break;
}
//LOG_NOTICE(HLE, "got audio frame (pts=0x%llx, nb_samples=%d, ch=%d, sample_rate=%d, nbps=%d)", //LOG_NOTICE(HLE, "got audio frame (pts=0x%llx, nb_samples=%d, ch=%d, sample_rate=%d, nbps=%d)",
//frame.pts, frame.data->nb_samples, frame.data->channels, frame.data->sample_rate, //frame.pts, frame.data->nb_samples, frame.data->channels, frame.data->sample_rate, nbps);
//av_get_bytes_per_sample((AVSampleFormat)frame.data->format));
if (adec.frames.Push(frame, &adec.is_closed)) if (adec.frames.push(frame, &adec.is_closed))
{ {
frame.data = nullptr; // to prevent destruction frame.data = nullptr; // to prevent destruction
adec.cbFunc.call(*adec.adecCb, adec.id, CELL_ADEC_MSG_TYPE_PCMOUT, CELL_OK, adec.cbArg); adec.cbFunc.call(*adec.adecCb, adec.id, CELL_ADEC_MSG_TYPE_PCMOUT, CELL_OK, adec.cbArg);
@@ -462,16 +461,17 @@ u32 adecOpen(AudioDecoder* data)
} }
adec.cbFunc.call(*adec.adecCb, adec.id, CELL_ADEC_MSG_TYPE_AUDONE, task.au.auInfo_addr, adec.cbArg); adec.cbFunc.call(*adec.adecCb, adec.id, CELL_ADEC_MSG_TYPE_AUDONE, task.au.auInfo_addr, adec.cbArg);
}
break; break;
}
case adecClose: break; case adecClose:
{
break;
}
default: default:
{ {
cellAdec->Error("Audio Decoder thread error: unknown task(%d)", task.type); ADEC_ERROR("Audio Decoder thread error: unknown task(%d)", task.type);
Emu.Pause();
return;
} }
} }
} }
@@ -490,23 +490,25 @@ bool adecCheckType(AudioCodecType type)
{ {
switch (type) switch (type)
{ {
case CELL_ADEC_TYPE_ATRACX: cellAdec->Notice("adecCheckType: ATRAC3plus"); break; case CELL_ADEC_TYPE_ATRACX: cellAdec->Notice("adecCheckType(): ATRAC3plus"); break;
case CELL_ADEC_TYPE_ATRACX_2CH: cellAdec->Notice("adecCheckType: ATRAC3plus 2ch"); break; case CELL_ADEC_TYPE_ATRACX_2CH: cellAdec->Notice("adecCheckType(): ATRAC3plus 2ch"); break;
case CELL_ADEC_TYPE_ATRACX_6CH: cellAdec->Notice("adecCheckType(): ATRAC3plus 6ch"); break;
case CELL_ADEC_TYPE_ATRACX_8CH: cellAdec->Notice("adecCheckType(): ATRAC3plus 8ch"); break;
case CELL_ADEC_TYPE_MP3: cellAdec->Notice("adecCheckType(): MP3"); break;
case CELL_ADEC_TYPE_ATRACX_6CH:
case CELL_ADEC_TYPE_ATRACX_8CH:
case CELL_ADEC_TYPE_LPCM_PAMF: case CELL_ADEC_TYPE_LPCM_PAMF:
case CELL_ADEC_TYPE_AC3: case CELL_ADEC_TYPE_AC3:
case CELL_ADEC_TYPE_MP3:
case CELL_ADEC_TYPE_ATRAC3: case CELL_ADEC_TYPE_ATRAC3:
case CELL_ADEC_TYPE_MPEG_L2: case CELL_ADEC_TYPE_MPEG_L2:
case CELL_ADEC_TYPE_CELP: case CELL_ADEC_TYPE_CELP:
case CELL_ADEC_TYPE_M4AAC: case CELL_ADEC_TYPE_M4AAC:
case CELL_ADEC_TYPE_CELP8: case CELL_ADEC_TYPE_CELP8:
{
cellAdec->Todo("Unimplemented audio codec type (%d)", type); cellAdec->Todo("Unimplemented audio codec type (%d)", type);
Emu.Pause();
break; break;
default: }
return false; default: return false;
} }
return true; return true;
@@ -554,14 +556,14 @@ int cellAdecClose(u32 handle)
{ {
cellAdec->Warning("cellAdecClose(handle=%d)", handle); cellAdec->Warning("cellAdecClose(handle=%d)", handle);
AudioDecoder* adec; std::shared_ptr<AudioDecoder> adec;
if (!Emu.GetIdManager().GetIDData(handle, adec)) if (!Emu.GetIdManager().GetIDData(handle, adec))
{ {
return CELL_ADEC_ERROR_ARG; return CELL_ADEC_ERROR_ARG;
} }
adec->is_closed = true; adec->is_closed = true;
adec->job.Push(AdecTask(adecClose), &sq_no_wait); adec->job.try_push(AdecTask(adecClose));
while (!adec->is_finished) while (!adec->is_finished)
{ {
@@ -570,7 +572,7 @@ int cellAdecClose(u32 handle)
cellAdec->Warning("cellAdecClose(%d) aborted", handle); cellAdec->Warning("cellAdecClose(%d) aborted", handle);
break; break;
} }
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
} }
if (adec->adecCb) Emu.GetCPU().RemoveThread(adec->adecCb->GetId()); if (adec->adecCb) Emu.GetCPU().RemoveThread(adec->adecCb->GetId());
@@ -582,7 +584,7 @@ int cellAdecStartSeq(u32 handle, u32 param_addr)
{ {
cellAdec->Warning("cellAdecStartSeq(handle=%d, param_addr=0x%x)", handle, param_addr); cellAdec->Warning("cellAdecStartSeq(handle=%d, param_addr=0x%x)", handle, param_addr);
AudioDecoder* adec; std::shared_ptr<AudioDecoder> adec;
if (!Emu.GetIdManager().GetIDData(handle, adec)) if (!Emu.GetIdManager().GetIDData(handle, adec))
{ {
return CELL_ADEC_ERROR_ARG; return CELL_ADEC_ERROR_ARG;
@@ -592,7 +594,10 @@ int cellAdecStartSeq(u32 handle, u32 param_addr)
switch (adec->type) switch (adec->type)
{ {
case CELL_ADEC_TYPE_ATRACX:
case CELL_ADEC_TYPE_ATRACX_2CH: case CELL_ADEC_TYPE_ATRACX_2CH:
case CELL_ADEC_TYPE_ATRACX_6CH:
case CELL_ADEC_TYPE_ATRACX_8CH:
{ {
auto param = vm::ptr<const CellAdecParamAtracX>::make(param_addr); auto param = vm::ptr<const CellAdecParamAtracX>::make(param_addr);
@@ -608,6 +613,13 @@ int cellAdecStartSeq(u32 handle, u32 param_addr)
task.at3p.sample_rate, task.at3p.channel_config, task.at3p.channels, task.at3p.frame_size, (u32&)task.at3p.extra_config, task.at3p.output, task.at3p.downmix, task.at3p.ats_header); task.at3p.sample_rate, task.at3p.channel_config, task.at3p.channels, task.at3p.frame_size, (u32&)task.at3p.extra_config, task.at3p.output, task.at3p.downmix, task.at3p.ats_header);
break; break;
} }
case CELL_ADEC_TYPE_MP3:
{
auto param = vm::ptr<const CellAdecParamMP3>::make(param_addr);
cellAdec->Todo("*** CellAdecParamMP3: bw_pcm=%d", param->bw_pcm.ToLE());
break;
}
default: default:
{ {
cellAdec->Todo("cellAdecStartSeq(): Unimplemented audio codec type(%d)", adec->type); cellAdec->Todo("cellAdecStartSeq(): Unimplemented audio codec type(%d)", adec->type);
@@ -616,7 +628,7 @@ int cellAdecStartSeq(u32 handle, u32 param_addr)
} }
} }
adec->job.Push(task, &adec->is_closed); adec->job.push(task, &adec->is_closed);
return CELL_OK; return CELL_OK;
} }
@@ -624,13 +636,13 @@ int cellAdecEndSeq(u32 handle)
{ {
cellAdec->Warning("cellAdecEndSeq(handle=%d)", handle); cellAdec->Warning("cellAdecEndSeq(handle=%d)", handle);
AudioDecoder* adec; std::shared_ptr<AudioDecoder> adec;
if (!Emu.GetIdManager().GetIDData(handle, adec)) if (!Emu.GetIdManager().GetIDData(handle, adec))
{ {
return CELL_ADEC_ERROR_ARG; return CELL_ADEC_ERROR_ARG;
} }
adec->job.Push(AdecTask(adecEndSeq), &adec->is_closed); adec->job.push(AdecTask(adecEndSeq), &adec->is_closed);
return CELL_OK; return CELL_OK;
} }
@@ -638,7 +650,7 @@ int cellAdecDecodeAu(u32 handle, vm::ptr<CellAdecAuInfo> auInfo)
{ {
cellAdec->Log("cellAdecDecodeAu(handle=%d, auInfo_addr=0x%x)", handle, auInfo.addr()); cellAdec->Log("cellAdecDecodeAu(handle=%d, auInfo_addr=0x%x)", handle, auInfo.addr());
AudioDecoder* adec; std::shared_ptr<AudioDecoder> adec;
if (!Emu.GetIdManager().GetIDData(handle, adec)) if (!Emu.GetIdManager().GetIDData(handle, adec))
{ {
return CELL_ADEC_ERROR_ARG; return CELL_ADEC_ERROR_ARG;
@@ -652,7 +664,7 @@ int cellAdecDecodeAu(u32 handle, vm::ptr<CellAdecAuInfo> auInfo)
task.au.userdata = auInfo->userData; task.au.userdata = auInfo->userData;
//cellAdec->Notice("cellAdecDecodeAu(): addr=0x%x, size=0x%x, pts=0x%llx", task.au.addr, task.au.size, task.au.pts); //cellAdec->Notice("cellAdecDecodeAu(): addr=0x%x, size=0x%x, pts=0x%llx", task.au.addr, task.au.size, task.au.pts);
adec->job.Push(task, &adec->is_closed); adec->job.push(task, &adec->is_closed);
return CELL_OK; return CELL_OK;
} }
@@ -660,14 +672,14 @@ int cellAdecGetPcm(u32 handle, vm::ptr<float> outBuffer)
{ {
cellAdec->Log("cellAdecGetPcm(handle=%d, outBuffer_addr=0x%x)", handle, outBuffer.addr()); cellAdec->Log("cellAdecGetPcm(handle=%d, outBuffer_addr=0x%x)", handle, outBuffer.addr());
AudioDecoder* adec; std::shared_ptr<AudioDecoder> adec;
if (!Emu.GetIdManager().GetIDData(handle, adec)) if (!Emu.GetIdManager().GetIDData(handle, adec))
{ {
return CELL_ADEC_ERROR_ARG; return CELL_ADEC_ERROR_ARG;
} }
AdecFrame af; AdecFrame af;
if (!adec->frames.Pop(af, &sq_no_wait)) if (!adec->frames.try_pop(af))
{ {
//std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack //std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
return CELL_ADEC_ERROR_EMPTY; return CELL_ADEC_ERROR_EMPTY;
@@ -678,7 +690,7 @@ int cellAdecGetPcm(u32 handle, vm::ptr<float> outBuffer)
if (outBuffer) if (outBuffer)
{ {
// reverse byte order: // reverse byte order:
if (frame->channels == 1) if (frame->format == AV_SAMPLE_FMT_FLTP && frame->channels == 1)
{ {
float* in_f = (float*)frame->extended_data[0]; float* in_f = (float*)frame->extended_data[0];
for (u32 i = 0; i < af.size / 4; i++) for (u32 i = 0; i < af.size / 4; i++)
@@ -686,7 +698,7 @@ int cellAdecGetPcm(u32 handle, vm::ptr<float> outBuffer)
outBuffer[i] = in_f[i]; outBuffer[i] = in_f[i];
} }
} }
else if (frame->channels == 2) else if (frame->format == AV_SAMPLE_FMT_FLTP && frame->channels == 2)
{ {
float* in_f[2]; float* in_f[2];
in_f[0] = (float*)frame->extended_data[0]; in_f[0] = (float*)frame->extended_data[0];
@@ -697,9 +709,70 @@ int cellAdecGetPcm(u32 handle, vm::ptr<float> outBuffer)
outBuffer[i * 2 + 1] = in_f[1][i]; outBuffer[i * 2 + 1] = in_f[1][i];
} }
} }
else if (frame->format == AV_SAMPLE_FMT_FLTP && frame->channels == 6)
{
float* in_f[6];
in_f[0] = (float*)frame->extended_data[0];
in_f[1] = (float*)frame->extended_data[1];
in_f[2] = (float*)frame->extended_data[2];
in_f[3] = (float*)frame->extended_data[3];
in_f[4] = (float*)frame->extended_data[4];
in_f[5] = (float*)frame->extended_data[5];
for (u32 i = 0; i < af.size / 24; i++)
{
outBuffer[i * 6 + 0] = in_f[0][i];
outBuffer[i * 6 + 1] = in_f[1][i];
outBuffer[i * 6 + 2] = in_f[2][i];
outBuffer[i * 6 + 3] = in_f[3][i];
outBuffer[i * 6 + 4] = in_f[4][i];
outBuffer[i * 6 + 5] = in_f[5][i];
}
}
else if (frame->format == AV_SAMPLE_FMT_FLTP && frame->channels == 8)
{
float* in_f[8];
in_f[0] = (float*)frame->extended_data[0];
in_f[1] = (float*)frame->extended_data[1];
in_f[2] = (float*)frame->extended_data[2];
in_f[3] = (float*)frame->extended_data[3];
in_f[4] = (float*)frame->extended_data[4];
in_f[5] = (float*)frame->extended_data[5];
in_f[6] = (float*)frame->extended_data[6];
in_f[7] = (float*)frame->extended_data[7];
for (u32 i = 0; i < af.size / 24; i++)
{
outBuffer[i * 8 + 0] = in_f[0][i];
outBuffer[i * 8 + 1] = in_f[1][i];
outBuffer[i * 8 + 2] = in_f[2][i];
outBuffer[i * 8 + 3] = in_f[3][i];
outBuffer[i * 8 + 4] = in_f[4][i];
outBuffer[i * 8 + 5] = in_f[5][i];
outBuffer[i * 8 + 6] = in_f[6][i];
outBuffer[i * 8 + 7] = in_f[7][i];
}
}
else if (frame->format == AV_SAMPLE_FMT_S16P && frame->channels == 1)
{
s16* in_i = (s16*)frame->extended_data[0];
for (u32 i = 0; i < af.size / 2; i++)
{
outBuffer[i] = (float)in_i[i] / 0x8000;
}
}
else if (frame->format == AV_SAMPLE_FMT_S16P && frame->channels == 2)
{
s16* in_i[2];
in_i[0] = (s16*)frame->extended_data[0];
in_i[1] = (s16*)frame->extended_data[1];
for (u32 i = 0; i < af.size / 4; i++)
{
outBuffer[i * 2 + 0] = (float)in_i[0][i] / 0x8000;
outBuffer[i * 2 + 1] = (float)in_i[1][i] / 0x8000;
}
}
else else
{ {
cellAdec->Error("cellAdecGetPcm(): unsupported channel count (%d)", frame->channels); cellAdec->Error("cellAdecGetPcm(): unsupported frame format (channels=%d, format=%d)", frame->channels, frame->format);
Emu.Pause(); Emu.Pause();
} }
} }
@@ -713,14 +786,14 @@ int cellAdecGetPcmItem(u32 handle, vm::ptr<u32> pcmItem_ptr)
{ {
cellAdec->Log("cellAdecGetPcmItem(handle=%d, pcmItem_ptr_addr=0x%x)", handle, pcmItem_ptr.addr()); cellAdec->Log("cellAdecGetPcmItem(handle=%d, pcmItem_ptr_addr=0x%x)", handle, pcmItem_ptr.addr());
AudioDecoder* adec; std::shared_ptr<AudioDecoder> adec;
if (!Emu.GetIdManager().GetIDData(handle, adec)) if (!Emu.GetIdManager().GetIDData(handle, adec))
{ {
return CELL_ADEC_ERROR_ARG; return CELL_ADEC_ERROR_ARG;
} }
AdecFrame af; AdecFrame af;
if (!adec->frames.Peek(af, &sq_no_wait)) if (!adec->frames.try_peek(af))
{ {
//std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack //std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
return CELL_ADEC_ERROR_EMPTY; return CELL_ADEC_ERROR_EMPTY;
@@ -747,7 +820,10 @@ int cellAdecGetPcmItem(u32 handle, vm::ptr<u32> pcmItem_ptr)
pcm->auInfo.startAddr = af.auAddr; pcm->auInfo.startAddr = af.auAddr;
pcm->auInfo.userData = af.userdata; pcm->auInfo.userData = af.userdata;
if (adecIsAtracX(adec->type))
{
auto atx = vm::ptr<CellAdecAtracXInfo>::make(pcm.addr() + sizeof(CellAdecPcmItem)); auto atx = vm::ptr<CellAdecAtracXInfo>::make(pcm.addr() + sizeof(CellAdecPcmItem));
atx->samplingFreq = frame->sample_rate; atx->samplingFreq = frame->sample_rate;
atx->nbytes = frame->nb_samples * sizeof(float); atx->nbytes = frame->nb_samples * sizeof(float);
if (frame->channels == 1) if (frame->channels == 1)
@@ -758,11 +834,27 @@ int cellAdecGetPcmItem(u32 handle, vm::ptr<u32> pcmItem_ptr)
{ {
atx->channelConfigIndex = 2; atx->channelConfigIndex = 2;
} }
else if (frame->channels == 6)
{
atx->channelConfigIndex = 6;
}
else if (frame->channels == 8)
{
atx->channelConfigIndex = 7;
}
else else
{ {
cellAdec->Error("cellAdecGetPcmItem(): unsupported channel count (%d)", frame->channels); cellAdec->Error("cellAdecGetPcmItem(): unsupported channel count (%d)", frame->channels);
Emu.Pause(); Emu.Pause();
} }
}
else if (adec->type == CELL_ADEC_TYPE_MP3)
{
auto mp3 = vm::ptr<CellAdecMP3Info>::make(pcm.addr() + sizeof(CellAdecPcmItem));
// TODO
memset(mp3.get_ptr(), 0, sizeof(CellAdecMP3Info));
}
*pcmItem_ptr = pcm.addr(); *pcmItem_ptr = pcm.addr();
return CELL_OK; return CELL_OK;
+14 -5
View File
@@ -1,7 +1,5 @@
#pragma once #pragma once
#include "Utilities/SQueue.h"
// Error Codes // Error Codes
enum enum
{ {
@@ -284,6 +282,14 @@ enum AudioCodecType
CELL_ADEC_TYPE_RESERVED25, CELL_ADEC_TYPE_RESERVED25,
}; };
static bool adecIsAtracX(const AudioCodecType type)
{
return type == CELL_ADEC_TYPE_ATRACX
|| type == CELL_ADEC_TYPE_ATRACX_2CH
|| type == CELL_ADEC_TYPE_ATRACX_6CH
|| type == CELL_ADEC_TYPE_ATRACX_8CH;
}
// Output Channel Number // Output Channel Number
enum CellAdecChannel enum CellAdecChannel
{ {
@@ -1093,13 +1099,15 @@ static_assert(sizeof(OMAHeader) == 96, "Wrong OMAHeader size");
class AudioDecoder class AudioDecoder
{ {
public: public:
SQueue<AdecTask> job; squeue_t<AdecTask> job;
u32 id; u32 id;
volatile bool is_closed; volatile bool is_closed;
volatile bool is_finished; volatile bool is_finished;
bool just_started; bool just_started;
bool just_finished; bool just_finished;
AVCodec* codec;
AVInputFormat* input_format;
AVCodecContext* ctx; AVCodecContext* ctx;
AVFormatContext* fmt; AVFormatContext* fmt;
u8* io_buf; u8* io_buf;
@@ -1118,7 +1126,7 @@ public:
} reader; } reader;
SQueue<AdecFrame> frames; squeue_t<AdecFrame> frames;
const AudioCodecType type; const AudioCodecType type;
const u32 memAddr; const u32 memAddr;
@@ -1130,7 +1138,8 @@ public:
AdecTask task; AdecTask task;
u64 last_pts, first_pts; u64 last_pts, first_pts;
u32 channels; u32 ch_out;
u32 ch_cfg;
u32 frame_size; u32 frame_size;
u32 sample_rate; u32 sample_rate;
bool use_ats_headers; bool use_ats_headers;
+146 -27
View File
@@ -2,11 +2,13 @@
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/SysCalls/Modules.h" #include "Emu/SysCalls/Modules.h"
#include "Emu/Memory/atomic_type.h"
#include "rpcs3/Ini.h" #include "rpcs3/Ini.h"
#include "Utilities/SQueue.h" #include "Emu/SysCalls/lv2/sleep_queue_type.h"
#include "Emu/Event.h"
#include "Emu/SysCalls/lv2/sys_time.h" #include "Emu/SysCalls/lv2/sys_time.h"
#include "Emu/SysCalls/lv2/sys_event.h"
#include "Emu/Event.h"
#include "Emu/Audio/AudioManager.h" #include "Emu/Audio/AudioManager.h"
#include "Emu/Audio/AudioDumper.h" #include "Emu/Audio/AudioDumper.h"
#include "Emu/Audio/cellAudio.h" #include "Emu/Audio/cellAudio.h"
@@ -74,11 +76,8 @@ int cellAudioInit()
oal_buffer_float[i] = std::unique_ptr<float[]>(new float[oal_buffer_size] {} ); oal_buffer_float[i] = std::unique_ptr<float[]>(new float[oal_buffer_size] {} );
} }
SQueue<s16*, 31> queue; squeue_t<s16*, 31> queue;
queue.Clear(); squeue_t<float*, 31> queue_float;
SQueue<float*, 31> queue_float;
queue_float.Clear();
std::vector<u64> keys; std::vector<u64> keys;
@@ -105,9 +104,9 @@ int cellAudioInit()
float* oal_buffer_float = nullptr; float* oal_buffer_float = nullptr;
if (g_is_u16) if (g_is_u16)
queue.Pop(oal_buffer, nullptr); queue.pop(oal_buffer);
else else
queue_float.Pop(oal_buffer_float, nullptr); queue_float.pop(oal_buffer_float);
if (g_is_u16) if (g_is_u16)
{ {
@@ -370,9 +369,9 @@ int cellAudioInit()
if(m_audio_out) if(m_audio_out)
{ {
if (g_is_u16) if (g_is_u16)
queue.Push(&oal_buffer[oal_pos][0], nullptr); queue.push(&oal_buffer[oal_pos][0]);
queue_float.Push(&oal_buffer_float[oal_pos][0], nullptr); queue_float.push(&oal_buffer_float[oal_pos][0]);
} }
oal_buffer_offset = 0; oal_buffer_offset = 0;
@@ -438,8 +437,8 @@ int cellAudioInit()
} }
cellAudio->Notice("Audio thread ended"); cellAudio->Notice("Audio thread ended");
abort: abort:
queue.Push(nullptr, nullptr); queue.push(nullptr);
queue_float.Push(nullptr, nullptr); queue_float.push(nullptr);
if(do_dump) if(do_dump)
m_dump.Finalize(); m_dump.Finalize();
@@ -457,7 +456,7 @@ abort:
while (!internal_finished) while (!internal_finished)
{ {
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
} }
m_config.m_is_audio_finalized = true; m_config.m_is_audio_finalized = true;
@@ -471,7 +470,7 @@ abort:
cellAudio->Warning("cellAudioInit() aborted"); cellAudio->Warning("cellAudioInit() aborted");
return CELL_OK; return CELL_OK;
} }
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
} }
return CELL_OK; return CELL_OK;
@@ -490,7 +489,7 @@ int cellAudioQuit()
while (!m_config.m_is_audio_finalized) while (!m_config.m_is_audio_finalized)
{ {
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
if (Emu.IsStopped()) if (Emu.IsStopped())
{ {
cellAudio->Warning("cellAudioQuit(): aborted"); cellAudio->Warning("cellAudioQuit(): aborted");
@@ -527,6 +526,9 @@ int cellAudioPortOpen(vm::ptr<CellAudioPortParam> audioParam, vm::ptr<u32> portN
port.channel = (u8)audioParam->nChannel; port.channel = (u8)audioParam->nChannel;
port.block = (u8)audioParam->nBlock; port.block = (u8)audioParam->nBlock;
port.attr = audioParam->attr; port.attr = audioParam->attr;
port.addr = m_config.m_buffer + (128 * 1024 * i);
port.read_index_addr = m_config.m_indexes + (sizeof(u64) * i);
port.size = port.channel * port.block * 256 * sizeof(float);
if (port.attr & CELL_AUDIO_PORTATTR_INITLEVEL) if (port.attr & CELL_AUDIO_PORTATTR_INITLEVEL)
{ {
port.level = audioParam->level; port.level = audioParam->level;
@@ -578,9 +580,9 @@ int cellAudioGetPortConfig(u32 portNum, vm::ptr<CellAudioPortConfig> portConfig)
portConfig->nChannel = port.channel; portConfig->nChannel = port.channel;
portConfig->nBlock = port.block; portConfig->nBlock = port.block;
portConfig->portSize = port.channel * port.block * 256 * sizeof(float); portConfig->portSize = port.size;
portConfig->portAddr = m_config.m_buffer + (128 * 1024 * portNum); // 0x20020000 portConfig->portAddr = port.addr; // 0x20020000
portConfig->readIndexAddr = m_config.m_indexes + (sizeof(u64) * portNum); // 0x20010010 on ps3 portConfig->readIndexAddr = port.read_index_addr; // 0x20010010 on ps3
cellAudio->Log("*** port config: nChannel=%d, nBlock=%d, portSize=0x%x, portAddr=0x%x, readIndexAddr=0x%x", cellAudio->Log("*** port config: nChannel=%d, nBlock=%d, portSize=0x%x, portAddr=0x%x, readIndexAddr=0x%x",
(u32)portConfig->nChannel, (u32)portConfig->nBlock, (u32)portConfig->portSize, (u32)portConfig->portAddr, (u32)portConfig->readIndexAddr); (u32)portConfig->nChannel, (u32)portConfig->nBlock, (u32)portConfig->portSize, (u32)portConfig->portAddr, (u32)portConfig->readIndexAddr);
@@ -731,6 +733,28 @@ int cellAudioGetPortBlockTag(u32 portNum, u64 blockNo, vm::ptr<u64> tag)
int cellAudioSetPortLevel(u32 portNum, float level) int cellAudioSetPortLevel(u32 portNum, float level)
{ {
cellAudio->Todo("cellAudioSetPortLevel(portNum=0x%x, level=%f)", portNum, level); cellAudio->Todo("cellAudioSetPortLevel(portNum=0x%x, level=%f)", portNum, level);
AudioPortConfig& port = m_config.m_ports[portNum];
if (portNum >= m_config.AUDIO_PORT_COUNT)
{
return CELL_AUDIO_ERROR_PARAM;
}
if (!port.m_is_audio_port_opened)
{
return CELL_AUDIO_ERROR_PORT_NOT_OPEN;
}
if (!port.m_is_audio_port_started)
{
return CELL_AUDIO_ERROR_PORT_NOT_RUN;
}
std::lock_guard<std::mutex> lock(audioMutex);
port.level = level; // TODO
return CELL_OK; return CELL_OK;
} }
@@ -749,11 +773,10 @@ int cellAudioCreateNotifyEventQueue(vm::ptr<u32> id, vm::ptr<u64> key)
} }
event_key = (event_key << 48) | 0x80004d494f323221; // left part: 0x8000, 0x8001, 0x8002 ... event_key = (event_key << 48) | 0x80004d494f323221; // left part: 0x8000, 0x8001, 0x8002 ...
EventQueue* eq = new EventQueue(SYS_SYNC_FIFO, SYS_PPU_QUEUE, event_key, event_key, 32); std::shared_ptr<EventQueue> eq(new EventQueue(SYS_SYNC_FIFO, SYS_PPU_QUEUE, event_key, event_key, 32));
if (!Emu.GetEventManager().RegisterKey(eq, event_key)) if (!Emu.GetEventManager().RegisterKey(eq, event_key))
{ {
delete eq;
return CELL_AUDIO_ERROR_EVENT_QUEUE; return CELL_AUDIO_ERROR_EVENT_QUEUE;
} }
@@ -841,21 +864,117 @@ int cellAudioRemoveNotifyEventQueueEx(u64 key, u32 iFlags)
return CELL_OK; return CELL_OK;
} }
int cellAudioAddData(u32 portNum, vm::ptr<be_t<float>> src, u32 samples, float volume) int cellAudioAddData(u32 portNum, vm::ptr<float> src, u32 samples, float volume)
{ {
cellAudio->Todo("cellAudioAddData(portNum=0x%x, src_addr=0x%x, samples=%d, volume=%f)", portNum, src.addr(), samples, volume); cellAudio->Warning("cellAudioAddData(portNum=0x%x, src_addr=0x%x, samples=%d, volume=%f)", portNum, src.addr(), samples, volume);
if (src.addr() % 16)
return CELL_AUDIO_ERROR_PARAM;
AudioPortConfig& port = m_config.m_ports[portNum];
if (portNum >= m_config.AUDIO_PORT_COUNT)
{
return CELL_AUDIO_ERROR_PARAM;
}
if (!port.m_is_audio_port_opened)
{
return CELL_AUDIO_ERROR_PORT_NOT_OPEN;
}
if (!port.m_is_audio_port_started)
{
return CELL_AUDIO_ERROR_PORT_NOT_RUN;
}
std::lock_guard<std::mutex> lock(audioMutex);
u32 addr = port.addr;
u32 src_addr = src.addr();
for (u32 i = 0; i < samples; i++)
{
// vm::write32(addr, (u32)((float)vm::read32(src_addr) * volume)); // TODO: use volume?
vm::write32(addr, vm::read32(src_addr));
src_addr += (port.size / samples);
addr += (port.size / samples);
}
return CELL_OK; return CELL_OK;
} }
int cellAudioAdd2chData(u32 portNum, vm::ptr<be_t<float>> src, u32 samples, float volume) int cellAudioAdd2chData(u32 portNum, vm::ptr<float> src, u32 samples, float volume)
{ {
cellAudio->Todo("cellAudioAdd2chData(portNum=0x%x, src_addr=0x%x, samples=%d, volume=%f)", portNum, src.addr(), samples, volume); cellAudio->Warning("cellAudioAdd2chData(portNum=0x%x, src_addr=0x%x, samples=%d, volume=%f)", portNum, src.addr(), samples, volume);
AudioPortConfig& port = m_config.m_ports[portNum];
if (portNum >= m_config.AUDIO_PORT_COUNT)
{
return CELL_AUDIO_ERROR_PARAM;
}
if (!port.m_is_audio_port_opened)
{
return CELL_AUDIO_ERROR_PORT_NOT_OPEN;
}
if (!port.m_is_audio_port_started)
{
return CELL_AUDIO_ERROR_PORT_NOT_RUN;
}
std::lock_guard<std::mutex> lock(audioMutex);
u32 addr = port.addr;
u32 src_addr = src.addr();
for (u32 i = 0; i < samples; i++)
{
// vm::write32(addr, (u32)((float)vm::read32(src_addr) * volume)); // TODO: use volume?
vm::write32(addr, vm::read32(src_addr));
src_addr += (2 * port.block * 256 * sizeof(float) / samples);
addr += (2 * port.block * 256 * sizeof(float) / samples);
}
return CELL_OK; return CELL_OK;
} }
int cellAudioAdd6chData(u32 portNum, vm::ptr<be_t<float>> src, float volume) int cellAudioAdd6chData(u32 portNum, vm::ptr<float> src, float volume)
{ {
cellAudio->Todo("cellAudioAdd6chData(portNum=0x%x, src_addr=0x%x, volume=%f)", portNum, src.addr(), volume); cellAudio->Warning("cellAudioAdd6chData(portNum=0x%x, src_addr=0x%x, volume=%f)", portNum, src.addr(), volume);
AudioPortConfig& port = m_config.m_ports[portNum];
if (portNum >= m_config.AUDIO_PORT_COUNT)
{
return CELL_AUDIO_ERROR_PARAM;
}
if (!port.m_is_audio_port_opened)
{
return CELL_AUDIO_ERROR_PORT_NOT_OPEN;
}
if (!port.m_is_audio_port_started)
{
return CELL_AUDIO_ERROR_PORT_NOT_RUN;
}
std::lock_guard<std::mutex> lock(audioMutex);
u32 addr = port.addr;
u32 src_addr = src.addr();
for (u32 i = 0; i < 256; i++)
{
// vm::write32(addr, (u32)((float)vm::read32(src_addr) * volume)); // TODO: use volume?
vm::write32(addr, vm::read32(src_addr));
src_addr += (6 * port.block * sizeof(float));
addr += (6 * port.block * sizeof(float));
}
return CELL_OK; return CELL_OK;
} }
+9 -6
View File
@@ -16,16 +16,18 @@ int cellVideoOutGetScreenSize(u32 videoOut, vm::ptr<float> screenSize)
{ {
cellAvconfExt->Warning("cellVideoOutGetScreenSize(videoOut=%d, screenSize_addr=0x%x)", videoOut, screenSize.addr()); cellAvconfExt->Warning("cellVideoOutGetScreenSize(videoOut=%d, screenSize_addr=0x%x)", videoOut, screenSize.addr());
if (!videoOut == CELL_VIDEO_OUT_PRIMARY) if (videoOut != CELL_VIDEO_OUT_PRIMARY)
{
return CELL_VIDEO_OUT_ERROR_UNSUPPORTED_VIDEO_OUT; return CELL_VIDEO_OUT_ERROR_UNSUPPORTED_VIDEO_OUT;
}
//TODO: Use virtual screen size //TODO: Use virtual screen size
#ifdef _WIN32 #ifdef _WIN32
HDC screen = GetDC(NULL); HDC screen = GetDC(NULL);
float diagonal = round(sqrt((pow(GetDeviceCaps(screen, HORZSIZE), 2) + pow(GetDeviceCaps(screen, VERTSIZE), 2))) * 0.0393); float diagonal = roundf(sqrtf((powf(float(GetDeviceCaps(screen, HORZSIZE)), 2) + powf(float(GetDeviceCaps(screen, VERTSIZE)), 2))) * 0.0393f);
#else #else
// TODO: Linux implementation, without using wx // TODO: Linux implementation, without using wx
// float diagonal = round(sqrt((pow(wxGetDisplaySizeMM().GetWidth(), 2) + pow(wxGetDisplaySizeMM().GetHeight(), 2))) * 0.0393); // float diagonal = roundf(sqrtf((powf(wxGetDisplaySizeMM().GetWidth(), 2) + powf(wxGetDisplaySizeMM().GetHeight(), 2))) * 0.0393f);
#endif #endif
if (Ini.GS3DTV.GetValue()) if (Ini.GS3DTV.GetValue())
@@ -55,7 +57,8 @@ void cellAvconfExt_init(Module *pxThis)
{ {
cellAvconfExt = pxThis; cellAvconfExt = pxThis;
cellAvconfExt->AddFunc(0x4ec8c141, cellVideoOutConvertCursorColor); REG_FUNC(cellAvconfExt, cellVideoOutConvertCursorColor);
cellAvconfExt->AddFunc(0xfaa275a4, cellVideoOutGetScreenSize); REG_FUNC(cellAvconfExt, cellVideoOutGetScreenSize);
cellAvconfExt->AddFunc(0xc7020f62, cellVideoOutSetGamma); REG_FUNC(cellAvconfExt, cellVideoOutGetGamma);
REG_FUNC(cellAvconfExt, cellVideoOutSetGamma);
} }
+287 -174
View File
@@ -10,67 +10,112 @@
Module *cellDmux = nullptr; Module *cellDmux = nullptr;
#define DMUX_ERROR(...) { cellDmux->Error(__VA_ARGS__); Emu.Pause(); return; } // only for demuxer thread
PesHeader::PesHeader(DemuxerStream& stream) PesHeader::PesHeader(DemuxerStream& stream)
: pts(0xffffffffffffffffull) : pts(CODEC_TS_INVALID)
, dts(0xffffffffffffffffull) , dts(CODEC_TS_INVALID)
, size(0) , size(0)
, has_ts(false) , has_ts(false)
, is_ok(false)
{ {
u16 header; u16 header;
stream.get(header); if (!stream.get(header))
stream.get(size);
if (size)
{ {
u8 empty = 0; DMUX_ERROR("PesHeader(): end of stream (header)");
u8 v; }
while (true) if (!stream.get(size))
{ {
stream.get(v); DMUX_ERROR("PesHeader(): end of stream (size)");
if (v != 0xFF) break; // skip padding bytes }
empty++; if (!stream.check(size))
if (empty == size) return; {
}; DMUX_ERROR("PesHeader(): end of stream (size=%d)", size);
}
if ((v & 0xF0) == 0x20 && (size - empty) >= 5) // pts only u8 pos = 0;
while (pos++ < size)
{ {
has_ts = true; u8 v;
if (!stream.get(v))
{
return; // should never occur
}
if (v == 0xff) // skip padding bytes
{
continue;
}
if ((v & 0xf0) == 0x20 && (size - pos) >= 4) // pts only
{
pos += 4;
pts = stream.get_ts(v); pts = stream.get_ts(v);
stream.skip(size - empty - 5); has_ts = true;
}
else if ((v & 0xf0) == 0x30 && (size - pos) >= 9) // pts and dts
{
pos += 5;
pts = stream.get_ts(v);
stream.get(v);
has_ts = true;
if ((v & 0xf0) != 0x10)
{
cellDmux->Error("PesHeader(): dts not found (v=0x%x, size=%d, pos=%d)", v, size, pos - 1);
stream.skip(size - pos);
return;
}
pos += 4;
dts = stream.get_ts(v);
} }
else else
{ {
has_ts = true; cellDmux->Warning("PesHeader(): unknown code (v=0x%x, size=%d, pos=%d)", v, size, pos - 1);
if ((v & 0xF0) != 0x30 || (size - empty) < 10) stream.skip(size - pos);
pos = size;
break;
}
}
is_ok = true;
}
ElementaryStream::ElementaryStream(Demuxer* dmux, u32 addr, u32 size, u32 fidMajor, u32 fidMinor, u32 sup1, u32 sup2, vm::ptr<CellDmuxCbEsMsg> cbFunc, u32 cbArg, u32 spec)
: dmux(dmux)
, memAddr(a128(addr))
, memSize(size - (addr - memAddr))
, fidMajor(fidMajor)
, fidMinor(fidMinor)
, sup1(sup1)
, sup2(sup2)
, cbFunc(cbFunc)
, cbArg(cbArg)
, spec(spec)
, put(a128(addr))
, put_count(0)
, got_count(0)
, released(0)
, raw_pos(0)
, last_dts(CODEC_TS_INVALID)
, last_pts(CODEC_TS_INVALID)
{ {
cellDmux->Error("PesHeader(): pts not found");
Emu.Pause();
}
pts = stream.get_ts(v);
stream.get(v);
if ((v & 0xF0) != 0x10)
{
cellDmux->Error("PesHeader(): dts not found");
Emu.Pause();
}
dts = stream.get_ts(v);
stream.skip(size - empty - 10);
}
}
} }
bool ElementaryStream::is_full(u32 space) bool ElementaryStream::is_full(u32 space)
{ {
if (released < put_count) if (released < put_count)
{ {
if (entries.IsFull()) if (entries.is_full())
{ {
return true; return true;
} }
u32 first = 0; u32 first = 0;
if (!entries.Peek(first, &dmux->is_closed) || !first) if (!entries.peek(first, 0, &dmux->is_closed) || !first)
{ {
throw "es::is_full() error: entries.Peek() failed"; assert(!"es::is_full() error: entries.Peek() failed");
return false;
} }
else if (first >= put) else if (first >= put)
{ {
@@ -103,10 +148,7 @@ void ElementaryStream::push_au(u32 size, u64 dts, u64 pts, u64 userdata, bool ra
{ {
std::lock_guard<std::mutex> lock(m_mutex); std::lock_guard<std::mutex> lock(m_mutex);
if (is_full(size)) assert(!is_full(size));
{
throw "es::push_au() error: buffer is full";
}
if (put + size + 128 > memAddr + memSize) if (put + size + 128 > memAddr + memSize)
{ {
@@ -146,9 +188,9 @@ void ElementaryStream::push_au(u32 size, u64 dts, u64 pts, u64 userdata, bool ra
put_count++; put_count++;
} }
if (!entries.Push(addr, &dmux->is_closed)) if (!entries.push(addr, &dmux->is_closed))
{ {
throw "es::push_au() error: entries.Push() failed"; assert(!"es::push_au() error: entries.Push() failed");
} }
} }
@@ -180,7 +222,7 @@ bool ElementaryStream::release()
} }
u32 addr = 0; u32 addr = 0;
if (!entries.Pop(addr, &dmux->is_closed) || !addr) if (!entries.pop(addr, &dmux->is_closed) || !addr)
{ {
cellDmux->Error("es::release() error: entries.Pop() failed"); cellDmux->Error("es::release() error: entries.Pop() failed");
Emu.Pause(); Emu.Pause();
@@ -206,7 +248,7 @@ bool ElementaryStream::peek(u32& out_data, bool no_ex, u32& out_spec, bool updat
} }
u32 addr = 0; u32 addr = 0;
if (!entries.Peek(addr, &dmux->is_closed, got_count - released) || !addr) if (!entries.peek(addr, got_count - released, &dmux->is_closed) || !addr)
{ {
cellDmux->Error("es::peek() error: entries.Peek() failed"); cellDmux->Error("es::peek() error: entries.Peek() failed");
Emu.Pause(); Emu.Pause();
@@ -227,7 +269,7 @@ void ElementaryStream::reset()
{ {
std::lock_guard<std::mutex> lock(m_mutex); std::lock_guard<std::mutex> lock(m_mutex);
put = memAddr; put = memAddr;
entries.Clear(); entries.clear();
put_count = 0; put_count = 0;
got_count = 0; got_count = 0;
released = 0; released = 0;
@@ -248,17 +290,18 @@ void dmuxQueryEsAttr(u32 info_addr /* may be 0 */, vm::ptr<const CellCodecEsFilt
if (esFilterId->filterIdMajor >= 0xe0) if (esFilterId->filterIdMajor >= 0xe0)
attr->memSize = 0x500000; // 0x45fa49 from ps3 attr->memSize = 0x500000; // 0x45fa49 from ps3
else else
attr->memSize = 0x8000; // 0x73d9 from ps3 attr->memSize = 0x7000; // 0x73d9 from ps3
cellDmux->Warning("*** filter(0x%x, 0x%x, 0x%x, 0x%x)", (u32)esFilterId->filterIdMajor, (u32)esFilterId->filterIdMinor, cellDmux->Warning("*** filter(0x%x, 0x%x, 0x%x, 0x%x)", (u32)esFilterId->filterIdMajor, (u32)esFilterId->filterIdMinor,
(u32)esFilterId->supplementalInfo1, (u32)esFilterId->supplementalInfo2); (u32)esFilterId->supplementalInfo1, (u32)esFilterId->supplementalInfo2);
} }
u32 dmuxOpen(Demuxer* data) u32 dmuxOpen(Demuxer* dmux_ptr)
{ {
Demuxer& dmux = *data; std::shared_ptr<Demuxer> sptr(dmux_ptr);
Demuxer& dmux = *dmux_ptr;
u32 dmux_id = cellDmux->GetNewId(data); u32 dmux_id = cellDmux->GetNewId(sptr);
dmux.id = dmux_id; dmux.id = dmux_id;
@@ -271,19 +314,20 @@ u32 dmuxOpen(Demuxer* data)
dmux.dmuxCb->InitRegs(); dmux.dmuxCb->InitRegs();
dmux.dmuxCb->DoRun(); dmux.dmuxCb->DoRun();
thread t("Demuxer[" + std::to_string(dmux_id) + "] Thread", [&]() thread t("Demuxer[" + std::to_string(dmux_id) + "] Thread", [dmux_ptr, sptr]()
{ {
Demuxer& dmux = *dmux_ptr;
cellDmux->Notice("Demuxer thread started (mem=0x%x, size=0x%x, cb=0x%x, arg=0x%x)", dmux.memAddr, dmux.memSize, dmux.cbFunc, dmux.cbArg); cellDmux->Notice("Demuxer thread started (mem=0x%x, size=0x%x, cb=0x%x, arg=0x%x)", dmux.memAddr, dmux.memSize, dmux.cbFunc, dmux.cbArg);
DemuxerTask task; DemuxerTask task;
DemuxerStream stream = {}; DemuxerStream stream = {};
ElementaryStream* esALL[192]; memset(esALL, 0, sizeof(esALL)); ElementaryStream* esALL[96]; memset(esALL, 0, sizeof(esALL));
ElementaryStream** esAVC = &esALL[0]; // AVC (max 16) ElementaryStream** esAVC = &esALL[0]; // AVC (max 16 minus M2V count)
ElementaryStream** esM2V = &esALL[16]; // MPEG-2 (max 16) ElementaryStream** esM2V = &esALL[16]; // M2V (max 16 minus AVC count)
ElementaryStream** esDATA = &esALL[32]; // user data (max 16) ElementaryStream** esDATA = &esALL[32]; // user data (max 16)
ElementaryStream** esATX = &esALL[48]; // ATRAC3+ (max 48) ElementaryStream** esATX = &esALL[48]; // ATRAC3+ (max 16)
ElementaryStream** esAC3 = &esALL[96]; // AC3 (max 48) ElementaryStream** esAC3 = &esALL[64]; // AC3 (max 16)
ElementaryStream** esPCM = &esALL[144]; // LPCM (max 48) ElementaryStream** esPCM = &esALL[80]; // LPCM (max 16)
u32 cb_add = 0; u32 cb_add = 0;
@@ -294,12 +338,11 @@ u32 dmuxOpen(Demuxer* data)
break; break;
} }
if (!dmux.job.Peek(task, &sq_no_wait) && dmux.is_running && stream.addr) if (!dmux.job.try_peek(task) && dmux.is_running && stream.addr)
{ {
// default task (demuxing) (if there is no other work) // default task (demuxing) (if there is no other work)
be_t<u32> code; be_t<u32> code;
be_t<u16> len; be_t<u16> len;
u8 ch;
if (!stream.peek(code)) if (!stream.peek(code))
{ {
@@ -310,64 +353,119 @@ u32 dmuxOpen(Demuxer* data)
dmux.cbFunc.call(*dmux.dmuxCb, dmux.id, dmuxMsg, dmux.cbArg); dmux.cbFunc.call(*dmux.dmuxCb, dmux.id, dmuxMsg, dmux.cbArg);
dmux.is_running = false; dmux.is_running = false;
continue;
} }
else switch (code.ToLE())
switch (code.ToLE())
{ {
case PACK_START_CODE: case PACK_START_CODE:
{ {
stream.skip(14); if (!stream.check(14))
{
DMUX_ERROR("End of stream (PACK_START_CODE)");
} }
stream.skip(14);
break; break;
}
case SYSTEM_HEADER_START_CODE: case SYSTEM_HEADER_START_CODE:
{ {
stream.skip(18); if (!stream.check(18))
{
DMUX_ERROR("End of stream (SYSTEM_HEADER_START_CODE)");
} }
stream.skip(18);
break; break;
}
case PADDING_STREAM: case PADDING_STREAM:
{ {
if (!stream.check(6))
{
DMUX_ERROR("End of stream (PADDING_STREAM)");
}
stream.skip(4); stream.skip(4);
stream.get(len); stream.get(len);
stream.skip(len);
if (!stream.check(len.ToLE()))
{
DMUX_ERROR("End of stream (PADDING_STREAM, len=%d)", len.ToLE());
} }
stream.skip(len);
break; break;
}
case PRIVATE_STREAM_2: case PRIVATE_STREAM_2:
{ {
if (!stream.check(6))
{
DMUX_ERROR("End of stream (PRIVATE_STREAM_2)");
}
stream.skip(4); stream.skip(4);
stream.get(len); stream.get(len);
stream.skip(len);
cellDmux->Notice("PRIVATE_STREAM_2 (%d)", len.ToLE());
if (!stream.check(len.ToLE()))
{
DMUX_ERROR("End of stream (PRIVATE_STREAM_2, len=%d)", len.ToLE());
} }
stream.skip(len);
break; break;
}
case PRIVATE_STREAM_1: case PRIVATE_STREAM_1:
{ {
// audio and user data stream
DemuxerStream backup = stream; DemuxerStream backup = stream;
// audio AT3+ (and probably LPCM or user data) if (!stream.check(6))
{
DMUX_ERROR("End of stream (PRIVATE_STREAM_1)");
}
stream.skip(4); stream.skip(4);
stream.get(len); stream.get(len);
PesHeader pes(stream); if (!stream.check(len.ToLE()))
{
DMUX_ERROR("End of stream (PRIVATE_STREAM_1, len=%d)", len.ToLE());
}
// read additional header: const PesHeader pes(stream);
stream.peek(ch); // ??? if (!pes.is_ok)
//stream.skip(4); {
//pes.size += 4; DMUX_ERROR("PesHeader error (PRIVATE_STREAM_1, len=%d)", len.ToLE());
}
if (esATX[ch]) if (len < pes.size + 4)
{
DMUX_ERROR("End of block (PRIVATE_STREAM_1, PesHeader + fid_minor, len=%d)", len.ToLE());
}
len -= pes.size + 4;
u8 fid_minor;
if (!stream.get(fid_minor))
{
DMUX_ERROR("End of stream (PRIVATE_STREAM1, fid_minor)");
}
const u32 ch = fid_minor % 16;
if ((fid_minor & -0x10) == 0 && esATX[ch])
{ {
ElementaryStream& es = *esATX[ch]; ElementaryStream& es = *esATX[ch];
if (es.raw_data.size() > 1024 * 1024) if (es.raw_data.size() > 1024 * 1024)
{ {
stream = backup; stream = backup;
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
continue; continue;
} }
stream.skip(4); if (len < 3 || !stream.check(3))
len -= 4; {
DMUX_ERROR("End of block (ATX, unknown header, len=%d)", len.ToLE());
}
len -= 3;
stream.skip(3);
if (pes.has_ts) if (pes.has_ts)
{ {
@@ -375,7 +473,7 @@ u32 dmuxOpen(Demuxer* data)
es.last_pts = pes.pts; es.last_pts = pes.pts;
} }
es.push(stream, len - pes.size - 3); es.push(stream, len);
while (true) while (true)
{ {
@@ -386,9 +484,7 @@ u32 dmuxOpen(Demuxer* data)
if (data[0] != 0x0f || data[1] != 0xd0) if (data[0] != 0x0f || data[1] != 0xd0)
{ {
cellDmux->Error("ATX: 0x0fd0 header not found (ats=0x%llx)", ((be_t<u64>*)data)->ToLE()); DMUX_ERROR("ATX: 0x0fd0 header not found (ats=0x%llx)", ((be_t<u64>*)data)->ToLE());
Emu.Pause();
return;
} }
u32 frame_size = ((((u32)data[2] & 0x3) << 8) | (u32)data[3]) * 8 + 8; u32 frame_size = ((((u32)data[2] & 0x3) << 8) | (u32)data[3]) * 8 + 8;
@@ -399,6 +495,8 @@ u32 dmuxOpen(Demuxer* data)
es.push_au(frame_size + 8, es.last_dts, es.last_pts, stream.userdata, false /* TODO: set correct value */, 0); es.push_au(frame_size + 8, es.last_dts, es.last_pts, stream.userdata, false /* TODO: set correct value */, 0);
//cellDmux->Notice("ATX AU pushed (ats=0x%llx, frame_size=%d)", ((be_t<u64>*)data)->ToLE(), frame_size);
auto esMsg = vm::ptr<CellDmuxEsMsg>::make(a128(dmux.memAddr) + (cb_add ^= 16)); auto esMsg = vm::ptr<CellDmuxEsMsg>::make(a128(dmux.memAddr) + (cb_add ^= 16));
esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_AU_FOUND; esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_AU_FOUND;
esMsg->supplementalInfo = stream.userdata; esMsg->supplementalInfo = stream.userdata;
@@ -407,38 +505,60 @@ u32 dmuxOpen(Demuxer* data)
} }
else else
{ {
stream.skip(len - pes.size - 3); cellDmux->Notice("PRIVATE_STREAM_1 (len=%d, fid_minor=0x%x)", len.ToLE(), fid_minor);
} stream.skip(len);
} }
break; break;
}
case 0x1e0: case 0x1e1: case 0x1e2: case 0x1e3: case 0x1e0: case 0x1e1: case 0x1e2: case 0x1e3:
case 0x1e4: case 0x1e5: case 0x1e6: case 0x1e7: case 0x1e4: case 0x1e5: case 0x1e6: case 0x1e7:
case 0x1e8: case 0x1e9: case 0x1ea: case 0x1eb: case 0x1e8: case 0x1e9: case 0x1ea: case 0x1eb:
case 0x1ec: case 0x1ed: case 0x1ee: case 0x1ef: case 0x1ec: case 0x1ed: case 0x1ee: case 0x1ef:
{ {
// video AVC // video stream (AVC or M2V)
ch = code - 0x1e0; DemuxerStream backup = stream;
if (!stream.check(6))
{
DMUX_ERROR("End of stream (video, code=0x%x)", code.ToLE());
}
stream.skip(4);
stream.get(len);
if (!stream.check(len.ToLE()))
{
DMUX_ERROR("End of stream (video, code=0x%x, len=%d)", code.ToLE(), len.ToLE());
}
const PesHeader pes(stream);
if (!pes.is_ok)
{
DMUX_ERROR("PesHeader error (video, code=0x%x, len=%d)", code.ToLE(), len.ToLE());
}
if (len < pes.size + 3)
{
DMUX_ERROR("End of block (video, code=0x%x, PesHeader)", code.ToLE());
}
len -= pes.size + 3;
const u32 ch = code.ToLE() % 16;
if (esAVC[ch]) if (esAVC[ch])
{ {
ElementaryStream& es = *esAVC[ch]; ElementaryStream& es = *esAVC[ch];
DemuxerStream backup = stream;
stream.skip(4);
stream.get(len);
PesHeader pes(stream);
const u32 old_size = (u32)es.raw_data.size(); const u32 old_size = (u32)es.raw_data.size();
if (es.isfull(old_size)) if (es.isfull(old_size))
{ {
stream = backup; stream = backup;
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
continue; continue;
} }
if ((pes.has_ts && old_size) || old_size >= 0x70000) if ((pes.has_ts && old_size) || old_size >= 0x69800)
{ {
// push AU if it becomes too big or the next packet contains ts data // push AU if it becomes too big or the next packet contains PTS/DTS
es.push_au(old_size, es.last_dts, es.last_pts, stream.userdata, false /* TODO: set correct value */, 0); es.push_au(old_size, es.last_dts, es.last_pts, stream.userdata, false /* TODO: set correct value */, 0);
// callback // callback
@@ -456,54 +576,35 @@ u32 dmuxOpen(Demuxer* data)
} }
// reconstruction of MPEG2-PS stream for vdec module // reconstruction of MPEG2-PS stream for vdec module
const u32 size = len + 6 /*- pes.size - 3*/; const u32 size = (u32)len.ToLE() + pes.size + 9;
stream = backup; stream = backup;
es.push(stream, size); es.push(stream, size);
} }
else else
{ {
stream.skip(4); cellDmux->Notice("Video stream (code=0x%x, len=%d)", code.ToLE(), len.ToLE());
stream.get(len);
stream.skip(len);
}
}
break;
case 0x1c0: case 0x1c1: case 0x1c2: case 0x1c3:
case 0x1c4: case 0x1c5: case 0x1c6: case 0x1c7:
case 0x1c8: case 0x1c9: case 0x1ca: case 0x1cb:
case 0x1cc: case 0x1cd: case 0x1ce: case 0x1cf:
case 0x1d0: case 0x1d1: case 0x1d2: case 0x1d3:
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); stream.skip(len);
} }
break; break;
case USER_DATA_START_CODE:
{
cellDmux->Error("USER_DATA_START_CODE found");
Emu.Pause();
return;
} }
default: default:
{ {
if ((code.ToLE() & PACKET_START_CODE_MASK) == PACKET_START_CODE_PREFIX)
{
DMUX_ERROR("Unknown code found (0x%x)", code.ToLE());
}
// search // search
stream.skip(1); stream.skip(1);
} }
} }
continue; continue;
} }
// wait for task with yielding (if no default work) // wait for task if no work
if (!dmux.job.Pop(task, &dmux.is_closed)) if (!dmux.job.pop(task, &dmux.is_closed))
{ {
break; // Emu is stopped break; // Emu is stopped
} }
@@ -515,7 +616,7 @@ u32 dmuxOpen(Demuxer* data)
if (task.stream.discontinuity) if (task.stream.discontinuity)
{ {
cellDmux->Warning("dmuxSetStream (beginning)"); cellDmux->Warning("dmuxSetStream (beginning)");
for (u32 i = 0; i < 192; i++) for (u32 i = 0; i < sizeof(esALL) / sizeof(esALL[0]); i++)
{ {
if (esALL[i]) if (esALL[i])
{ {
@@ -527,8 +628,8 @@ u32 dmuxOpen(Demuxer* data)
stream = task.stream; stream = task.stream;
//LOG_NOTICE(HLE, "*** stream updated(addr=0x%x, size=0x%x, discont=%d, userdata=0x%llx)", //LOG_NOTICE(HLE, "*** stream updated(addr=0x%x, size=0x%x, discont=%d, userdata=0x%llx)",
//stream.addr, stream.size, stream.discontinuity, stream.userdata); //stream.addr, stream.size, stream.discontinuity, stream.userdata);
}
break; break;
}
case dmuxResetStream: case dmuxResetStream:
case dmuxResetStreamAndWaitDone: case dmuxResetStreamAndWaitDone:
@@ -543,44 +644,55 @@ u32 dmuxOpen(Demuxer* data)
//if (task.type == dmuxResetStreamAndWaitDone) //if (task.type == dmuxResetStreamAndWaitDone)
//{ //{
//} //}
}
break; break;
}
case dmuxEnableEs: case dmuxEnableEs:
{ {
ElementaryStream& es = *task.es.es_ptr; ElementaryStream& es = *task.es.es_ptr;
if (es.fidMajor >= 0xe0 &&
es.fidMajor <= 0xef && // TODO: uncomment when ready to use
es.fidMinor == 0 && if ((es.fidMajor & -0x10) == 0xe0 && es.fidMinor == 0 && es.sup1 == 1 && !es.sup2)
es.sup1 == 1 &&
es.sup2 == 0)
{ {
esAVC[es.fidMajor - 0xe0] = task.es.es_ptr; esAVC[es.fidMajor % 16] = task.es.es_ptr;
} }
else if (es.fidMajor == 0xbd && //else if ((es.fidMajor & -0x10) == 0xe0 && es.fidMinor == 0 && !es.sup1 && !es.sup2)
es.fidMinor == 0 && //{
es.sup1 == 0 && // esM2V[es.fidMajor % 16] = task.es.es_ptr;
es.sup2 == 0) //}
else if (es.fidMajor == 0xbd && (es.fidMinor & -0x10) == 0 && !es.sup1 && !es.sup2)
{ {
esATX[0] = task.es.es_ptr; esATX[es.fidMinor % 16] = task.es.es_ptr;
} }
//else if (es.fidMajor == 0xbd && (es.fidMinor & -0x10) == 0x20 && !es.sup1 && !es.sup2)
//{
// esDATA[es.fidMinor % 16] = task.es.es_ptr;
//}
//else if (es.fidMajor == 0xbd && (es.fidMinor & -0x10) == 0x30 && !es.sup1 && !es.sup2)
//{
// esAC3[es.fidMinor % 16] = task.es.es_ptr;
//}
//else if (es.fidMajor == 0xbd && (es.fidMinor & -0x10) == 0x40 && !es.sup1 && !es.sup2)
//{
// esPCM[es.fidMinor % 16] = task.es.es_ptr;
//}
else else
{ {
cellDmux->Warning("dmuxEnableEs: (TODO) unsupported filter (0x%x, 0x%x, 0x%x, 0x%x)", es.fidMajor, es.fidMinor, es.sup1, es.sup2); DMUX_ERROR("dmuxEnableEs: unknown filter (0x%x, 0x%x, 0x%x, 0x%x)", es.fidMajor, es.fidMinor, es.sup1, es.sup2);
} }
es.dmux = &dmux; es.dmux = &dmux;
}
break; break;
}
case dmuxDisableEs: case dmuxDisableEs:
{ {
ElementaryStream& es = *task.es.es_ptr; ElementaryStream& es = *task.es.es_ptr;
if (es.dmux != &dmux) if (es.dmux != &dmux)
{ {
cellDmux->Warning("dmuxDisableEs: invalid elementary stream"); DMUX_ERROR("dmuxDisableEs: invalid elementary stream");
break;
} }
for (u32 i = 0; i < 192; i++)
for (u32 i = 0; i < sizeof(esALL) / sizeof(esALL[0]); i++)
{ {
if (esALL[i] == &es) if (esALL[i] == &es)
{ {
@@ -589,22 +701,22 @@ u32 dmuxOpen(Demuxer* data)
} }
es.dmux = nullptr; es.dmux = nullptr;
Emu.GetIdManager().RemoveID(task.es.es); Emu.GetIdManager().RemoveID(task.es.es);
}
break; break;
}
case dmuxFlushEs: case dmuxFlushEs:
{ {
ElementaryStream& es = *task.es.es_ptr; ElementaryStream& es = *task.es.es_ptr;
const u32 old_size = (u32)es.raw_data.size(); const u32 old_size = (u32)es.raw_data.size();
if (old_size && (es.fidMajor & 0xf0) == 0xe0) if (old_size && (es.fidMajor & -0x10) == 0xe0)
{ {
// TODO (it's only for AVC, some ATX data may be lost) // TODO (it's only for AVC, some ATX data may be lost)
while (es.isfull(old_size)) while (es.isfull(old_size))
{ {
if (Emu.IsStopped() || dmux.is_closed) break; if (Emu.IsStopped() || dmux.is_closed) break;
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
} }
es.push_au(old_size, es.last_dts, es.last_pts, stream.userdata, false, 0); es.push_au(old_size, es.last_dts, es.last_pts, stream.userdata, false, 0);
@@ -626,22 +738,23 @@ u32 dmuxOpen(Demuxer* data)
esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_FLUSH_DONE; esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_FLUSH_DONE;
esMsg->supplementalInfo = stream.userdata; esMsg->supplementalInfo = stream.userdata;
es.cbFunc.call(*dmux.dmuxCb, dmux.id, es.id, esMsg, es.cbArg); es.cbFunc.call(*dmux.dmuxCb, dmux.id, es.id, esMsg, es.cbArg);
}
break; break;
}
case dmuxResetEs: case dmuxResetEs:
{ {
task.es.es_ptr->reset(); task.es.es_ptr->reset();
}
break; break;
}
case dmuxClose: break; case dmuxClose:
{
break;
}
default: default:
{ {
cellDmux->Error("Demuxer thread error: unknown task(%d)", task.type); DMUX_ERROR("Demuxer thread error: unknown task (0x%x)", task.type);
Emu.Pause();
return;
} }
} }
} }
@@ -740,14 +853,14 @@ int cellDmuxClose(u32 demuxerHandle)
{ {
cellDmux->Warning("cellDmuxClose(demuxerHandle=%d)", demuxerHandle); cellDmux->Warning("cellDmuxClose(demuxerHandle=%d)", demuxerHandle);
Demuxer* dmux; std::shared_ptr<Demuxer> dmux;
if (!Emu.GetIdManager().GetIDData(demuxerHandle, dmux)) if (!Emu.GetIdManager().GetIDData(demuxerHandle, dmux))
{ {
return CELL_DMUX_ERROR_ARG; return CELL_DMUX_ERROR_ARG;
} }
dmux->is_closed = true; dmux->is_closed = true;
dmux->job.Push(DemuxerTask(dmuxClose), &sq_no_wait); dmux->job.try_push(DemuxerTask(dmuxClose));
while (!dmux->is_finished) while (!dmux->is_finished)
{ {
@@ -757,7 +870,7 @@ int cellDmuxClose(u32 demuxerHandle)
return CELL_OK; return CELL_OK;
} }
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
} }
if (dmux->dmuxCb) Emu.GetCPU().RemoveThread(dmux->dmuxCb->GetId()); if (dmux->dmuxCb) Emu.GetCPU().RemoveThread(dmux->dmuxCb->GetId());
@@ -770,7 +883,7 @@ int cellDmuxSetStream(u32 demuxerHandle, const u32 streamAddress, u32 streamSize
cellDmux->Log("cellDmuxSetStream(demuxerHandle=%d, streamAddress=0x%x, streamSize=%d, discontinuity=%d, userData=0x%llx", cellDmux->Log("cellDmuxSetStream(demuxerHandle=%d, streamAddress=0x%x, streamSize=%d, discontinuity=%d, userData=0x%llx",
demuxerHandle, streamAddress, streamSize, discontinuity, userData); demuxerHandle, streamAddress, streamSize, discontinuity, userData);
Demuxer* dmux; std::shared_ptr<Demuxer> dmux;
if (!Emu.GetIdManager().GetIDData(demuxerHandle, dmux)) if (!Emu.GetIdManager().GetIDData(demuxerHandle, dmux))
{ {
return CELL_DMUX_ERROR_ARG; return CELL_DMUX_ERROR_ARG;
@@ -789,7 +902,7 @@ int cellDmuxSetStream(u32 demuxerHandle, const u32 streamAddress, u32 streamSize
info.discontinuity = discontinuity; info.discontinuity = discontinuity;
info.userdata = userData; info.userdata = userData;
dmux->job.Push(task, &dmux->is_closed); dmux->job.push(task, &dmux->is_closed);
return CELL_OK; return CELL_OK;
} }
@@ -797,13 +910,13 @@ int cellDmuxResetStream(u32 demuxerHandle)
{ {
cellDmux->Warning("cellDmuxResetStream(demuxerHandle=%d)", demuxerHandle); cellDmux->Warning("cellDmuxResetStream(demuxerHandle=%d)", demuxerHandle);
Demuxer* dmux; std::shared_ptr<Demuxer> dmux;
if (!Emu.GetIdManager().GetIDData(demuxerHandle, dmux)) if (!Emu.GetIdManager().GetIDData(demuxerHandle, dmux))
{ {
return CELL_DMUX_ERROR_ARG; return CELL_DMUX_ERROR_ARG;
} }
dmux->job.Push(DemuxerTask(dmuxResetStream), &dmux->is_closed); dmux->job.push(DemuxerTask(dmuxResetStream), &dmux->is_closed);
return CELL_OK; return CELL_OK;
} }
@@ -811,13 +924,13 @@ int cellDmuxResetStreamAndWaitDone(u32 demuxerHandle)
{ {
cellDmux->Warning("cellDmuxResetStreamAndWaitDone(demuxerHandle=%d)", demuxerHandle); cellDmux->Warning("cellDmuxResetStreamAndWaitDone(demuxerHandle=%d)", demuxerHandle);
Demuxer* dmux; std::shared_ptr<Demuxer> dmux;
if (!Emu.GetIdManager().GetIDData(demuxerHandle, dmux)) if (!Emu.GetIdManager().GetIDData(demuxerHandle, dmux))
{ {
return CELL_DMUX_ERROR_ARG; return CELL_DMUX_ERROR_ARG;
} }
dmux->job.Push(DemuxerTask(dmuxResetStreamAndWaitDone), &dmux->is_closed); dmux->job.push(DemuxerTask(dmuxResetStreamAndWaitDone), &dmux->is_closed);
while (dmux->is_running && !dmux->is_closed) // TODO: ensure that it is safe while (dmux->is_running && !dmux->is_closed) // TODO: ensure that it is safe
{ {
if (Emu.IsStopped()) if (Emu.IsStopped())
@@ -825,7 +938,7 @@ int cellDmuxResetStreamAndWaitDone(u32 demuxerHandle)
cellDmux->Warning("cellDmuxResetStreamAndWaitDone(%d) aborted", demuxerHandle); cellDmux->Warning("cellDmuxResetStreamAndWaitDone(%d) aborted", demuxerHandle);
return CELL_OK; return CELL_OK;
} }
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
} }
return CELL_OK; return CELL_OK;
} }
@@ -870,7 +983,7 @@ int cellDmuxEnableEs(u32 demuxerHandle, vm::ptr<const CellCodecEsFilterId> esFil
"esSpecificInfo_addr=0x%x, esHandle_addr=0x%x)", demuxerHandle, esFilterId.addr(), esResourceInfo.addr(), "esSpecificInfo_addr=0x%x, esHandle_addr=0x%x)", demuxerHandle, esFilterId.addr(), esResourceInfo.addr(),
esCb.addr(), esSpecificInfo_addr, esHandle.addr()); esCb.addr(), esSpecificInfo_addr, esHandle.addr());
Demuxer* dmux; std::shared_ptr<Demuxer> dmux;
if (!Emu.GetIdManager().GetIDData(demuxerHandle, dmux)) if (!Emu.GetIdManager().GetIDData(demuxerHandle, dmux))
{ {
return CELL_DMUX_ERROR_ARG; return CELL_DMUX_ERROR_ARG;
@@ -878,9 +991,9 @@ int cellDmuxEnableEs(u32 demuxerHandle, vm::ptr<const CellCodecEsFilterId> esFil
// TODO: check esFilterId, esResourceInfo, esCb and esSpecificInfo correctly // TODO: check esFilterId, esResourceInfo, esCb and esSpecificInfo correctly
ElementaryStream* es = new ElementaryStream(dmux, esResourceInfo->memAddr, esResourceInfo->memSize, std::shared_ptr<ElementaryStream> es(new ElementaryStream(dmux.get(), esResourceInfo->memAddr, esResourceInfo->memSize,
esFilterId->filterIdMajor, esFilterId->filterIdMinor, esFilterId->supplementalInfo1, esFilterId->supplementalInfo2, esFilterId->filterIdMajor, esFilterId->filterIdMinor, esFilterId->supplementalInfo1, esFilterId->supplementalInfo2,
vm::ptr<CellDmuxCbEsMsg>::make(esCb->cbEsMsgFunc.addr()), esCb->cbArg, esSpecificInfo_addr); vm::ptr<CellDmuxCbEsMsg>::make(esCb->cbEsMsgFunc.addr()), esCb->cbArg, esSpecificInfo_addr));
u32 id = cellDmux->GetNewId(es); u32 id = cellDmux->GetNewId(es);
es->id = id; es->id = id;
@@ -891,9 +1004,9 @@ int cellDmuxEnableEs(u32 demuxerHandle, vm::ptr<const CellCodecEsFilterId> esFil
DemuxerTask task(dmuxEnableEs); DemuxerTask task(dmuxEnableEs);
task.es.es = id; task.es.es = id;
task.es.es_ptr = es; task.es.es_ptr = es.get();
dmux->job.Push(task, &dmux->is_closed); dmux->job.push(task, &dmux->is_closed);
return CELL_OK; return CELL_OK;
} }
@@ -901,7 +1014,7 @@ int cellDmuxDisableEs(u32 esHandle)
{ {
cellDmux->Warning("cellDmuxDisableEs(esHandle=0x%x)", esHandle); cellDmux->Warning("cellDmuxDisableEs(esHandle=0x%x)", esHandle);
ElementaryStream* es; std::shared_ptr<ElementaryStream> es;
if (!Emu.GetIdManager().GetIDData(esHandle, es)) if (!Emu.GetIdManager().GetIDData(esHandle, es))
{ {
return CELL_DMUX_ERROR_ARG; return CELL_DMUX_ERROR_ARG;
@@ -909,9 +1022,9 @@ int cellDmuxDisableEs(u32 esHandle)
DemuxerTask task(dmuxDisableEs); DemuxerTask task(dmuxDisableEs);
task.es.es = esHandle; task.es.es = esHandle;
task.es.es_ptr = es; task.es.es_ptr = es.get();
es->dmux->job.Push(task, &es->dmux->is_closed); es->dmux->job.push(task, &es->dmux->is_closed);
return CELL_OK; return CELL_OK;
} }
@@ -919,7 +1032,7 @@ int cellDmuxResetEs(u32 esHandle)
{ {
cellDmux->Log("cellDmuxResetEs(esHandle=0x%x)", esHandle); cellDmux->Log("cellDmuxResetEs(esHandle=0x%x)", esHandle);
ElementaryStream* es; std::shared_ptr<ElementaryStream> es;
if (!Emu.GetIdManager().GetIDData(esHandle, es)) if (!Emu.GetIdManager().GetIDData(esHandle, es))
{ {
return CELL_DMUX_ERROR_ARG; return CELL_DMUX_ERROR_ARG;
@@ -927,9 +1040,9 @@ int cellDmuxResetEs(u32 esHandle)
DemuxerTask task(dmuxResetEs); DemuxerTask task(dmuxResetEs);
task.es.es = esHandle; task.es.es = esHandle;
task.es.es_ptr = es; task.es.es_ptr = es.get();
es->dmux->job.Push(task, &es->dmux->is_closed); es->dmux->job.push(task, &es->dmux->is_closed);
return CELL_OK; return CELL_OK;
} }
@@ -938,7 +1051,7 @@ int cellDmuxGetAu(u32 esHandle, vm::ptr<u32> auInfo_ptr, vm::ptr<u32> auSpecific
cellDmux->Log("cellDmuxGetAu(esHandle=0x%x, auInfo_ptr_addr=0x%x, auSpecificInfo_ptr_addr=0x%x)", cellDmux->Log("cellDmuxGetAu(esHandle=0x%x, auInfo_ptr_addr=0x%x, auSpecificInfo_ptr_addr=0x%x)",
esHandle, auInfo_ptr.addr(), auSpecificInfo_ptr.addr()); esHandle, auInfo_ptr.addr(), auSpecificInfo_ptr.addr());
ElementaryStream* es; std::shared_ptr<ElementaryStream> es;
if (!Emu.GetIdManager().GetIDData(esHandle, es)) if (!Emu.GetIdManager().GetIDData(esHandle, es))
{ {
return CELL_DMUX_ERROR_ARG; return CELL_DMUX_ERROR_ARG;
@@ -961,7 +1074,7 @@ int cellDmuxPeekAu(u32 esHandle, vm::ptr<u32> auInfo_ptr, vm::ptr<u32> auSpecifi
cellDmux->Log("cellDmuxPeekAu(esHandle=0x%x, auInfo_ptr_addr=0x%x, auSpecificInfo_ptr_addr=0x%x)", cellDmux->Log("cellDmuxPeekAu(esHandle=0x%x, auInfo_ptr_addr=0x%x, auSpecificInfo_ptr_addr=0x%x)",
esHandle, auInfo_ptr.addr(), auSpecificInfo_ptr.addr()); esHandle, auInfo_ptr.addr(), auSpecificInfo_ptr.addr());
ElementaryStream* es; std::shared_ptr<ElementaryStream> es;
if (!Emu.GetIdManager().GetIDData(esHandle, es)) if (!Emu.GetIdManager().GetIDData(esHandle, es))
{ {
return CELL_DMUX_ERROR_ARG; return CELL_DMUX_ERROR_ARG;
@@ -984,7 +1097,7 @@ int cellDmuxGetAuEx(u32 esHandle, vm::ptr<u32> auInfoEx_ptr, vm::ptr<u32> auSpec
cellDmux->Log("cellDmuxGetAuEx(esHandle=0x%x, auInfoEx_ptr_addr=0x%x, auSpecificInfo_ptr_addr=0x%x)", cellDmux->Log("cellDmuxGetAuEx(esHandle=0x%x, auInfoEx_ptr_addr=0x%x, auSpecificInfo_ptr_addr=0x%x)",
esHandle, auInfoEx_ptr.addr(), auSpecificInfo_ptr.addr()); esHandle, auInfoEx_ptr.addr(), auSpecificInfo_ptr.addr());
ElementaryStream* es; std::shared_ptr<ElementaryStream> es;
if (!Emu.GetIdManager().GetIDData(esHandle, es)) if (!Emu.GetIdManager().GetIDData(esHandle, es))
{ {
return CELL_DMUX_ERROR_ARG; return CELL_DMUX_ERROR_ARG;
@@ -1007,7 +1120,7 @@ int cellDmuxPeekAuEx(u32 esHandle, vm::ptr<u32> auInfoEx_ptr, vm::ptr<u32> auSpe
cellDmux->Log("cellDmuxPeekAuEx(esHandle=0x%x, auInfoEx_ptr_addr=0x%x, auSpecificInfo_ptr_addr=0x%x)", cellDmux->Log("cellDmuxPeekAuEx(esHandle=0x%x, auInfoEx_ptr_addr=0x%x, auSpecificInfo_ptr_addr=0x%x)",
esHandle, auInfoEx_ptr.addr(), auSpecificInfo_ptr.addr()); esHandle, auInfoEx_ptr.addr(), auSpecificInfo_ptr.addr());
ElementaryStream* es; std::shared_ptr<ElementaryStream> es;
if (!Emu.GetIdManager().GetIDData(esHandle, es)) if (!Emu.GetIdManager().GetIDData(esHandle, es))
{ {
return CELL_DMUX_ERROR_ARG; return CELL_DMUX_ERROR_ARG;
@@ -1029,7 +1142,7 @@ int cellDmuxReleaseAu(u32 esHandle)
{ {
cellDmux->Log("cellDmuxReleaseAu(esHandle=0x%x)", esHandle); cellDmux->Log("cellDmuxReleaseAu(esHandle=0x%x)", esHandle);
ElementaryStream* es; std::shared_ptr<ElementaryStream> es;
if (!Emu.GetIdManager().GetIDData(esHandle, es)) if (!Emu.GetIdManager().GetIDData(esHandle, es))
{ {
return CELL_DMUX_ERROR_ARG; return CELL_DMUX_ERROR_ARG;
@@ -1046,7 +1159,7 @@ int cellDmuxFlushEs(u32 esHandle)
{ {
cellDmux->Warning("cellDmuxFlushEs(esHandle=0x%x)", esHandle); cellDmux->Warning("cellDmuxFlushEs(esHandle=0x%x)", esHandle);
ElementaryStream* es; std::shared_ptr<ElementaryStream> es;
if (!Emu.GetIdManager().GetIDData(esHandle, es)) if (!Emu.GetIdManager().GetIDData(esHandle, es))
{ {
return CELL_DMUX_ERROR_ARG; return CELL_DMUX_ERROR_ARG;
@@ -1054,9 +1167,9 @@ int cellDmuxFlushEs(u32 esHandle)
DemuxerTask task(dmuxFlushEs); DemuxerTask task(dmuxFlushEs);
task.es.es = esHandle; task.es.es = esHandle;
task.es.es_ptr = es; task.es.es_ptr = es.get();
es->dmux->job.Push(task, &es->dmux->is_closed); es->dmux->job.push(task, &es->dmux->is_closed);
return CELL_OK; return CELL_OK;
} }
+10 -38
View File
@@ -1,7 +1,5 @@
#pragma once #pragma once
#include "Utilities/SQueue.h"
// align size or address to 128 // align size or address to 128
#define a128(x) ((x + 127) & (~127)) #define a128(x) ((x + 127) & (~127))
@@ -288,15 +286,8 @@ enum
PACKET_START_CODE_MASK = 0xffffff00, PACKET_START_CODE_MASK = 0xffffff00,
PACKET_START_CODE_PREFIX = 0x00000100, PACKET_START_CODE_PREFIX = 0x00000100,
USER_DATA_START_CODE = 0x000001b2,
SEQUENCE_START_CODE = 0x000001b3,
EXT_START_CODE = 0x000001b5,
SEQUENCE_END_CODE = 0x000001b7,
GOP_START_CODE = 0x000001b8,
ISO_11172_END_CODE = 0x000001b9,
PACK_START_CODE = 0x000001ba, PACK_START_CODE = 0x000001ba,
SYSTEM_HEADER_START_CODE = 0x000001bb, SYSTEM_HEADER_START_CODE = 0x000001bb,
PROGRAM_STREAM_MAP = 0x000001bc,
PRIVATE_STREAM_1 = 0x000001bd, PRIVATE_STREAM_1 = 0x000001bd,
PADDING_STREAM = 0x000001be, PADDING_STREAM = 0x000001be,
PRIVATE_STREAM_2 = 0x000001bf, PRIVATE_STREAM_2 = 0x000001bf,
@@ -336,6 +327,11 @@ struct DemuxerStream
size = size > count ? size - count : 0; size = size > count ? size - count : 0;
} }
bool check(u32 count) const
{
return count <= size;
}
u64 get_ts(u8 c) u64 get_ts(u8 c)
{ {
u8 v[4]; get((u32&)v); u8 v[4]; get((u32&)v);
@@ -345,12 +341,6 @@ struct DemuxerStream
(((u64)v[1] & 0x7e) << 15) | (((u64)v[1] & 0x7e) << 15) |
(((u64)v[2]) << 7) | ((u64)v[3] >> 1); (((u64)v[2]) << 7) | ((u64)v[3] >> 1);
} }
u64 get_ts()
{
u8 v; get(v);
return get_ts(v);
}
}; };
struct PesHeader struct PesHeader
@@ -359,6 +349,7 @@ struct PesHeader
u64 dts; u64 dts;
u8 size; u8 size;
bool has_ts; bool has_ts;
bool is_ok;
PesHeader(DemuxerStream& stream); PesHeader(DemuxerStream& stream);
}; };
@@ -407,7 +398,7 @@ struct DemuxerTask
class Demuxer class Demuxer
{ {
public: public:
SQueue<DemuxerTask, 32> job; squeue_t<DemuxerTask, 32> job;
const u32 memAddr; const u32 memAddr;
const u32 memSize; const u32 memSize;
const vm::ptr<CellDmuxCbMsg> cbFunc; const vm::ptr<CellDmuxCbMsg> cbFunc;
@@ -436,7 +427,7 @@ class ElementaryStream
{ {
std::mutex m_mutex; std::mutex m_mutex;
SQueue<u32> entries; // AU starting addresses squeue_t<u32> entries; // AU starting addresses
u32 put_count; // number of AU written u32 put_count; // number of AU written
u32 got_count; // number of AU obtained by GetAu(Ex) u32 got_count; // number of AU obtained by GetAu(Ex)
u32 released; // number of AU released u32 released; // number of AU released
@@ -446,6 +437,8 @@ class ElementaryStream
bool is_full(u32 space); bool is_full(u32 space);
public: public:
ElementaryStream(Demuxer* dmux, u32 addr, u32 size, u32 fidMajor, u32 fidMinor, u32 sup1, u32 sup2, vm::ptr<CellDmuxCbEsMsg> cbFunc, u32 cbArg, u32 spec);
Demuxer* dmux; Demuxer* dmux;
u32 id; u32 id;
const u32 memAddr; const u32 memAddr;
@@ -465,27 +458,6 @@ public:
void push(DemuxerStream& stream, u32 size); // called by demuxer thread (not multithread-safe) void push(DemuxerStream& stream, u32 size); // called by demuxer thread (not multithread-safe)
ElementaryStream(Demuxer* dmux, u32 addr, u32 size, u32 fidMajor, u32 fidMinor, u32 sup1, u32 sup2, vm::ptr<CellDmuxCbEsMsg> cbFunc, u32 cbArg, u32 spec)
: dmux(dmux)
, memAddr(a128(addr))
, memSize(size - (addr - memAddr))
, fidMajor(fidMajor)
, fidMinor(fidMinor)
, sup1(sup1)
, sup2(sup2)
, cbFunc(cbFunc)
, cbArg(cbArg)
, spec(spec)
, put(memAddr)
, put_count(0)
, got_count(0)
, released(0)
, raw_pos(0)
, last_dts(0xffffffffffffffffull)
, last_pts(0xffffffffffffffffull)
{
}
bool isfull(u32 space); bool isfull(u32 space);
void push_au(u32 size, u64 dts, u64 pts, u64 userdata, bool rap, u32 specific); void push_au(u32 size, u64 dts, u64 pts, u64 userdata, bool rap, u32 specific);
+2 -4
View File
@@ -385,8 +385,7 @@ int cellFontGetEffectSlant(vm::ptr<CellFont> font, vm::ptr<be_t<float>> slantPar
int cellFontGetFontIdCode(vm::ptr<CellFont> font, u32 code, vm::ptr<u32> fontId, vm::ptr<u32> fontCode) int cellFontGetFontIdCode(vm::ptr<CellFont> font, u32 code, vm::ptr<u32> fontId, vm::ptr<u32> fontCode)
{ {
cellFont->Todo("cellFontGetFontIdCode(font_addr=0x%x, code=0x%x, fontId_addr=0x%x, fontCode_addr=0x%x", cellFont->Todo("cellFontGetFontIdCode(font_addr=0x%x, code=0x%x, fontId_addr=0x%x, fontCode_addr=0x%x)", font.addr(), code, fontId.addr(), fontCode.addr());
font.addr(), code, fontId.addr(), fontCode.addr());
// TODO: ? // TODO: ?
return CELL_FONT_OK; return CELL_FONT_OK;
@@ -406,8 +405,7 @@ int cellFontCloseFont(vm::ptr<CellFont> font)
int cellFontGetCharGlyphMetrics(vm::ptr<CellFont> font, u32 code, vm::ptr<CellFontGlyphMetrics> metrics) int cellFontGetCharGlyphMetrics(vm::ptr<CellFont> font, u32 code, vm::ptr<CellFontGlyphMetrics> metrics)
{ {
cellFont->Log("cellFontGetCharGlyphMetrics(font_addr=0x%x, code=0x%x, metrics_addr=0x%x", cellFont->Log("cellFontGetCharGlyphMetrics(font_addr=0x%x, code=0x%x, metrics_addr=0x%x)", font.addr(), code, metrics.addr());
font.addr(), code, metrics.addr());
int x0, y0, x1, y1; int x0, y0, x1, y1;
int advanceWidth, leftSideBearing; int advanceWidth, leftSideBearing;
+8 -5
View File
@@ -369,7 +369,7 @@ s32 _cellGcmInitBody(vm::ptr<CellGcmContextData> context, u32 cmdSize, u32 ioSiz
u32 ctx_begin = ioAddress/* + 0x1000*/; u32 ctx_begin = ioAddress/* + 0x1000*/;
u32 ctx_size = 0x6ffc; u32 ctx_size = 0x6ffc;
current_context.begin = ctx_begin; current_context.begin = ctx_begin;
current_context.end = ctx_begin + ctx_size; current_context.end = ctx_begin + ctx_size - 4;
current_context.current = current_context.begin; current_context.current = current_context.begin;
current_context.callback.set(be_t<u32>::make(Emu.GetRSXCallback() - 4)); current_context.callback.set(be_t<u32>::make(Emu.GetRSXCallback() - 4));
@@ -805,8 +805,7 @@ s32 cellGcmAddressToOffset(u64 address, vm::ptr<be_t<u32>> offset)
cellGcmSys->Log("cellGcmAddressToOffset(address=0x%x,offset_addr=0x%x)", address, offset.addr()); cellGcmSys->Log("cellGcmAddressToOffset(address=0x%x,offset_addr=0x%x)", address, offset.addr());
// Address not on main memory or local memory // Address not on main memory or local memory
if (!address || address >= 0xD0000000) { if (address >= 0xD0000000) {
cellGcmSys->Error("cellGcmAddressToOffset(address=0x%x,offset_addr=0x%x)", address, offset.addr());
return CELL_GCM_ERROR_FAILURE; return CELL_GCM_ERROR_FAILURE;
} }
@@ -1170,12 +1169,16 @@ s32 cellGcmCallback(vm::ptr<CellGcmContextData> context, u32 count)
{ {
cellGcmSys->Log("cellGcmCallback(context_addr=0x%x, count=0x%x)", context.addr(), count); cellGcmSys->Log("cellGcmCallback(context_addr=0x%x, count=0x%x)", context.addr(), count);
GSLockCurrent gslock(GS_LOCK_WAIT_FLUSH);
if (1) if (1)
{ {
auto& ctrl = vm::get_ref<CellGcmControl>(gcm_info.control_addr); auto& ctrl = vm::get_ref<CellGcmControl>(gcm_info.control_addr);
be_t<u32> res = be_t<u32>::make(context->current - context->begin - ctrl.put.read_relaxed()); be_t<u32> res = be_t<u32>::make(context->current - context->begin - ctrl.put.read_relaxed());
if (res != 0)
{
GSLockCurrent gslock(GS_LOCK_WAIT_FLUSH);
}
memmove(vm::get_ptr<void>(context->begin), vm::get_ptr<void>(context->current - res), res); memmove(vm::get_ptr<void>(context->begin), vm::get_ptr<void>(context->current - res), res);
context->current = context->begin + res; context->current = context->begin + res;
+6 -6
View File
@@ -4,7 +4,7 @@
#include "stblib/stb_image.h" #include "stblib/stb_image.h"
#include "stblib/stb_image.c" // (TODO: Should we put this elsewhere?) #include "stblib/stb_image.c" // (TODO: Should we put this elsewhere?)
#include "Emu/SysCalls/lv2/lv2Fs.h" #include "Emu/SysCalls/lv2/cellFs.h"
#include "cellGifDec.h" #include "cellGifDec.h"
Module *cellGifDec = nullptr; Module *cellGifDec = nullptr;
@@ -26,7 +26,7 @@ int cellGifDecOpen(u32 mainHandle, vm::ptr<u32> subHandle, vm::ptr<CellGifDecSrc
cellGifDec->Warning("cellGifDecOpen(mainHandle=0x%x, subHandle_addr=0x%x, src_addr=0x%x, openInfo_addr=0x%x)", cellGifDec->Warning("cellGifDecOpen(mainHandle=0x%x, subHandle_addr=0x%x, src_addr=0x%x, openInfo_addr=0x%x)",
mainHandle, subHandle.addr(), src.addr(), openInfo.addr()); mainHandle, subHandle.addr(), src.addr(), openInfo.addr());
CellGifDecSubHandle *current_subHandle = new CellGifDecSubHandle; std::shared_ptr<CellGifDecSubHandle> current_subHandle(new CellGifDecSubHandle);
current_subHandle->fd = 0; current_subHandle->fd = 0;
current_subHandle->src = *src; current_subHandle->src = *src;
@@ -62,7 +62,7 @@ int cellGifDecReadHeader(u32 mainHandle, u32 subHandle, vm::ptr<CellGifDecInfo>
cellGifDec->Warning("cellGifDecReadHeader(mainHandle=0x%x, subHandle=0x%x, info_addr=0x%x)", cellGifDec->Warning("cellGifDecReadHeader(mainHandle=0x%x, subHandle=0x%x, info_addr=0x%x)",
mainHandle, subHandle, info.addr()); mainHandle, subHandle, info.addr());
CellGifDecSubHandle* subHandle_data; std::shared_ptr<CellGifDecSubHandle> subHandle_data;
if(!cellGifDec->CheckId(subHandle, subHandle_data)) if(!cellGifDec->CheckId(subHandle, subHandle_data))
return CELL_GIFDEC_ERROR_FATAL; return CELL_GIFDEC_ERROR_FATAL;
@@ -112,7 +112,7 @@ int cellGifDecSetParameter(u32 mainHandle, u32 subHandle, vm::ptr<const CellGifD
cellGifDec->Warning("cellGifDecSetParameter(mainHandle=0x%x, subHandle=0x%x, inParam_addr=0x%x, outParam_addr=0x%x)", cellGifDec->Warning("cellGifDecSetParameter(mainHandle=0x%x, subHandle=0x%x, inParam_addr=0x%x, outParam_addr=0x%x)",
mainHandle, subHandle, inParam.addr(), outParam.addr()); mainHandle, subHandle, inParam.addr(), outParam.addr());
CellGifDecSubHandle* subHandle_data; std::shared_ptr<CellGifDecSubHandle> subHandle_data;
if(!cellGifDec->CheckId(subHandle, subHandle_data)) if(!cellGifDec->CheckId(subHandle, subHandle_data))
return CELL_GIFDEC_ERROR_FATAL; return CELL_GIFDEC_ERROR_FATAL;
@@ -144,7 +144,7 @@ int cellGifDecDecodeData(u32 mainHandle, u32 subHandle, vm::ptr<u8> data, vm::pt
dataOutInfo->status = CELL_GIFDEC_DEC_STATUS_STOP; dataOutInfo->status = CELL_GIFDEC_DEC_STATUS_STOP;
CellGifDecSubHandle* subHandle_data; std::shared_ptr<CellGifDecSubHandle> subHandle_data;
if(!cellGifDec->CheckId(subHandle, subHandle_data)) if(!cellGifDec->CheckId(subHandle, subHandle_data))
return CELL_GIFDEC_ERROR_FATAL; return CELL_GIFDEC_ERROR_FATAL;
@@ -259,7 +259,7 @@ int cellGifDecClose(u32 mainHandle, u32 subHandle)
cellGifDec->Warning("cellGifDecClose(mainHandle=0x%x, subHandle=0x%x)", cellGifDec->Warning("cellGifDecClose(mainHandle=0x%x, subHandle=0x%x)",
mainHandle, subHandle); mainHandle, subHandle);
CellGifDecSubHandle* subHandle_data; std::shared_ptr<CellGifDecSubHandle> subHandle_data;
if(!cellGifDec->CheckId(subHandle, subHandle_data)) if(!cellGifDec->CheckId(subHandle, subHandle_data))
return CELL_GIFDEC_ERROR_FATAL; return CELL_GIFDEC_ERROR_FATAL;
+6 -6
View File
@@ -3,7 +3,7 @@
#include "Emu/SysCalls/Modules.h" #include "Emu/SysCalls/Modules.h"
#include "stblib/stb_image.h" #include "stblib/stb_image.h"
#include "Emu/SysCalls/lv2/lv2Fs.h" #include "Emu/SysCalls/lv2/cellFs.h"
#include "cellJpgDec.h" #include "cellJpgDec.h"
Module *cellJpgDec = nullptr; Module *cellJpgDec = nullptr;
@@ -31,7 +31,7 @@ int cellJpgDecOpen(u32 mainHandle, vm::ptr<u32> subHandle, vm::ptr<CellJpgDecSrc
cellJpgDec->Warning("cellJpgDecOpen(mainHandle=0x%x, subHandle_addr=0x%x, src_addr=0x%x, openInfo_addr=0x%x)", cellJpgDec->Warning("cellJpgDecOpen(mainHandle=0x%x, subHandle_addr=0x%x, src_addr=0x%x, openInfo_addr=0x%x)",
mainHandle, subHandle.addr(), src.addr(), openInfo.addr()); mainHandle, subHandle.addr(), src.addr(), openInfo.addr());
CellJpgDecSubHandle *current_subHandle = new CellJpgDecSubHandle; std::shared_ptr<CellJpgDecSubHandle> current_subHandle(new CellJpgDecSubHandle);
current_subHandle->fd = 0; current_subHandle->fd = 0;
current_subHandle->src = *src; current_subHandle->src = *src;
@@ -68,7 +68,7 @@ int cellJpgDecClose(u32 mainHandle, u32 subHandle)
cellJpgDec->Warning("cellJpgDecOpen(mainHandle=0x%x, subHandle=0x%x)", cellJpgDec->Warning("cellJpgDecOpen(mainHandle=0x%x, subHandle=0x%x)",
mainHandle, subHandle); mainHandle, subHandle);
CellJpgDecSubHandle* subHandle_data; std::shared_ptr<CellJpgDecSubHandle> subHandle_data;
if(!cellJpgDec->CheckId(subHandle, subHandle_data)) if(!cellJpgDec->CheckId(subHandle, subHandle_data))
return CELL_JPGDEC_ERROR_FATAL; return CELL_JPGDEC_ERROR_FATAL;
@@ -82,7 +82,7 @@ int cellJpgDecReadHeader(u32 mainHandle, u32 subHandle, vm::ptr<CellJpgDecInfo>
{ {
cellJpgDec->Log("cellJpgDecReadHeader(mainHandle=0x%x, subHandle=0x%x, info_addr=0x%x)", mainHandle, subHandle, info.addr()); cellJpgDec->Log("cellJpgDecReadHeader(mainHandle=0x%x, subHandle=0x%x, info_addr=0x%x)", mainHandle, subHandle, info.addr());
CellJpgDecSubHandle* subHandle_data; std::shared_ptr<CellJpgDecSubHandle> subHandle_data;
if(!cellJpgDec->CheckId(subHandle, subHandle_data)) if(!cellJpgDec->CheckId(subHandle, subHandle_data))
return CELL_JPGDEC_ERROR_FATAL; return CELL_JPGDEC_ERROR_FATAL;
@@ -151,7 +151,7 @@ int cellJpgDecDecodeData(u32 mainHandle, u32 subHandle, vm::ptr<u8> data, vm::pt
mainHandle, subHandle, data.addr(), dataCtrlParam.addr(), dataOutInfo.addr()); mainHandle, subHandle, data.addr(), dataCtrlParam.addr(), dataOutInfo.addr());
dataOutInfo->status = CELL_JPGDEC_DEC_STATUS_STOP; dataOutInfo->status = CELL_JPGDEC_DEC_STATUS_STOP;
CellJpgDecSubHandle* subHandle_data; std::shared_ptr<CellJpgDecSubHandle> subHandle_data;
if(!cellJpgDec->CheckId(subHandle, subHandle_data)) if(!cellJpgDec->CheckId(subHandle, subHandle_data))
return CELL_JPGDEC_ERROR_FATAL; return CELL_JPGDEC_ERROR_FATAL;
@@ -281,7 +281,7 @@ int cellJpgDecSetParameter(u32 mainHandle, u32 subHandle, vm::ptr<const CellJpgD
cellJpgDec->Log("cellJpgDecSetParameter(mainHandle=0x%x, subHandle=0x%x, inParam_addr=0x%x, outParam_addr=0x%x)", cellJpgDec->Log("cellJpgDecSetParameter(mainHandle=0x%x, subHandle=0x%x, inParam_addr=0x%x, outParam_addr=0x%x)",
mainHandle, subHandle, inParam.addr(), outParam.addr()); mainHandle, subHandle, inParam.addr(), outParam.addr());
CellJpgDecSubHandle* subHandle_data; std::shared_ptr<CellJpgDecSubHandle> subHandle_data;
if(!cellJpgDec->CheckId(subHandle, subHandle_data)) if(!cellJpgDec->CheckId(subHandle, subHandle_data))
return CELL_JPGDEC_ERROR_FATAL; return CELL_JPGDEC_ERROR_FATAL;
+73 -38
View File
@@ -32,29 +32,13 @@ MsgDialogProgressBarSetMsgCb MsgDialogProgressBarSetMsg = nullptr;
MsgDialogProgressBarResetCb MsgDialogProgressBarReset = nullptr; MsgDialogProgressBarResetCb MsgDialogProgressBarReset = nullptr;
MsgDialogProgressBarIncCb MsgDialogProgressBarInc = nullptr; MsgDialogProgressBarIncCb MsgDialogProgressBarInc = nullptr;
void SetMsgDialogCreateCallback(MsgDialogCreateCb cb) void SetMsgDialogCallbacks(MsgDialogCreateCb ccb, MsgDialogDestroyCb dcb, MsgDialogProgressBarSetMsgCb pbscb, MsgDialogProgressBarResetCb pbrcb, MsgDialogProgressBarIncCb pbicb)
{ {
MsgDialogCreate = cb; MsgDialogCreate = ccb;
} MsgDialogDestroy = dcb;
MsgDialogProgressBarSetMsg = pbscb;
void SetMsgDialogDestroyCallback(MsgDialogDestroyCb cb) MsgDialogProgressBarReset = pbrcb;
{ MsgDialogProgressBarInc = pbicb;
MsgDialogDestroy = cb;
}
void SetMsgDialogProgressBarSetMsgCallback(MsgDialogProgressBarSetMsgCb cb)
{
MsgDialogProgressBarSetMsg = cb;
}
void SetMsgDialogProgressBarResetCallback(MsgDialogProgressBarResetCb cb)
{
MsgDialogProgressBarReset = cb;
}
void SetMsgDialogProgressBarIncCallback(MsgDialogProgressBarIncCb cb)
{
MsgDialogProgressBarInc = cb;
} }
void MsgDialogClose() void MsgDialogClose()
@@ -63,13 +47,64 @@ void MsgDialogClose()
g_msg_dialog_wait_until = get_system_time(); g_msg_dialog_wait_until = get_system_time();
} }
int cellMsgDialogOpen2(u32 type, vm::ptr<const char> msgString, vm::ptr<CellMsgDialogCallback> callback, u32 userData, u32 extParam) s32 cellMsgDialogOpen2(u32 type, vm::ptr<const char> msgString, vm::ptr<CellMsgDialogCallback> callback, u32 userData, u32 extParam)
{ {
cellSysutil->Warning("cellMsgDialogOpen2(type=0x%x, msgString_addr=0x%x, callback_addr=0x%x, userData=0x%x, extParam=0x%x)", cellSysutil->Warning("cellMsgDialogOpen2(type=0x%x, msgString_addr=0x%x, callback_addr=0x%x, userData=0x%x, extParam=0x%x)",
type, msgString.addr(), callback.addr(), userData, extParam); type, msgString.addr(), callback.addr(), userData, extParam);
//type |= CELL_MSGDIALOG_TYPE_PROGRESSBAR_SINGLE | CELL_MSGDIALOG_TYPE_BG_INVISIBLE; if (!msgString || strlen(msgString.get_ptr()) >= 0x200 || type & -0x33f8)
//type |= CELL_MSGDIALOG_TYPE_BUTTON_TYPE_YESNO | CELL_MSGDIALOG_TYPE_DEFAULT_CURSOR_NO; {
return CELL_MSGDIALOG_ERROR_PARAM;
}
switch (type & CELL_MSGDIALOG_TYPE_BUTTON_TYPE)
{
case CELL_MSGDIALOG_TYPE_BUTTON_TYPE_NONE:
{
if (type & CELL_MSGDIALOG_TYPE_DEFAULT_CURSOR)
{
return CELL_MSGDIALOG_ERROR_PARAM;
}
switch (type & CELL_MSGDIALOG_TYPE_PROGRESSBAR)
{
case CELL_MSGDIALOG_TYPE_PROGRESSBAR_NONE: break;
case CELL_MSGDIALOG_TYPE_PROGRESSBAR_SINGLE: break;
case CELL_MSGDIALOG_TYPE_PROGRESSBAR_DOUBLE: break;
default: return CELL_MSGDIALOG_ERROR_PARAM;
}
break;
}
case CELL_MSGDIALOG_TYPE_BUTTON_TYPE_YESNO:
{
switch (type & CELL_MSGDIALOG_TYPE_DEFAULT_CURSOR)
{
case CELL_MSGDIALOG_TYPE_DEFAULT_CURSOR_YES: break;
case CELL_MSGDIALOG_TYPE_DEFAULT_CURSOR_NO: break;
default: return CELL_MSGDIALOG_ERROR_PARAM;
}
if (type & CELL_MSGDIALOG_TYPE_PROGRESSBAR)
{
return CELL_MSGDIALOG_ERROR_PARAM;
}
break;
}
case CELL_MSGDIALOG_TYPE_BUTTON_TYPE_OK:
{
if (type & CELL_MSGDIALOG_TYPE_DEFAULT_CURSOR)
{
return CELL_MSGDIALOG_ERROR_PARAM;
}
if (type & CELL_MSGDIALOG_TYPE_PROGRESSBAR)
{
return CELL_MSGDIALOG_ERROR_PARAM;
}
break;
}
default: return CELL_MSGDIALOG_ERROR_PARAM;
}
MsgDialogState old = msgDialogNone; MsgDialogState old = msgDialogNone;
if (!g_msg_dialog_state.compare_exchange_strong(old, msgDialogOpen)) if (!g_msg_dialog_state.compare_exchange_strong(old, msgDialogOpen))
@@ -83,7 +118,7 @@ int cellMsgDialogOpen2(u32 type, vm::ptr<const char> msgString, vm::ptr<CellMsgD
{ {
case CELL_MSGDIALOG_TYPE_PROGRESSBAR_DOUBLE: g_msg_dialog_progress_bar_count = 2; break; case CELL_MSGDIALOG_TYPE_PROGRESSBAR_DOUBLE: g_msg_dialog_progress_bar_count = 2; break;
case CELL_MSGDIALOG_TYPE_PROGRESSBAR_SINGLE: g_msg_dialog_progress_bar_count = 1; break; case CELL_MSGDIALOG_TYPE_PROGRESSBAR_SINGLE: g_msg_dialog_progress_bar_count = 1; break;
default: g_msg_dialog_progress_bar_count = 0; break; // ??? default: g_msg_dialog_progress_bar_count = 0; break;
} }
std::string msg = msgString.get_ptr(); std::string msg = msgString.get_ptr();
@@ -121,7 +156,7 @@ int cellMsgDialogOpen2(u32 type, vm::ptr<const char> msgString, vm::ptr<CellMsgD
cellSysutil->Warning("MsgDialog thread aborted"); cellSysutil->Warning("MsgDialog thread aborted");
return; return;
} }
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
} }
while (g_msg_dialog_state == msgDialogOpen || (s64)(get_system_time() - g_msg_dialog_wait_until) < 0) while (g_msg_dialog_state == msgDialogOpen || (s64)(get_system_time() - g_msg_dialog_wait_until) < 0)
@@ -131,7 +166,7 @@ int cellMsgDialogOpen2(u32 type, vm::ptr<const char> msgString, vm::ptr<CellMsgD
g_msg_dialog_state = msgDialogAbort; g_msg_dialog_state = msgDialogAbort;
break; break;
} }
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
} }
if (callback && (g_msg_dialog_state != msgDialogAbort)) if (callback && (g_msg_dialog_state != msgDialogAbort))
@@ -156,7 +191,7 @@ int cellMsgDialogOpen2(u32 type, vm::ptr<const char> msgString, vm::ptr<CellMsgD
return CELL_OK; return CELL_OK;
} }
int cellMsgDialogOpenErrorCode(u32 errorCode, vm::ptr<CellMsgDialogCallback> callback, u32 userData, u32 extParam) s32 cellMsgDialogOpenErrorCode(u32 errorCode, vm::ptr<CellMsgDialogCallback> callback, u32 userData, u32 extParam)
{ {
cellSysutil->Warning("cellMsgDialogOpenErrorCode(errorCode=0x%x, callback_addr=0x%x, userData=0x%x, extParam=%d)", cellSysutil->Warning("cellMsgDialogOpenErrorCode(errorCode=0x%x, callback_addr=0x%x, userData=0x%x, extParam=%d)",
errorCode, callback.addr(), userData, extParam); errorCode, callback.addr(), userData, extParam);
@@ -174,15 +209,15 @@ int cellMsgDialogOpenErrorCode(u32 errorCode, vm::ptr<CellMsgDialogCallback> cal
case 0x80010007: errorMessage = "The file is in unrecognized format / The file is not a valid ELF file."; break; case 0x80010007: errorMessage = "The file is in unrecognized format / The file is not a valid ELF file."; break;
case 0x80010008: errorMessage = "Resource deadlock is avoided."; break; case 0x80010008: errorMessage = "Resource deadlock is avoided."; break;
case 0x80010009: errorMessage = "Operation not permitted."; break; case 0x80010009: errorMessage = "Operation not permitted."; break;
case 0x8001000A: errorMessage = "The device or resource is bus."; break; case 0x8001000A: errorMessage = "The device or resource is busy."; break;
case 0x8001000B: errorMessage = "The operation is timed ou."; break; case 0x8001000B: errorMessage = "The operation is timed out."; break;
case 0x8001000C: errorMessage = "The operation is aborte."; break; case 0x8001000C: errorMessage = "The operation is aborted."; break;
case 0x8001000D: errorMessage = "Invalid memory access."; break; case 0x8001000D: errorMessage = "Invalid memory access."; break;
case 0x8001000F: errorMessage = "State of the target thread is invalid."; break; case 0x8001000F: errorMessage = "State of the target thread is invalid."; break;
case 0x80010010: errorMessage = "Alignment is invalid."; break; case 0x80010010: errorMessage = "Alignment is invalid."; break;
case 0x80010011: errorMessage = "Shortage of the kernel resources."; break; case 0x80010011: errorMessage = "Shortage of the kernel resources."; break;
case 0x80010012: errorMessage = "The file is a directory."; break; case 0x80010012: errorMessage = "The file is a directory."; break;
case 0x80010013: errorMessage = "Operation canceled."; break; case 0x80010013: errorMessage = "Operation cancelled."; break;
case 0x80010014: errorMessage = "Entry already exists."; break; case 0x80010014: errorMessage = "Entry already exists."; break;
case 0x80010015: errorMessage = "Port is already connected."; break; case 0x80010015: errorMessage = "Port is already connected."; break;
case 0x80010016: errorMessage = "Port is not connected."; break; case 0x80010016: errorMessage = "Port is not connected."; break;
@@ -255,7 +290,7 @@ int cellMsgDialogOpenErrorCode(u32 errorCode, vm::ptr<CellMsgDialogCallback> cal
return CELL_OK; return CELL_OK;
} }
int cellMsgDialogClose(float delay) s32 cellMsgDialogClose(float delay)
{ {
cellSysutil->Warning("cellMsgDialogClose(delay=%f)", delay); cellSysutil->Warning("cellMsgDialogClose(delay=%f)", delay);
@@ -277,7 +312,7 @@ int cellMsgDialogClose(float delay)
return CELL_OK; return CELL_OK;
} }
int cellMsgDialogAbort() s32 cellMsgDialogAbort()
{ {
cellSysutil->Warning("cellMsgDialogAbort()"); cellSysutil->Warning("cellMsgDialogAbort()");
@@ -298,7 +333,7 @@ int cellMsgDialogAbort()
return CELL_OK; return CELL_OK;
} }
int cellMsgDialogProgressBarSetMsg(u32 progressBarIndex, vm::ptr<const char> msgString) s32 cellMsgDialogProgressBarSetMsg(u32 progressBarIndex, vm::ptr<const char> msgString)
{ {
cellSysutil->Warning("cellMsgDialogProgressBarSetMsg(progressBarIndex=%d, msgString_addr=0x%x ['%s'])", cellSysutil->Warning("cellMsgDialogProgressBarSetMsg(progressBarIndex=%d, msgString_addr=0x%x ['%s'])",
progressBarIndex, msgString.addr(), msgString.get_ptr()); progressBarIndex, msgString.addr(), msgString.get_ptr());
@@ -322,7 +357,7 @@ int cellMsgDialogProgressBarSetMsg(u32 progressBarIndex, vm::ptr<const char> msg
return CELL_OK; return CELL_OK;
} }
int cellMsgDialogProgressBarReset(u32 progressBarIndex) s32 cellMsgDialogProgressBarReset(u32 progressBarIndex)
{ {
cellSysutil->Warning("cellMsgDialogProgressBarReset(progressBarIndex=%d)", progressBarIndex); cellSysutil->Warning("cellMsgDialogProgressBarReset(progressBarIndex=%d)", progressBarIndex);
@@ -343,7 +378,7 @@ int cellMsgDialogProgressBarReset(u32 progressBarIndex)
return CELL_OK; return CELL_OK;
} }
int cellMsgDialogProgressBarInc(u32 progressBarIndex, u32 delta) s32 cellMsgDialogProgressBarInc(u32 progressBarIndex, u32 delta)
{ {
cellSysutil->Warning("cellMsgDialogProgressBarInc(progressBarIndex=%d, delta=%d)", progressBarIndex, delta); cellSysutil->Warning("cellMsgDialogProgressBarInc(progressBarIndex=%d, delta=%d)", progressBarIndex, delta);
+15 -20
View File
@@ -18,28 +18,28 @@ enum CellMsgDialogType
enum enum
{ {
CELL_MSGDIALOG_TYPE_SE_TYPE = 1 << 0, CELL_MSGDIALOG_TYPE_SE_TYPE = 0x1,
CELL_MSGDIALOG_TYPE_SE_TYPE_ERROR = 0 << 0, CELL_MSGDIALOG_TYPE_SE_TYPE_ERROR = 0 << 0,
CELL_MSGDIALOG_TYPE_SE_TYPE_NORMAL = 1 << 0, CELL_MSGDIALOG_TYPE_SE_TYPE_NORMAL = 1 << 0,
}; };
enum enum
{ {
CELL_MSGDIALOG_TYPE_SE_MUTE = 1 << 1, CELL_MSGDIALOG_TYPE_SE_MUTE = 0x2,
CELL_MSGDIALOG_TYPE_SE_MUTE_OFF = 0 << 1, CELL_MSGDIALOG_TYPE_SE_MUTE_OFF = 0 << 1,
CELL_MSGDIALOG_TYPE_SE_MUTE_ON = 1 << 1, CELL_MSGDIALOG_TYPE_SE_MUTE_ON = 1 << 1,
}; };
enum enum
{ {
CELL_MSGDIALOG_TYPE_BG = 1 << 2, CELL_MSGDIALOG_TYPE_BG = 0x4,
CELL_MSGDIALOG_TYPE_BG_VISIBLE = 0 << 2, CELL_MSGDIALOG_TYPE_BG_VISIBLE = 0 << 2,
CELL_MSGDIALOG_TYPE_BG_INVISIBLE = 1 << 2, CELL_MSGDIALOG_TYPE_BG_INVISIBLE = 1 << 2,
}; };
enum enum
{ {
CELL_MSGDIALOG_TYPE_BUTTON_TYPE = 3 << 4, CELL_MSGDIALOG_TYPE_BUTTON_TYPE = 0x70,
CELL_MSGDIALOG_TYPE_BUTTON_TYPE_NONE = 0 << 4, CELL_MSGDIALOG_TYPE_BUTTON_TYPE_NONE = 0 << 4,
CELL_MSGDIALOG_TYPE_BUTTON_TYPE_YESNO = 1 << 4, CELL_MSGDIALOG_TYPE_BUTTON_TYPE_YESNO = 1 << 4,
CELL_MSGDIALOG_TYPE_BUTTON_TYPE_OK = 2 << 4, CELL_MSGDIALOG_TYPE_BUTTON_TYPE_OK = 2 << 4,
@@ -47,14 +47,14 @@ enum
enum enum
{ {
CELL_MSGDIALOG_TYPE_DISABLE_CANCEL = 1 << 7, CELL_MSGDIALOG_TYPE_DISABLE_CANCEL = 0x80,
CELL_MSGDIALOG_TYPE_DISABLE_CANCEL_OFF = 0 << 7, CELL_MSGDIALOG_TYPE_DISABLE_CANCEL_OFF = 0 << 7,
CELL_MSGDIALOG_TYPE_DISABLE_CANCEL_ON = 1 << 7, CELL_MSGDIALOG_TYPE_DISABLE_CANCEL_ON = 1 << 7,
}; };
enum enum
{ {
CELL_MSGDIALOG_TYPE_DEFAULT_CURSOR = 1 << 8, CELL_MSGDIALOG_TYPE_DEFAULT_CURSOR = 0x300,
CELL_MSGDIALOG_TYPE_DEFAULT_CURSOR_NONE = 0 << 8, CELL_MSGDIALOG_TYPE_DEFAULT_CURSOR_NONE = 0 << 8,
CELL_MSGDIALOG_TYPE_DEFAULT_CURSOR_YES = 0 << 8, CELL_MSGDIALOG_TYPE_DEFAULT_CURSOR_YES = 0 << 8,
CELL_MSGDIALOG_TYPE_DEFAULT_CURSOR_NO = 1 << 8, CELL_MSGDIALOG_TYPE_DEFAULT_CURSOR_NO = 1 << 8,
@@ -63,7 +63,7 @@ enum
enum enum
{ {
CELL_MSGDIALOG_TYPE_PROGRESSBAR = 3 << 12, CELL_MSGDIALOG_TYPE_PROGRESSBAR = 0x3000,
CELL_MSGDIALOG_TYPE_PROGRESSBAR_NONE = 0 << 12, CELL_MSGDIALOG_TYPE_PROGRESSBAR_NONE = 0 << 12,
CELL_MSGDIALOG_TYPE_PROGRESSBAR_SINGLE = 1 << 12, CELL_MSGDIALOG_TYPE_PROGRESSBAR_SINGLE = 1 << 12,
CELL_MSGDIALOG_TYPE_PROGRESSBAR_DOUBLE = 2 << 12, CELL_MSGDIALOG_TYPE_PROGRESSBAR_DOUBLE = 2 << 12,
@@ -81,14 +81,14 @@ enum
typedef void(*CellMsgDialogCallback)(s32 buttonType, u32 userData); typedef void(*CellMsgDialogCallback)(s32 buttonType, u32 userData);
int cellMsgDialogOpen2(u32 type, vm::ptr<const char> msgString, vm::ptr<CellMsgDialogCallback> callback, u32 userData, u32 extParam); s32 cellMsgDialogOpen2(u32 type, vm::ptr<const char> msgString, vm::ptr<CellMsgDialogCallback> callback, u32 userData, u32 extParam);
int cellMsgDialogOpenErrorCode(u32 errorCode, vm::ptr<CellMsgDialogCallback> callback, u32 userData, u32 extParam); s32 cellMsgDialogOpenErrorCode(u32 errorCode, vm::ptr<CellMsgDialogCallback> callback, u32 userData, u32 extParam);
int cellMsgDialogProgressBarSetMsg(u32 progressBarIndex, vm::ptr<const char> msgString); s32 cellMsgDialogProgressBarSetMsg(u32 progressBarIndex, vm::ptr<const char> msgString);
int cellMsgDialogProgressBarReset(u32 progressBarIndex); s32 cellMsgDialogProgressBarReset(u32 progressBarIndex);
int cellMsgDialogProgressBarInc(u32 progressBarIndex, u32 delta); s32 cellMsgDialogProgressBarInc(u32 progressBarIndex, u32 delta);
int cellMsgDialogClose(float delay); s32 cellMsgDialogClose(float delay);
int cellMsgDialogAbort(); s32 cellMsgDialogAbort();
typedef void(*MsgDialogCreateCb)(u32 type, const char* msg, u64& status); typedef void(*MsgDialogCreateCb)(u32 type, const char* msg, u64& status);
typedef void(*MsgDialogDestroyCb)(); typedef void(*MsgDialogDestroyCb)();
@@ -96,10 +96,5 @@ typedef void(*MsgDialogProgressBarSetMsgCb)(u32 progressBarIndex, const char* ms
typedef void(*MsgDialogProgressBarResetCb)(u32 progressBarIndex); typedef void(*MsgDialogProgressBarResetCb)(u32 progressBarIndex);
typedef void(*MsgDialogProgressBarIncCb)(u32 progressBarIndex, u32 delta); typedef void(*MsgDialogProgressBarIncCb)(u32 progressBarIndex, u32 delta);
void SetMsgDialogCreateCallback(MsgDialogCreateCb cb); void SetMsgDialogCallbacks(MsgDialogCreateCb ccb, MsgDialogDestroyCb dcb, MsgDialogProgressBarSetMsgCb pbscb, MsgDialogProgressBarResetCb pbrcb, MsgDialogProgressBarIncCb pbicb);
void SetMsgDialogDestroyCallback(MsgDialogDestroyCb cb);
void SetMsgDialogProgressBarSetMsgCallback(MsgDialogProgressBarSetMsgCb cb);
void SetMsgDialogProgressBarResetCallback(MsgDialogProgressBarResetCb cb);
void SetMsgDialogProgressBarIncCallback(MsgDialogProgressBarIncCb cb);
void MsgDialogClose(); void MsgDialogClose();
+27 -3
View File
@@ -54,16 +54,39 @@ int cellPadClearBuf(u32 port_no)
return CELL_OK; return CELL_OK;
} }
int cellPadPeriphGetInfo(vm::ptr<CellPadPeriphInfo> info)
{
sys_io->Warning("cellPadPeriphGetInfo(info_addr=0x%x)", info.addr());
// TODO: Support other types of controllers
for (int i = 0; i < info->now_connect; i++)
{
info->pclass_type[i] = CELL_PAD_PCLASS_TYPE_STANDARD;
}
return CELL_OK;
}
int cellPadGetData(u32 port_no, vm::ptr<CellPadData> data) int cellPadGetData(u32 port_no, vm::ptr<CellPadData> data)
{ {
sys_io->Log("cellPadGetData(port_no=%d, data_addr=0x%x)", port_no, data.addr()); sys_io->Log("cellPadGetData(port_no=%d, data_addr=0x%x)", port_no, data.addr());
std::vector<Pad>& pads = Emu.GetPadManager().GetPads(); std::vector<Pad>& pads = Emu.GetPadManager().GetPads();
if(!Emu.GetPadManager().IsInited()) return CELL_PAD_ERROR_UNINITIALIZED;
if (!Emu.GetPadManager().IsInited()) {
return CELL_PAD_ERROR_UNINITIALIZED;
}
const PadInfo& rinfo = Emu.GetPadManager().GetInfo(); const PadInfo& rinfo = Emu.GetPadManager().GetInfo();
if(port_no >= rinfo.max_connect) return CELL_PAD_ERROR_INVALID_PARAMETER;
if (port_no >= rinfo.max_connect) {
return CELL_PAD_ERROR_INVALID_PARAMETER;
}
//We have a choice here of NO_DEVICE or READ_FAILED...lets try no device for now //We have a choice here of NO_DEVICE or READ_FAILED...lets try no device for now
if(port_no >= rinfo.now_connect) return CELL_PAD_ERROR_NO_DEVICE; if (port_no >= rinfo.now_connect) {
return CELL_PAD_ERROR_NO_DEVICE;
}
Pad& pad = pads[port_no]; Pad& pad = pads[port_no];
@@ -409,6 +432,7 @@ void cellPad_init()
sys_io->AddFunc(0xf65544ee, cellPadSetActDirect); sys_io->AddFunc(0xf65544ee, cellPadSetActDirect);
sys_io->AddFunc(0x3aaad464, cellPadGetInfo); sys_io->AddFunc(0x3aaad464, cellPadGetInfo);
sys_io->AddFunc(0xa703a51d, cellPadGetInfo2); sys_io->AddFunc(0xa703a51d, cellPadGetInfo2);
sys_io->AddFunc(0x4cc9b68d, cellPadPeriphGetInfo);
sys_io->AddFunc(0x578e3c98, cellPadSetPortSetting); sys_io->AddFunc(0x578e3c98, cellPadSetPortSetting);
sys_io->AddFunc(0x0e2dfaad, cellPadInfoPressMode); sys_io->AddFunc(0x0e2dfaad, cellPadInfoPressMode);
sys_io->AddFunc(0x78200559, cellPadInfoSensorMode); sys_io->AddFunc(0x78200559, cellPadInfoSensorMode);
+24
View File
@@ -14,6 +14,17 @@ enum CELL_PAD_ERROR_CODE
CELL_PAD_ERROR_EBUSY = 0x8012110a, CELL_PAD_ERROR_EBUSY = 0x8012110a,
}; };
// Controller types
enum
{
CELL_PAD_PCLASS_TYPE_STANDARD = 0x00,
CELL_PAD_PCLASS_TYPE_GUITAR = 0x01,
CELL_PAD_PCLASS_TYPE_DRUM = 0x02,
CELL_PAD_PCLASS_TYPE_DJ = 0x03,
CELL_PAD_PCLASS_TYPE_DANCEMAT = 0x04,
CELL_PAD_PCLASS_TYPE_NAVIGATION = 0x05,
};
struct CellPadData struct CellPadData
{ {
be_t<s32> len; be_t<s32> len;
@@ -41,6 +52,19 @@ struct CellPadInfo2
be_t<u32> device_type[CELL_PAD_MAX_PORT_NUM]; be_t<u32> device_type[CELL_PAD_MAX_PORT_NUM];
}; };
struct CellPadPeriphInfo
{
be_t<u32> max_connect;
be_t<u32> now_connect;
be_t<u32> system_info;
be_t<u32> port_status[CELL_PAD_MAX_PORT_NUM];
be_t<u32> port_setting[CELL_PAD_MAX_PORT_NUM];
be_t<u32> device_capability[CELL_PAD_MAX_PORT_NUM];
be_t<u32> device_type[CELL_PAD_MAX_PORT_NUM];
be_t<u32> pclass_type[CELL_PAD_MAX_PORT_NUM];
be_t<u32> pclass_profile[CELL_PAD_MAX_PORT_NUM];
};
struct CellCapabilityInfo struct CellCapabilityInfo
{ {
be_t<u32> info[CELL_PAD_MAX_CAPABILITY_INFO]; be_t<u32> info[CELL_PAD_MAX_CAPABILITY_INFO];
+407 -236
View File
@@ -1,157 +1,203 @@
#include "stdafx.h" #include "stdafx.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "Emu/SysCalls/Modules.h" #include "Emu/SysCalls/Modules.h"
#include "cellPamf.h" #include "cellPamf.h"
Module *cellPamf = nullptr; Module *cellPamf = nullptr;
int pamfStreamTypeToEsFilterId(u8 type, u8 ch, vm::ptr<CellCodecEsFilterId> pEsFilterId) s32 pamfStreamTypeToEsFilterId(u8 type, u8 ch, CellCodecEsFilterId& pEsFilterId)
{ {
//TODO: convert type and ch to EsFilterId // convert type and ch to EsFilterId
pEsFilterId->filterIdMajor = 0; assert(ch < 16);
pEsFilterId->filterIdMinor = 0; pEsFilterId.supplementalInfo1 = type == CELL_PAMF_STREAM_TYPE_AVC;
pEsFilterId->supplementalInfo1 = 0; pEsFilterId.supplementalInfo2 = 0;
pEsFilterId->supplementalInfo2 = 0;
switch (type) switch (type)
{ {
case CELL_PAMF_STREAM_TYPE_AVC: case CELL_PAMF_STREAM_TYPE_AVC:
{ {
if (ch < 16) // code = 0x1b
{ pEsFilterId.filterIdMajor = 0xe0 | ch;
pEsFilterId->filterIdMajor = 0xe0 + ch; pEsFilterId.filterIdMinor = 0;
pEsFilterId->filterIdMinor = 0;
pEsFilterId->supplementalInfo1 = 0x01;
pEsFilterId->supplementalInfo2 = 0;
}
else
cellPamf->Error("pamfStreamTypeToEsFilterId: invalid CELL_PAMF_STREAM_TYPE_AVC channel (ch=%d)", ch);
}
break; break;
case CELL_PAMF_STREAM_TYPE_ATRAC3PLUS:
if (ch == 0)
{
pEsFilterId->filterIdMajor = 0xbd;
pEsFilterId->filterIdMinor = 0;
pEsFilterId->supplementalInfo1 = 0;
pEsFilterId->supplementalInfo2 = 0;
} }
else
cellPamf->Todo("pamfStreamTypeToEsFilterId: CELL_PAMF_STREAM_TYPE_ATRAC3PLUS (ch=%d)", ch);
break;
case CELL_PAMF_STREAM_TYPE_PAMF_LPCM:
if (ch == 0)
{
pEsFilterId->filterIdMajor = 0xbd;
pEsFilterId->filterIdMinor = 0x40;
pEsFilterId->supplementalInfo1 = 0;
pEsFilterId->supplementalInfo2 = 0;
}
else
cellPamf->Todo("pamfStreamTypeToEsFilterId: CELL_PAMF_STREAM_TYPE_LPCM (ch=%d)", ch);
break;
case CELL_PAMF_STREAM_TYPE_USER_DATA:
if (ch == 0)
{
pEsFilterId->filterIdMajor = 0xbd;
pEsFilterId->filterIdMinor = 0x20;
pEsFilterId->supplementalInfo1 = 0;
pEsFilterId->supplementalInfo2 = 0;
}
else
cellPamf->Todo("pamfStreamTypeToEsFilterId: CELL_PAMF_STREAM_TYPE_USER_DATA (ch=%d)", ch);
break;
case CELL_PAMF_STREAM_TYPE_AC3:
cellPamf->Todo("pamfStreamTypeToEsFilterId: CELL_PAMF_STREAM_TYPE_AC3 (ch=%d)", ch);
break;
case CELL_PAMF_STREAM_TYPE_M2V: case CELL_PAMF_STREAM_TYPE_M2V:
cellPamf->Todo("pamfStreamTypeToEsFilterId: CELL_PAMF_STREAM_TYPE_M2V (ch=%d)", ch); {
// code = 0x02
pEsFilterId.filterIdMajor = 0xe0 | ch;
pEsFilterId.filterIdMinor = 0;
break; break;
}
case CELL_PAMF_STREAM_TYPE_ATRAC3PLUS:
{
// code = 0xdc
pEsFilterId.filterIdMajor = 0xbd;
pEsFilterId.filterIdMinor = ch;
break;
}
case CELL_PAMF_STREAM_TYPE_PAMF_LPCM:
{
// code = 0x80
pEsFilterId.filterIdMajor = 0xbd;
pEsFilterId.filterIdMinor = 0x40 | ch;
break;
}
case CELL_PAMF_STREAM_TYPE_AC3:
{
// code = 0x81
pEsFilterId.filterIdMajor = 0xbd;
pEsFilterId.filterIdMinor = 0x30 | ch;
break;
}
case CELL_PAMF_STREAM_TYPE_USER_DATA:
{
// code = 0xdd
pEsFilterId.filterIdMajor = 0xbd;
pEsFilterId.filterIdMinor = 0x20 | ch;
break;
}
case 6:
{
// code = 0xff
pEsFilterId.filterIdMajor = 0xe0 | ch;
pEsFilterId.filterIdMinor = 0;
break;
}
case 7:
{
// code = 0xff
pEsFilterId.filterIdMajor = 0xbd;
pEsFilterId.filterIdMinor = ch;
break;
}
case 8:
{
// code = 0xff
pEsFilterId.filterIdMajor = 0xbd;
pEsFilterId.filterIdMinor = 0x10 | ch;
break;
}
case 9:
{
// code = 0xff
pEsFilterId.filterIdMajor = 0xbd;
pEsFilterId.filterIdMinor = 0x20 | ch;
break;
}
default: default:
{
cellPamf->Error("pamfStreamTypeToEsFilterId(): unknown type (%d, ch=%d)", type, ch);
Emu.Pause();
return CELL_PAMF_ERROR_INVALID_ARG; return CELL_PAMF_ERROR_INVALID_ARG;
} }
}
return CELL_OK; return CELL_OK;
} }
u8 pamfGetStreamType(vm::ptr<CellPamfReader> pSelf, u8 stream) u8 pamfGetStreamType(vm::ptr<CellPamfReader> pSelf, u32 stream)
{ {
// TODO: get stream type correctly // TODO: get stream type correctly
switch (pSelf->pAddr->stream_headers[stream].type) assert(stream < (u32)pSelf->pAddr->stream_count);
auto& header = pSelf->pAddr->stream_headers[stream];
switch (header.type)
{ {
case 0x1b: return CELL_PAMF_STREAM_TYPE_AVC; case 0x1b: return CELL_PAMF_STREAM_TYPE_AVC;
case 0x02: return CELL_PAMF_STREAM_TYPE_M2V;
case 0xdc: return CELL_PAMF_STREAM_TYPE_ATRAC3PLUS; case 0xdc: return CELL_PAMF_STREAM_TYPE_ATRAC3PLUS;
case 0x80: return CELL_PAMF_STREAM_TYPE_PAMF_LPCM; case 0x80: return CELL_PAMF_STREAM_TYPE_PAMF_LPCM;
case 0x81: return CELL_PAMF_STREAM_TYPE_AC3;
case 0xdd: return CELL_PAMF_STREAM_TYPE_USER_DATA; case 0xdd: return CELL_PAMF_STREAM_TYPE_USER_DATA;
default:
cellPamf->Todo("pamfGetStreamType: unsupported stream type found(0x%x)", pSelf->pAddr->stream_headers[stream].type);
return 0;
}
} }
u8 pamfGetStreamChannel(vm::ptr<CellPamfReader> pSelf, u8 stream) cellPamf->Todo("pamfGetStreamType(): unsupported stream type found(0x%x)", header.type);
Emu.Pause();
return 0xff;
}
u8 pamfGetStreamChannel(vm::ptr<CellPamfReader> pSelf, u32 stream)
{ {
// TODO: get stream channel correctly // TODO: get stream channel correctly
assert(stream < (u32)pSelf->pAddr->stream_count);
auto& header = pSelf->pAddr->stream_headers[stream];
switch (pSelf->pAddr->stream_headers[stream].type) switch (header.type)
{ {
case 0x1b: case 0x1b: // AVC
if ((pSelf->pAddr->stream_headers[stream].stream_id >= 0xe0) && (pSelf->pAddr->stream_headers[stream].stream_id <= 0xef)) case 0x02: // M2V
{ {
return pSelf->pAddr->stream_headers[stream].stream_id - 0xe0; assert((header.fid_major & 0xf0) == 0xe0 && header.fid_minor == 0);
return header.fid_major % 16;
} }
else
case 0xdc: // ATRAC3PLUS
{ {
cellPamf->Error("pamfGetStreamChannel: stream type 0x%x got invalid stream id=0x%x", assert(header.fid_major == 0xbd && (header.fid_minor & 0xf0) == 0);
pSelf->pAddr->stream_headers[stream].type, pSelf->pAddr->stream_headers[stream].stream_id); return header.fid_minor % 16;
return 0; }
case 0x80: // LPCM
{
assert(header.fid_major == 0xbd && (header.fid_minor & 0xf0) == 0x40);
return header.fid_minor % 16;
}
case 0x81: // AC3
{
assert(header.fid_major == 0xbd && (header.fid_minor & 0xf0) == 0x30);
return header.fid_minor % 16;
} }
case 0xdc:
cellPamf->Todo("pamfGetStreamChannel: CELL_PAMF_STREAM_TYPE_ATRAC3PLUS");
return 0;
case 0x80:
cellPamf->Todo("pamfGetStreamChannel: CELL_PAMF_STREAM_TYPE_PAMF_LPCM");
return 0;
case 0xdd: case 0xdd:
cellPamf->Todo("pamfGetStreamChannel: CELL_PAMF_STREAM_TYPE_USER_DATA"); {
return 0; assert(header.fid_major == 0xbd && (header.fid_minor & 0xf0) == 0x20);
default: return header.fid_minor % 16;
cellPamf->Todo("pamfGetStreamType: unsupported stream type found(0x%x)", pSelf->pAddr->stream_headers[stream].type); }
return 0;
} }
cellPamf->Todo("pamfGetStreamChannel(): unsupported stream type found(0x%x)", header.type);
Emu.Pause();
return 0xff;
} }
int cellPamfGetHeaderSize(vm::ptr<PamfHeader> pAddr, u64 fileSize, vm::ptr<u64> pSize) s32 cellPamfGetHeaderSize(vm::ptr<PamfHeader> pAddr, u64 fileSize, vm::ptr<u64> pSize)
{ {
cellPamf->Warning("cellPamfGetHeaderSize(pAddr=0x%x, fileSize=%d, pSize_addr=0x%x)", pAddr.addr(), fileSize, pSize.addr()); cellPamf->Warning("cellPamfGetHeaderSize(pAddr=0x%x, fileSize=%d, pSize_addr=0x%x)", pAddr.addr(), fileSize, pSize.addr());
//if ((u32)pAddr->magic != 0x464d4150) //if ((u32)pAddr->magic != 0x464d4150) return CELL_PAMF_ERROR_UNKNOWN_TYPE;
//return CELL_PAMF_ERROR_UNKNOWN_TYPE;
const u64 offset = (u64)pAddr->data_offset << 11; const u64 offset = (u64)pAddr->data_offset << 11;
*pSize = offset; *pSize = offset;
return CELL_OK; return CELL_OK;
} }
int cellPamfGetHeaderSize2(vm::ptr<PamfHeader> pAddr, u64 fileSize, u32 attribute, vm::ptr<u64> pSize) s32 cellPamfGetHeaderSize2(vm::ptr<PamfHeader> pAddr, u64 fileSize, u32 attribute, vm::ptr<u64> pSize)
{ {
cellPamf->Warning("cellPamfGetHeaderSize2(pAddr=0x%x, fileSize=%d, attribute=0x%x, pSize_addr=0x%x)", pAddr.addr(), fileSize, attribute, pSize.addr()); cellPamf->Warning("cellPamfGetHeaderSize2(pAddr=0x%x, fileSize=%d, attribute=0x%x, pSize_addr=0x%x)", pAddr.addr(), fileSize, attribute, pSize.addr());
//if ((u32)pAddr->magic != 0x464d4150) //if ((u32)pAddr->magic != 0x464d4150) return CELL_PAMF_ERROR_UNKNOWN_TYPE;
//return CELL_PAMF_ERROR_UNKNOWN_TYPE;
const u64 offset = (u64)pAddr->data_offset << 11; const u64 offset = (u64)pAddr->data_offset << 11;
*pSize = offset; *pSize = offset;
return CELL_OK; return CELL_OK;
} }
int cellPamfGetStreamOffsetAndSize(vm::ptr<PamfHeader> pAddr, u64 fileSize, vm::ptr<u64> pOffset, vm::ptr<u64> pSize) s32 cellPamfGetStreamOffsetAndSize(vm::ptr<PamfHeader> pAddr, u64 fileSize, vm::ptr<u64> pOffset, vm::ptr<u64> pSize)
{ {
cellPamf->Warning("cellPamfGetStreamOffsetAndSize(pAddr=0x%x, fileSize=%d, pOffset_addr=0x%x, pSize_addr=0x%x)", pAddr.addr(), fileSize, pOffset.addr(), pSize.addr()); cellPamf->Warning("cellPamfGetStreamOffsetAndSize(pAddr=0x%x, fileSize=%d, pOffset_addr=0x%x, pSize_addr=0x%x)", pAddr.addr(), fileSize, pOffset.addr(), pSize.addr());
//if ((u32)pAddr->magic != 0x464d4150) //if ((u32)pAddr->magic != 0x464d4150) return CELL_PAMF_ERROR_UNKNOWN_TYPE;
//return CELL_PAMF_ERROR_UNKNOWN_TYPE;
const u64 offset = (u64)pAddr->data_offset << 11; const u64 offset = (u64)pAddr->data_offset << 11;
*pOffset = offset; *pOffset = offset;
@@ -160,14 +206,15 @@ int cellPamfGetStreamOffsetAndSize(vm::ptr<PamfHeader> pAddr, u64 fileSize, vm::
return CELL_OK; return CELL_OK;
} }
int cellPamfVerify(vm::ptr<PamfHeader> pAddr, u64 fileSize) s32 cellPamfVerify(vm::ptr<PamfHeader> pAddr, u64 fileSize)
{ {
cellPamf->Warning("cellPamfVerify(pAddr=0x%x, fileSize=%d)", pAddr.addr(), fileSize); cellPamf->Todo("cellPamfVerify(pAddr=0x%x, fileSize=%d)", pAddr.addr(), fileSize);
// TODO
return CELL_OK; return CELL_OK;
} }
int cellPamfReaderInitialize(vm::ptr<CellPamfReader> pSelf, vm::ptr<const PamfHeader> pAddr, u64 fileSize, u32 attribute) s32 cellPamfReaderInitialize(vm::ptr<CellPamfReader> pSelf, vm::ptr<const PamfHeader> pAddr, u64 fileSize, u32 attribute)
{ {
cellPamf->Warning("cellPamfReaderInitialize(pSelf=0x%x, pAddr=0x%x, fileSize=%d, attribute=0x%x)", pSelf.addr(), pAddr.addr(), fileSize, attribute); cellPamf->Warning("cellPamfReaderInitialize(pSelf=0x%x, pAddr=0x%x, fileSize=%d, attribute=0x%x)", pSelf.addr(), pAddr.addr(), fileSize, attribute);
@@ -184,69 +231,58 @@ int cellPamfReaderInitialize(vm::ptr<CellPamfReader> pSelf, vm::ptr<const PamfHe
if (attribute & CELL_PAMF_ATTRIBUTE_VERIFY_ON) if (attribute & CELL_PAMF_ATTRIBUTE_VERIFY_ON)
{ {
// TODO // TODO
cellPamf->Todo("cellPamfReaderInitialize(): verification");
} }
pSelf->stream = 0; //??? currently set stream pSelf->stream = 0; // currently set stream
return CELL_OK; return CELL_OK;
} }
int cellPamfReaderGetPresentationStartTime(vm::ptr<CellPamfReader> pSelf, vm::ptr<CellCodecTimeStamp> pTimeStamp) s32 cellPamfReaderGetPresentationStartTime(vm::ptr<CellPamfReader> pSelf, vm::ptr<CellCodecTimeStamp> pTimeStamp)
{ {
cellPamf->Warning("cellPamfReaderGetPresentationStartTime(pSelf=0x%x, pTimeStamp_addr=0x%x)", pSelf.addr(), pTimeStamp.addr()); cellPamf->Warning("cellPamfReaderGetPresentationStartTime(pSelf=0x%x, pTimeStamp_addr=0x%x)", pSelf.addr(), pTimeStamp.addr());
if (!pSelf->pAddr) { // always returns CELL_OK
return CELL_PAMF_ERROR_INVALID_PAMF;
}
pTimeStamp->upper = (u32)(u16)pSelf->pAddr->start_pts_high; pTimeStamp->upper = (u32)(u16)pSelf->pAddr->start_pts_high;
pTimeStamp->lower = pSelf->pAddr->start_pts_low; pTimeStamp->lower = pSelf->pAddr->start_pts_low;
return CELL_OK; return CELL_OK;
} }
int cellPamfReaderGetPresentationEndTime(vm::ptr<CellPamfReader> pSelf, vm::ptr<CellCodecTimeStamp> pTimeStamp) s32 cellPamfReaderGetPresentationEndTime(vm::ptr<CellPamfReader> pSelf, vm::ptr<CellCodecTimeStamp> pTimeStamp)
{ {
cellPamf->Warning("cellPamfReaderGetPresentationEndTime(pSelf=0x%x, pTimeStamp_addr=0x%x)", pSelf.addr(), pTimeStamp.addr()); cellPamf->Warning("cellPamfReaderGetPresentationEndTime(pSelf=0x%x, pTimeStamp_addr=0x%x)", pSelf.addr(), pTimeStamp.addr());
if (!pSelf->pAddr) { // always returns CELL_OK
return CELL_PAMF_ERROR_INVALID_PAMF;
}
pTimeStamp->upper = (u32)(u16)pSelf->pAddr->end_pts_high; pTimeStamp->upper = (u32)(u16)pSelf->pAddr->end_pts_high;
pTimeStamp->lower = pSelf->pAddr->end_pts_low; pTimeStamp->lower = pSelf->pAddr->end_pts_low;
return CELL_OK; return CELL_OK;
} }
int cellPamfReaderGetMuxRateBound(vm::ptr<CellPamfReader> pSelf) u32 cellPamfReaderGetMuxRateBound(vm::ptr<CellPamfReader> pSelf)
{ {
cellPamf->Warning("cellPamfReaderGetMuxRateBound(pSelf=0x%x)", pSelf.addr()); cellPamf->Warning("cellPamfReaderGetMuxRateBound(pSelf=0x%x)", pSelf.addr());
if (!pSelf->pAddr) { // cannot return error code
return CELL_PAMF_ERROR_INVALID_PAMF;
}
return pSelf->pAddr->mux_rate_max; return pSelf->pAddr->mux_rate_max;
} }
int cellPamfReaderGetNumberOfStreams(vm::ptr<CellPamfReader> pSelf) u8 cellPamfReaderGetNumberOfStreams(vm::ptr<CellPamfReader> pSelf)
{ {
cellPamf->Warning("cellPamfReaderGetNumberOfStreams(pSelf=0x%x)", pSelf.addr()); cellPamf->Warning("cellPamfReaderGetNumberOfStreams(pSelf=0x%x)", pSelf.addr());
if (!pSelf->pAddr) { // cannot return error code
return CELL_PAMF_ERROR_INVALID_PAMF;
}
return pSelf->pAddr->stream_count; return pSelf->pAddr->stream_count;
} }
int cellPamfReaderGetNumberOfSpecificStreams(vm::ptr<CellPamfReader> pSelf, u8 streamType) u8 cellPamfReaderGetNumberOfSpecificStreams(vm::ptr<CellPamfReader> pSelf, u8 streamType)
{ {
cellPamf->Warning("cellPamfReaderGetNumberOfSpecificStreams(pSelf=0x%x, streamType=%d)", pSelf.addr(), streamType); cellPamf->Warning("cellPamfReaderGetNumberOfSpecificStreams(pSelf=0x%x, streamType=%d)", pSelf.addr(), streamType);
if (!pSelf->pAddr) { // cannot return error code
return CELL_PAMF_ERROR_INVALID_PAMF;
}
int counts[6] = {0, 0, 0, 0, 0, 0}; u8 counts[256] = {};
for (u8 i = 0; i < pSelf->pAddr->stream_count; i++) for (u8 i = 0; i < pSelf->pAddr->stream_count; i++)
{ {
@@ -261,46 +297,48 @@ int cellPamfReaderGetNumberOfSpecificStreams(vm::ptr<CellPamfReader> pSelf, u8 s
case CELL_PAMF_STREAM_TYPE_PAMF_LPCM: case CELL_PAMF_STREAM_TYPE_PAMF_LPCM:
case CELL_PAMF_STREAM_TYPE_AC3: case CELL_PAMF_STREAM_TYPE_AC3:
case CELL_PAMF_STREAM_TYPE_USER_DATA: case CELL_PAMF_STREAM_TYPE_USER_DATA:
{
return counts[streamType]; return counts[streamType];
}
case CELL_PAMF_STREAM_TYPE_VIDEO: case CELL_PAMF_STREAM_TYPE_VIDEO:
{
return counts[CELL_PAMF_STREAM_TYPE_AVC] + counts[CELL_PAMF_STREAM_TYPE_M2V]; return counts[CELL_PAMF_STREAM_TYPE_AVC] + counts[CELL_PAMF_STREAM_TYPE_M2V];
}
case CELL_PAMF_STREAM_TYPE_AUDIO: case CELL_PAMF_STREAM_TYPE_AUDIO:
{
return counts[CELL_PAMF_STREAM_TYPE_ATRAC3PLUS] + counts[CELL_PAMF_STREAM_TYPE_PAMF_LPCM] + counts[CELL_PAMF_STREAM_TYPE_AC3]; return counts[CELL_PAMF_STREAM_TYPE_ATRAC3PLUS] + counts[CELL_PAMF_STREAM_TYPE_PAMF_LPCM] + counts[CELL_PAMF_STREAM_TYPE_AC3];
default:
return 0;
} }
} }
int cellPamfReaderSetStreamWithIndex(vm::ptr<CellPamfReader> pSelf, u8 streamIndex) cellPamf->Todo("cellPamfReaderGetNumberOfSpecificStreams(): unsupported stream type (0x%x)", streamType);
Emu.Pause();
return 0;
}
s32 cellPamfReaderSetStreamWithIndex(vm::ptr<CellPamfReader> pSelf, u8 streamIndex)
{ {
cellPamf->Warning("cellPamfReaderSetStreamWithIndex(pSelf=0x%x, streamIndex=%d)", pSelf.addr(), streamIndex); cellPamf->Warning("cellPamfReaderSetStreamWithIndex(pSelf=0x%x, streamIndex=%d)", pSelf.addr(), streamIndex);
if (!pSelf->pAddr) { if (streamIndex >= pSelf->pAddr->stream_count)
return CELL_PAMF_ERROR_INVALID_PAMF; {
return CELL_PAMF_ERROR_INVALID_ARG;
} }
if (streamIndex < pSelf->pAddr->stream_count)
{
pSelf->stream = streamIndex; pSelf->stream = streamIndex;
return CELL_OK; return CELL_OK;
} }
cellPamf->Error("cellPamfReaderSetStreamWithIndex: CELL_PAMF_ERROR_INVALID_ARG"); s32 cellPamfReaderSetStreamWithTypeAndChannel(vm::ptr<CellPamfReader> pSelf, u8 streamType, u8 ch)
return CELL_PAMF_ERROR_INVALID_ARG;
}
int cellPamfReaderSetStreamWithTypeAndChannel(vm::ptr<CellPamfReader> pSelf, u8 streamType, u8 ch)
{ {
cellPamf->Warning("cellPamfReaderSetStreamWithTypeAndChannel(pSelf=0x%x, streamType=%d, ch=%d)", pSelf.addr(), streamType, ch); cellPamf->Warning("cellPamfReaderSetStreamWithTypeAndChannel(pSelf=0x%x, streamType=%d, ch=%d)", pSelf.addr(), streamType, ch);
if (!pSelf->pAddr) {
return CELL_PAMF_ERROR_INVALID_PAMF;
}
if (streamType > 5)
{
cellPamf->Error("cellPamfReaderSetStreamWithTypeAndChannel: invalid stream type(%d)", streamType);
// it probably doesn't support "any audio" or "any video" argument // it probably doesn't support "any audio" or "any video" argument
if (streamType > 5 || ch >= 16)
{
cellPamf->Error("cellPamfReaderSetStreamWithTypeAndChannel(): invalid arguments (streamType=%d, ch=%d)", streamType, ch);
Emu.Pause();
return CELL_PAMF_ERROR_INVALID_ARG; return CELL_PAMF_ERROR_INVALID_ARG;
} }
@@ -319,14 +357,10 @@ int cellPamfReaderSetStreamWithTypeAndChannel(vm::ptr<CellPamfReader> pSelf, u8
return CELL_PAMF_ERROR_STREAM_NOT_FOUND; return CELL_PAMF_ERROR_STREAM_NOT_FOUND;
} }
int cellPamfReaderSetStreamWithTypeAndIndex(vm::ptr<CellPamfReader> pSelf, u8 streamType, u8 streamIndex) s32 cellPamfReaderSetStreamWithTypeAndIndex(vm::ptr<CellPamfReader> pSelf, u8 streamType, u8 streamIndex)
{ {
cellPamf->Warning("cellPamfReaderSetStreamWithTypeAndIndex(pSelf=0x%x, streamType=%d, streamIndex=%d)", pSelf.addr(), streamType, streamIndex); cellPamf->Warning("cellPamfReaderSetStreamWithTypeAndIndex(pSelf=0x%x, streamType=%d, streamIndex=%d)", pSelf.addr(), streamType, streamIndex);
if (!pSelf->pAddr) {
return CELL_PAMF_ERROR_INVALID_PAMF;
}
u32 found = 0; u32 found = 0;
for (u8 i = 0; i < pSelf->pAddr->stream_count; i++) for (u8 i = 0; i < pSelf->pAddr->stream_count; i++)
@@ -340,23 +374,31 @@ int cellPamfReaderSetStreamWithTypeAndIndex(vm::ptr<CellPamfReader> pSelf, u8 st
else switch(streamType) else switch(streamType)
{ {
case CELL_PAMF_STREAM_TYPE_VIDEO: case CELL_PAMF_STREAM_TYPE_VIDEO:
{
if (type == CELL_PAMF_STREAM_TYPE_AVC || type == CELL_PAMF_STREAM_TYPE_M2V) if (type == CELL_PAMF_STREAM_TYPE_AVC || type == CELL_PAMF_STREAM_TYPE_M2V)
{ {
found++; found++;
} }
break; break;
}
case CELL_PAMF_STREAM_TYPE_AUDIO: case CELL_PAMF_STREAM_TYPE_AUDIO:
{
if (type == CELL_PAMF_STREAM_TYPE_ATRAC3PLUS || type == CELL_PAMF_STREAM_TYPE_AC3 || type == CELL_PAMF_STREAM_TYPE_PAMF_LPCM) if (type == CELL_PAMF_STREAM_TYPE_ATRAC3PLUS || type == CELL_PAMF_STREAM_TYPE_AC3 || type == CELL_PAMF_STREAM_TYPE_PAMF_LPCM)
{ {
found++; found++;
} }
break; break;
}
default: default:
{
if (streamType > 5) if (streamType > 5)
{ {
return CELL_PAMF_ERROR_INVALID_ARG; return CELL_PAMF_ERROR_INVALID_ARG;
} }
} }
}
if (found > streamIndex) if (found > streamIndex)
{ {
@@ -368,199 +410,328 @@ int cellPamfReaderSetStreamWithTypeAndIndex(vm::ptr<CellPamfReader> pSelf, u8 st
return CELL_PAMF_ERROR_STREAM_NOT_FOUND; return CELL_PAMF_ERROR_STREAM_NOT_FOUND;
} }
int cellPamfStreamTypeToEsFilterId(u8 type, u8 ch, vm::ptr<CellCodecEsFilterId> pEsFilterId) s32 cellPamfStreamTypeToEsFilterId(u8 type, u8 ch, vm::ptr<CellCodecEsFilterId> pEsFilterId)
{ {
cellPamf->Warning("cellPamfStreamTypeToEsFilterId(type=%d, ch=%d, pEsFilterId_addr=0x%x)", type, ch, pEsFilterId.addr()); cellPamf->Warning("cellPamfStreamTypeToEsFilterId(type=%d, ch=%d, pEsFilterId_addr=0x%x)", type, ch, pEsFilterId.addr());
return pamfStreamTypeToEsFilterId(type, ch, pEsFilterId); if (!pEsFilterId)
{
return CELL_PAMF_ERROR_INVALID_ARG;
} }
int cellPamfReaderGetStreamIndex(vm::ptr<CellPamfReader> pSelf) return pamfStreamTypeToEsFilterId(type, ch, *pEsFilterId);
}
s32 cellPamfReaderGetStreamIndex(vm::ptr<CellPamfReader> pSelf)
{ {
cellPamf->Log("cellPamfReaderGetStreamIndex(pSelf=0x%x)", pSelf.addr()); cellPamf->Log("cellPamfReaderGetStreamIndex(pSelf=0x%x)", pSelf.addr());
// seems that CELL_PAMF_ERROR_INVALID_PAMF must be already written in pSelf->stream if it's the case
return pSelf->stream; return pSelf->stream;
} }
int cellPamfReaderGetStreamTypeAndChannel(vm::ptr<CellPamfReader> pSelf, vm::ptr<u8> pType, vm::ptr<u8> pCh) s32 cellPamfReaderGetStreamTypeAndChannel(vm::ptr<CellPamfReader> pSelf, vm::ptr<u8> pType, vm::ptr<u8> pCh)
{ {
cellPamf->Warning("cellPamfReaderGetStreamTypeAndChannel(pSelf=0x%x (stream=%d), pType_addr=0x%x, pCh_addr=0x%x", cellPamf->Warning("cellPamfReaderGetStreamTypeAndChannel(pSelf=0x%x (stream=%d), pType_addr=0x%x, pCh_addr=0x%x",
pSelf.addr(), pSelf->stream, pType.addr(), pCh.addr()); pSelf.addr(), pSelf->stream, pType.addr(), pCh.addr());
// unclear
*pType = pamfGetStreamType(pSelf, pSelf->stream); *pType = pamfGetStreamType(pSelf, pSelf->stream);
*pCh = pamfGetStreamChannel(pSelf, pSelf->stream); *pCh = pamfGetStreamChannel(pSelf, pSelf->stream);
return CELL_OK; return CELL_OK;
} }
int cellPamfReaderGetEsFilterId(vm::ptr<CellPamfReader> pSelf, vm::ptr<CellCodecEsFilterId> pEsFilterId) s32 cellPamfReaderGetEsFilterId(vm::ptr<CellPamfReader> pSelf, vm::ptr<CellCodecEsFilterId> pEsFilterId)
{ {
cellPamf->Warning("cellPamfReaderGetEsFilterId(pSelf=0x%x (stream=%d), pEsFilterId_addr=0x%x)", pSelf.addr(), pSelf->stream, pEsFilterId.addr()); cellPamf->Warning("cellPamfReaderGetEsFilterId(pSelf=0x%x (stream=%d), pEsFilterId_addr=0x%x)", pSelf.addr(), pSelf->stream, pEsFilterId.addr());
return pamfStreamTypeToEsFilterId(pamfGetStreamType(pSelf, pSelf->stream), // always returns CELL_OK
pamfGetStreamChannel(pSelf, pSelf->stream), pEsFilterId);
assert((u32)pSelf->stream < (u32)pSelf->pAddr->stream_count);
auto& header = pSelf->pAddr->stream_headers[pSelf->stream];
pEsFilterId->filterIdMajor = header.fid_major;
pEsFilterId->filterIdMinor = header.fid_minor;
pEsFilterId->supplementalInfo1 = header.type == 0x1b ? 1 : 0;
pEsFilterId->supplementalInfo2 = 0;
return CELL_OK;
} }
int cellPamfReaderGetStreamInfo(vm::ptr<CellPamfReader> pSelf, u32 pInfo_addr, u32 size) s32 cellPamfReaderGetStreamInfo(vm::ptr<CellPamfReader> pSelf, u32 pInfo_addr, u32 size)
{ {
cellPamf->Warning("cellPamfReaderGetStreamInfo(pSelf=0x%x, stream=%d, pInfo_addr=0x%x, size=%d)", pSelf.addr(), pSelf->stream, pInfo_addr, size); cellPamf->Warning("cellPamfReaderGetStreamInfo(pSelf=0x%x, stream=%d, pInfo_addr=0x%x, size=%d)", pSelf.addr(), pSelf->stream, pInfo_addr, size);
if (!pSelf->pAddr) { assert((u32)pSelf->stream < (u32)pSelf->pAddr->stream_count);
return CELL_PAMF_ERROR_INVALID_PAMF; auto& header = pSelf->pAddr->stream_headers[pSelf->stream];
} const u8 type = pamfGetStreamType(pSelf, pSelf->stream);
const u8 ch = pamfGetStreamChannel(pSelf, pSelf->stream);
memset(vm::get_ptr<void>(pInfo_addr), 0, size); switch (type)
switch (pamfGetStreamType(pSelf, pSelf->stream))
{ {
case CELL_PAMF_STREAM_TYPE_AVC: case CELL_PAMF_STREAM_TYPE_AVC:
{ {
auto pInfo = vm::ptr<CellPamfAvcInfo>::make(pInfo_addr); if (size < sizeof(CellPamfAvcInfo))
auto pAVC = vm::ptr<PamfStreamHeader_AVC>::make(pSelf->pAddr.addr() + 0x98 + pSelf->stream * 0x30);
if (size != sizeof(CellPamfAvcInfo))
{ {
cellPamf->Error("cellPamfReaderGetStreamInfo: wrong AVC data size(%d)", size);
return CELL_PAMF_ERROR_INVALID_ARG; return CELL_PAMF_ERROR_INVALID_ARG;
} }
pInfo->profileIdc = pAVC->profileIdc; auto info = vm::ptr<CellPamfAvcInfo>::make(pInfo_addr);
pInfo->levelIdc = pAVC->levelIdc;
pInfo->frameMbsOnlyFlag = 1; //fake info->profileIdc = header.AVC.profileIdc;
pInfo->frameRateInfo = (pAVC->unk0 & 0x7) - 1; info->levelIdc = header.AVC.levelIdc;
pInfo->aspectRatioIdc = 1; //fake info->frameMbsOnlyFlag = (header.AVC.x2 & 0x80) >> 7;
info->videoSignalInfoFlag = (header.AVC.x2 & 0x40) >> 6;
info->frameRateInfo = (header.AVC.x2 & 0x0f) - 1;
info->aspectRatioIdc = header.AVC.aspectRatioIdc;
pInfo->horizontalSize = 16 * (u16)pAVC->horizontalSize; if (header.AVC.aspectRatioIdc == 0xff)
pInfo->verticalSize = 16 * (u16)pAVC->verticalSize; {
info->sarWidth = header.AVC.sarWidth;
pInfo->videoSignalInfoFlag = 1; //fake info->sarHeight = header.AVC.sarHeight;
pInfo->colourPrimaries = 1; //fake
pInfo->transferCharacteristics = 1; //fake
pInfo->matrixCoefficients = 1; //fake
//pInfo->deblockingFilterFlag = 1; //???
cellPamf->Warning("cellPamfReaderGetStreamInfo: CELL_PAMF_STREAM_TYPE_AVC");
} }
else
{
info->sarWidth = 0;
info->sarHeight = 0;
}
info->horizontalSize = ((u16)header.AVC.horizontalSize & 0xff) * 16;
info->verticalSize = ((u16)header.AVC.verticalSize & 0xff) * 16;
info->frameCropLeftOffset = header.AVC.frameCropLeftOffset;
info->frameCropRightOffset = header.AVC.frameCropRightOffset;
info->frameCropTopOffset = header.AVC.frameCropTopOffset;
info->frameCropBottomOffset = header.AVC.frameCropBottomOffset;
if (info->videoSignalInfoFlag)
{
info->videoFormat = header.AVC.x14 >> 5;
info->videoFullRangeFlag = (header.AVC.x14 & 0x10) >> 4;
info->colourPrimaries = header.AVC.colourPrimaries;
info->transferCharacteristics = header.AVC.transferCharacteristics;
info->matrixCoefficients = header.AVC.matrixCoefficients;
}
else
{
info->videoFormat = 0;
info->videoFullRangeFlag = 0;
info->colourPrimaries = 0;
info->transferCharacteristics = 0;
info->matrixCoefficients = 0;
}
info->entropyCodingModeFlag = (header.AVC.x18 & 0x80) >> 7;
info->deblockingFilterFlag = (header.AVC.x18 & 0x40) >> 6;
info->minNumSlicePerPictureIdc = (header.AVC.x18 & 0x30) >> 4;
info->nfwIdc = header.AVC.x18 & 0x03;
info->maxMeanBitrate = header.AVC.maxMeanBitrate;
cellPamf->Notice("cellPamfReaderGetStreamInfo(): CELL_PAMF_STREAM_TYPE_AVC");
break; break;
}
case CELL_PAMF_STREAM_TYPE_M2V: case CELL_PAMF_STREAM_TYPE_M2V:
{ {
//TODO if (size < sizeof(CellPamfM2vInfo))
cellPamf->Error("TODO: cellPamfReaderGetStreamInfo: CELL_PAMF_STREAM_TYPE_M2V"); {
return CELL_PAMF_ERROR_INVALID_ARG;
} }
auto info = vm::ptr<CellPamfM2vInfo>::make(pInfo_addr);
switch (header.M2V.x0)
{
case 0x44: info->profileAndLevelIndication = 3; break;
case 0x48: info->profileAndLevelIndication = 1; break;
default: info->profileAndLevelIndication = CELL_PAMF_M2V_UNKNOWN;
}
info->progressiveSequence = (header.M2V.x2 & 0x80) >> 7;
info->videoSignalInfoFlag = (header.M2V.x2 & 0x40) >> 6;
info->frameRateInfo = header.M2V.x2 & 0xf;
info->aspectRatioIdc = header.M2V.aspectRatioIdc;
if (header.M2V.aspectRatioIdc == 0xff)
{
info->sarWidth = header.M2V.sarWidth;
info->sarHeight = header.M2V.sarHeight;
}
else
{
info->sarWidth = 0;
info->sarHeight = 0;
}
info->horizontalSize = ((u16)header.M2V.horizontalSize & 0xff) * 16;
info->verticalSize = ((u16)header.M2V.verticalSize & 0xff) * 16;
info->horizontalSizeValue = header.M2V.horizontalSizeValue;
info->verticalSizeValue = header.M2V.verticalSizeValue;
if (info->videoSignalInfoFlag)
{
info->videoFormat = header.M2V.x14 >> 5;
info->videoFullRangeFlag = (header.M2V.x14 & 0x10) >> 4;
info->colourPrimaries = header.M2V.colourPrimaries;
info->transferCharacteristics = header.M2V.transferCharacteristics;
info->matrixCoefficients = header.M2V.matrixCoefficients;
}
else
{
info->videoFormat = 0;
info->videoFullRangeFlag = 0;
info->colourPrimaries = 0;
info->transferCharacteristics = 0;
info->matrixCoefficients = 0;
}
cellPamf->Notice("cellPamfReaderGetStreamInfo(): CELL_PAMF_STREAM_TYPE_M2V");
break; break;
}
case CELL_PAMF_STREAM_TYPE_ATRAC3PLUS: case CELL_PAMF_STREAM_TYPE_ATRAC3PLUS:
{ {
auto pInfo = vm::ptr<CellPamfAtrac3plusInfo>::make(pInfo_addr); if (size < sizeof(CellPamfAtrac3plusInfo))
auto pAudio = vm::ptr<PamfStreamHeader_Audio>::make(pSelf->pAddr.addr() + 0x98 + pSelf->stream * 0x30);
if (size != sizeof(CellPamfAtrac3plusInfo))
{ {
cellPamf->Error("cellPamfReaderGetStreamInfo: wrong ATRAC3+ data size(%d)", size);
return CELL_PAMF_ERROR_INVALID_ARG; return CELL_PAMF_ERROR_INVALID_ARG;
} }
pInfo->numberOfChannels = pAudio->channels; auto info = vm::ptr<CellPamfAtrac3plusInfo>::make(pInfo_addr);
pInfo->samplingFrequency = CELL_PAMF_FS_48kHz;
}
break;
case CELL_PAMF_STREAM_TYPE_AC3:
{
auto pInfo = vm::ptr<CellPamfAc3Info>::make(pInfo_addr);
auto pAudio = vm::ptr<PamfStreamHeader_Audio>::make(pSelf->pAddr.addr() + 0x98 + pSelf->stream * 0x30);
if (size != sizeof(CellPamfAc3Info)) info->samplingFrequency = header.audio.freq & 0xf;
{ info->numberOfChannels = header.audio.channels & 0xf;
cellPamf->Error("cellPamfReaderGetStreamInfo: wrong AC3 data size(%d)", size);
return CELL_PAMF_ERROR_INVALID_ARG; cellPamf->Notice("cellPamfReaderGetStreamInfo(): CELL_PAMF_STREAM_TYPE_ATRAC3PLUS");
break;
} }
pInfo->numberOfChannels = pAudio->channels;
pInfo->samplingFrequency = CELL_PAMF_FS_48kHz;
}
break;
case CELL_PAMF_STREAM_TYPE_PAMF_LPCM: case CELL_PAMF_STREAM_TYPE_PAMF_LPCM:
{ {
auto pInfo = vm::ptr<CellPamfLpcmInfo>::make(pInfo_addr); if (size < sizeof(CellPamfLpcmInfo))
auto pAudio = vm::ptr<PamfStreamHeader_Audio>::make(pSelf->pAddr.addr() + 0x98 + pSelf->stream * 0x30);
if (size != sizeof(CellPamfLpcmInfo))
{ {
cellPamf->Error("cellPamfReaderGetStreamInfo: wrong LPCM data size(%d)", size);
return CELL_PAMF_ERROR_INVALID_ARG; return CELL_PAMF_ERROR_INVALID_ARG;
} }
pInfo->numberOfChannels = pAudio->channels; auto info = vm::ptr<CellPamfLpcmInfo>::make(pInfo_addr);
pInfo->samplingFrequency = CELL_PAMF_FS_48kHz;
if (pAudio->bps == 0x40) info->samplingFrequency = header.audio.freq & 0xf;
pInfo->bitsPerSample = CELL_PAMF_BIT_LENGTH_16; info->numberOfChannels = header.audio.channels & 0xf;
else info->bitsPerSample = header.audio.bps >> 6;
//TODO: CELL_PAMF_BIT_LENGTH_24
cellPamf->Error("cellPamfReaderGetStreamInfo: unknown bps(0x%x)", (u8)pAudio->bps); cellPamf->Notice("cellPamfReaderGetStreamInfo(): CELL_PAMF_STREAM_TYPE_PAMF_LPCM");
}
break; break;
}
case CELL_PAMF_STREAM_TYPE_AC3:
{
if (size < sizeof(CellPamfAc3Info))
{
return CELL_PAMF_ERROR_INVALID_ARG;
}
auto info = vm::ptr<CellPamfAc3Info>::make(pInfo_addr);
info->samplingFrequency = header.audio.freq & 0xf;
info->numberOfChannels = header.audio.channels & 0xf;
cellPamf->Notice("cellPamfReaderGetStreamInfo(): CELL_PAMF_STREAM_TYPE_AC3");
break;
}
case CELL_PAMF_STREAM_TYPE_USER_DATA: case CELL_PAMF_STREAM_TYPE_USER_DATA:
{ {
cellPamf->Error("cellPamfReaderGetStreamInfo: CELL_PAMF_STREAM_TYPE_USER_DATA"); cellPamf->Error("cellPamfReaderGetStreamInfo(): invalid type CELL_PAMF_STREAM_TYPE_USER_DATA");
return CELL_PAMF_ERROR_INVALID_ARG; return CELL_PAMF_ERROR_INVALID_ARG;
} }
case 6:
{
if (size < 4)
{
return CELL_PAMF_ERROR_INVALID_ARG;
}
cellPamf->Todo("cellPamfReaderGetStreamInfo(): type 6");
break;
}
case 7:
{
if (size < 2)
{
return CELL_PAMF_ERROR_INVALID_ARG;
}
cellPamf->Todo("cellPamfReaderGetStreamInfo(): type 7");
break;
}
case 8:
{
if (size < 2)
{
return CELL_PAMF_ERROR_INVALID_ARG;
}
cellPamf->Todo("cellPamfReaderGetStreamInfo(): type 8");
break;
}
case 9:
{
cellPamf->Error("cellPamfReaderGetStreamInfo(): invalid type 9");
return CELL_PAMF_ERROR_INVALID_ARG;
}
default:
{
// invalid type or getting type/ch failed
cellPamf->Error("cellPamfReaderGetStreamInfo(): invalid type %d (ch=%d)", type, ch);
return CELL_PAMF_ERROR_INVALID_PAMF;
}
} }
return CELL_OK; return CELL_OK;
} }
int cellPamfReaderGetNumberOfEp(vm::ptr<CellPamfReader> pSelf) u32 cellPamfReaderGetNumberOfEp(vm::ptr<CellPamfReader> pSelf)
{ {
cellPamf->Warning("cellPamfReaderGetNumberOfEp(pSelf=0x%x, stream=%d)", pSelf.addr(), pSelf->stream); cellPamf->Todo("cellPamfReaderGetNumberOfEp(pSelf=0x%x, stream=%d)", pSelf.addr(), pSelf->stream);
if (!pSelf->pAddr) { // cannot return error code
return CELL_PAMF_ERROR_INVALID_PAMF; return 0; //pSelf->pAddr->stream_headers[pSelf->stream].ep_num;
} }
return pSelf->pAddr->stream_headers[pSelf->stream].ep_num; s32 cellPamfReaderGetEpIteratorWithIndex(vm::ptr<CellPamfReader> pSelf, u32 epIndex, vm::ptr<CellPamfEpIterator> pIt)
}
int cellPamfReaderGetEpIteratorWithIndex(vm::ptr<CellPamfReader> pSelf, u32 epIndex, vm::ptr<CellPamfEpIterator> pIt)
{ {
cellPamf->Todo("cellPamfReaderGetEpIteratorWithIndex(pSelf=0x%x, stream=%d, epIndex=%d, pIt_addr=0x%x)", pSelf.addr(), pSelf->stream, epIndex, pIt.addr()); cellPamf->Todo("cellPamfReaderGetEpIteratorWithIndex(pSelf=0x%x, stream=%d, epIndex=%d, pIt_addr=0x%x)", pSelf.addr(), pSelf->stream, epIndex, pIt.addr());
if (!pSelf->pAddr) { // TODO
return CELL_PAMF_ERROR_INVALID_PAMF;
}
//TODO:
return CELL_OK; return CELL_OK;
} }
int cellPamfReaderGetEpIteratorWithTimeStamp(vm::ptr<CellPamfReader> pSelf, vm::ptr<CellCodecTimeStamp> pTimeStamp, vm::ptr<CellPamfEpIterator> pIt) s32 cellPamfReaderGetEpIteratorWithTimeStamp(vm::ptr<CellPamfReader> pSelf, vm::ptr<CellCodecTimeStamp> pTimeStamp, vm::ptr<CellPamfEpIterator> pIt)
{ {
cellPamf->Todo("cellPamfReaderGetEpIteratorWithTimeStamp(pSelf=0x%x, pTimeStamp_addr=0x%x, pIt_addr=0x%x)", pSelf.addr(), pTimeStamp.addr(), pIt.addr()); cellPamf->Todo("cellPamfReaderGetEpIteratorWithTimeStamp(pSelf=0x%x, pTimeStamp_addr=0x%x, pIt_addr=0x%x)", pSelf.addr(), pTimeStamp.addr(), pIt.addr());
if (!pSelf->pAddr) { // TODO
return CELL_PAMF_ERROR_INVALID_PAMF;
}
//TODO:
return CELL_OK; return CELL_OK;
} }
int cellPamfEpIteratorGetEp(vm::ptr<CellPamfEpIterator> pIt, vm::ptr<CellPamfEp> pEp) s32 cellPamfEpIteratorGetEp(vm::ptr<CellPamfEpIterator> pIt, vm::ptr<CellPamfEp> pEp)
{ {
cellPamf->Todo("cellPamfEpIteratorGetEp(pIt_addr=0x%x, pEp_addr=0x%x)", pIt.addr(), pEp.addr()); cellPamf->Todo("cellPamfEpIteratorGetEp(pIt_addr=0x%x, pEp_addr=0x%x)", pIt.addr(), pEp.addr());
//TODO: // always returns CELL_OK
// TODO
return CELL_OK; return CELL_OK;
} }
int cellPamfEpIteratorMove(vm::ptr<CellPamfEpIterator> pIt, s32 steps, vm::ptr<CellPamfEp> pEp) s32 cellPamfEpIteratorMove(vm::ptr<CellPamfEpIterator> pIt, s32 steps, vm::ptr<CellPamfEp> pEp)
{ {
cellPamf->Todo("cellPamfEpIteratorMove(pIt_addr=0x%x, steps=%d, pEp_addr=0x%x)", pIt.addr(), steps, pEp.addr()); cellPamf->Todo("cellPamfEpIteratorMove(pIt_addr=0x%x, steps=%d, pEp_addr=0x%x)", pIt.addr(), steps, pEp.addr());
//TODO: // cannot return error code
// TODO
return CELL_OK; return 0;
} }
void cellPamf_init(Module *pxThis) void cellPamf_init(Module *pxThis)
+131 -73
View File
@@ -141,6 +141,8 @@ struct CellCodecTimeStamp
be_t<u32> lower; be_t<u32> lower;
}; };
static const u64 CODEC_TS_INVALID = 0xffffffffffffffffull;
// Entry point information // Entry point information
struct CellPamfEp struct CellPamfEp
{ {
@@ -168,37 +170,41 @@ struct CellCodecEsFilterId
}; };
// AVC (MPEG4 AVC Video) Specific Information // AVC (MPEG4 AVC Video) Specific Information
struct CellPamfAvcInfo { struct CellPamfAvcInfo
{
u8 profileIdc; u8 profileIdc;
u8 levelIdc; u8 levelIdc;
u8 frameMbsOnlyFlag; u8 frameMbsOnlyFlag;
u8 videoSignalInfoFlag; u8 videoSignalInfoFlag;
u8 frameRateInfo; u8 frameRateInfo;
u8 aspectRatioIdc; u8 aspectRatioIdc;
be_t<u16> sarWidth; //reserved be_t<u16> sarWidth;
be_t<u16> sarHeight; //reserved be_t<u16> sarHeight;
be_t<u16> horizontalSize; be_t<u16> horizontalSize;
be_t<u16> verticalSize; be_t<u16> verticalSize;
be_t<u16> frameCropLeftOffset; //reserved be_t<u16> frameCropLeftOffset;
be_t<u16> frameCropRightOffset; //reserved be_t<u16> frameCropRightOffset;
be_t<u16> frameCropTopOffset; //reserved be_t<u16> frameCropTopOffset;
be_t<u16> frameCropBottomOffset; //!!!!! be_t<u16> frameCropBottomOffset;
u8 videoFormat; //reserved u8 videoFormat;
u8 videoFullRangeFlag; u8 videoFullRangeFlag;
u8 colourPrimaries; u8 colourPrimaries;
u8 transferCharacteristics; u8 transferCharacteristics;
u8 matrixCoefficients; u8 matrixCoefficients;
u8 entropyCodingModeFlag; //reserved u8 entropyCodingModeFlag;
u8 deblockingFilterFlag; u8 deblockingFilterFlag;
u8 minNumSlicePerPictureIdc; //reserved u8 minNumSlicePerPictureIdc;
u8 nfwIdc; //reserved u8 nfwIdc;
u8 maxMeanBitrate; //reserved u8 maxMeanBitrate;
}; };
static_assert(sizeof(CellPamfAvcInfo) == 0x20, "Invalid CellPamfAvcInfo size");
// M2V (MPEG2 Video) Specific Information // M2V (MPEG2 Video) Specific Information
struct CellPamfM2vInfo { struct CellPamfM2vInfo
{
u8 profileAndLevelIndication; u8 profileAndLevelIndication;
bool progressiveSequence; u8 progressiveSequence;
u8 videoSignalInfoFlag; u8 videoSignalInfoFlag;
u8 frameRateInfo; u8 frameRateInfo;
u8 aspectRatioIdc; u8 aspectRatioIdc;
@@ -215,75 +221,121 @@ struct CellPamfM2vInfo {
u8 matrixCoefficients; u8 matrixCoefficients;
}; };
static_assert(sizeof(CellPamfM2vInfo) == 0x18, "Invalid CellPamfM2vInfo size");
// ATRAC3+ Audio Specific Information
struct CellPamfAtrac3plusInfo
{
be_t<u32> samplingFrequency;
u8 numberOfChannels;
};
static_assert(sizeof(CellPamfAtrac3plusInfo) == 8, "Invalid CellPamfAtrac3plusInfo size");
// AC3 Audio Specific Information
struct CellPamfAc3Info
{
be_t<u32> samplingFrequency;
u8 numberOfChannels;
};
static_assert(sizeof(CellPamfAc3Info) == 8, "Invalid CellPamfAc3Info size");
// LPCM Audio Specific Information // LPCM Audio Specific Information
struct CellPamfLpcmInfo { struct CellPamfLpcmInfo
{
be_t<u32> samplingFrequency; be_t<u32> samplingFrequency;
u8 numberOfChannels; u8 numberOfChannels;
be_t<u16> bitsPerSample; be_t<u16> bitsPerSample;
}; };
// ATRAC3+ Audio Specific Information
struct CellPamfAtrac3plusInfo {
be_t<u32> samplingFrequency;
u8 numberOfChannels;
};
// AC3 Audio Specific Information
struct CellPamfAc3Info {
be_t<u32> samplingFrequency;
u8 numberOfChannels;
};
#pragma pack(push, 1) // file data #pragma pack(push, 1) // file data
struct PamfStreamHeader_AVC { //AVC specific information struct PamfStreamHeader
u8 profileIdc;
u8 levelIdc;
u8 unk0;
u8 unk1; //1
u32 unk2; //0
be_t<u16> horizontalSize; //divided by 16
be_t<u16> verticalSize; //divided by 16
u32 unk3; //0
u32 unk4; //0
u8 unk5; //0xA0
u8 unk6; //1
u8 unk7; //1
u8 unk8; //1
u8 unk9; //0xB0
u8 unk10;
u16 unk11; //0
u32 unk12; //0
};
struct PamfStreamHeader_M2V { //M2V specific information
u8 unknown[32]; //no information yet
};
struct PamfStreamHeader_Audio { //Audio specific information
u16 unknown; //== 0
u8 channels; //number of channels (1, 2, 6 or 8)
u8 freq; //== 1 (always 48000)
u8 bps; //(LPCM only, 0x40 for 16 bit, ???? for 24)
u8 reserved[27]; //probably nothing
};
struct PamfStreamHeader //48 bytes
{ {
//TODO: look for correct beginning of stream header u8 type;
u8 type; //0x1B for video (AVC), 0xDC ATRAC3+, 0x80 LPCM, 0xDD userdata u8 unknown[3];
u8 unknown[3]; //0 u8 fid_major;
//TODO: examine stream_ch encoding u8 fid_minor;
u8 stream_id; u8 unknown1;
u8 private_stream_id; u8 unknown2;
u8 unknown1; //?????
u8 unknown2; //?????
//Entry Point Info
be_t<u32> ep_offset; // offset of EP section in header be_t<u32> ep_offset; // offset of EP section in header
be_t<u32> ep_num; // count of EPs be_t<u32> ep_num; // count of EPs
//Specific Info
u8 data[32]; union
{
u8 data[32]; // specific info
// AVC specific information
struct
{
u8 profileIdc;
u8 levelIdc;
u8 x2; // contains frameMbsOnlyFlag, videoSignalInfoFlag, frameRateInfo
u8 aspectRatioIdc;
u32 x4; // 0 (not used)
be_t<u16> horizontalSize; // divided by 16
be_t<u16> verticalSize; // divided by 16
be_t<u16> frameCropLeftOffset;
be_t<u16> frameCropRightOffset;
be_t<u16> frameCropTopOffset;
be_t<u16> frameCropBottomOffset;
union
{
struct
{
be_t<u16> sarWidth;
be_t<u16> sarHeight;
}; };
struct
{
u8 x14; // contains videoFormat and videoFullRangeFlag
u8 colourPrimaries;
u8 transferCharacteristics;
u8 matrixCoefficients;
};
};
u8 x18; // contains entropyCodingModeFlag, deblockingFilterFlag, minNumSlicePerPictureIdc, nfwIdc
u8 maxMeanBitrate;
} AVC;
// M2V specific information
struct
{
s8 x0; // contains profileAndLevelIndication
u8 x1; // not used
u8 x2; // contains progressiveSequence, videoSignalInfoFlag, frameRateInfo
u8 aspectRatioIdc;
be_t<u16> sarWidth;
be_t<u16> sarHeight;
be_t<u16> horizontalSize;
be_t<u16> verticalSize;
be_t<u16> horizontalSizeValue;
be_t<u16> verticalSizeValue;
u32 x10; // not used
u8 x14; // contains videoFormat and videoFullRangeFlag
u8 colourPrimaries;
u8 transferCharacteristics;
u8 matrixCoefficients;
} M2V;
// Audio specific information
struct
{
u16 unknown; // 0
u8 channels; // number of channels (1, 2, 6, 8)
u8 freq; // 1 (always 48000)
u8 bps; // LPCM only
} audio;
};
};
static_assert(sizeof(PamfStreamHeader) == 48, "Invalid PamfStreamHeader size");
struct PamfHeader struct PamfHeader
{ {
@@ -317,21 +369,27 @@ struct PamfHeader
PamfStreamHeader stream_headers[256]; PamfStreamHeader stream_headers[256];
}; };
struct PamfEpHeader { //12 bytes struct PamfEpHeader
{
be_t<u16> value0; //mixed indexN (probably left 2 bits) and nThRefPictureOffset be_t<u16> value0; //mixed indexN (probably left 2 bits) and nThRefPictureOffset
be_t<u16> pts_high; be_t<u16> pts_high;
be_t<u32> pts_low; be_t<u32> pts_low;
be_t<u32> rpnOffset; be_t<u32> rpnOffset;
}; };
static_assert(sizeof(PamfEpHeader) == 12, "Invalid PamfEpHeader size");
#pragma pack(pop) #pragma pack(pop)
// not directly accessed by virtual CPU, fields are unknown
struct CellPamfReader struct CellPamfReader
{ {
//this struct can be used in any way, if it is not accessed directly by virtual CPU
//be_t<u64> internalData[16];
vm::ptr<const PamfHeader> pAddr; vm::ptr<const PamfHeader> pAddr;
int stream; s32 stream;
u64 fileSize; u64 fileSize;
u32 internalData[28]; u32 internalData[28];
}; };
static_assert(sizeof(CellPamfReader) == 128, "Invalid CellPamfReader size");
s32 cellPamfReaderInitialize(vm::ptr<CellPamfReader> pSelf, vm::ptr<const PamfHeader> pAddr, u64 fileSize, u32 attribute);
+28 -22
View File
@@ -4,12 +4,14 @@
#include "Emu/SysCalls/Modules.h" #include "Emu/SysCalls/Modules.h"
#include "stblib/stb_image.h" #include "stblib/stb_image.h"
#include "Emu/SysCalls/lv2/lv2Fs.h" #include "Emu/SysCalls/lv2/cellFs.h"
#include "cellPngDec.h" #include "cellPngDec.h"
#include <map> #include <map>
Module *cellPngDec = nullptr; Module *cellPngDec = nullptr;
#undef PRX_DEBUG
#ifdef PRX_DEBUG #ifdef PRX_DEBUG
#include "prx_libpngdec.h" #include "prx_libpngdec.h"
u32 libpngdec; u32 libpngdec;
@@ -75,13 +77,13 @@ s64 pngDecOpen(
stream->fd = 0; stream->fd = 0;
stream->src = *src; stream->src = *src;
switch (src->srcSelect.ToLE()) switch ((u32)src->srcSelect.ToBE())
{ {
case CELL_PNGDEC_BUFFER: case se32(CELL_PNGDEC_BUFFER):
stream->fileSize = src->streamSize.ToLE(); stream->fileSize = src->streamSize.ToLE();
break; break;
case CELL_PNGDEC_FILE: case se32(CELL_PNGDEC_FILE):
// Get file descriptor // Get file descriptor
vm::var<be_t<u32>> fd; vm::var<be_t<u32>> fd;
int ret = cellFsOpen(vm::ptr<const char>::make(src->fileName.addr()), 0, fd, vm::ptr<u32>::make(0), 0); int ret = cellFsOpen(vm::ptr<const char>::make(src->fileName.addr()), 0, fd, vm::ptr<u32>::make(0), 0);
@@ -143,7 +145,7 @@ s64 pngReadHeader(
auto buffer_32 = buffer.To<be_t<u32>>(); auto buffer_32 = buffer.To<be_t<u32>>();
vm::var<be_t<u64>> pos, nread; vm::var<be_t<u64>> pos, nread;
switch (stream->src.srcSelect.ToBE()) switch ((u32)stream->src.srcSelect.ToBE())
{ {
case se32(CELL_PNGDEC_BUFFER): case se32(CELL_PNGDEC_BUFFER):
memmove(buffer.begin(), stream->src.streamPtr.get_ptr(), buffer.size()); memmove(buffer.begin(), stream->src.streamPtr.get_ptr(), buffer.size());
@@ -204,17 +206,21 @@ s64 pngDecSetParameter(
current_outParam.outputHeight = current_info.imageHeight; current_outParam.outputHeight = current_info.imageHeight;
current_outParam.outputColorSpace = inParam->outputColorSpace; current_outParam.outputColorSpace = inParam->outputColorSpace;
switch ((u32)current_outParam.outputColorSpace) switch ((u32)current_outParam.outputColorSpace.ToBE())
{ {
case CELL_PNGDEC_PALETTE: case se32(CELL_PNGDEC_PALETTE):
case CELL_PNGDEC_GRAYSCALE: current_outParam.outputComponents = 1; break; case se32(CELL_PNGDEC_GRAYSCALE):
current_outParam.outputComponents = 1; break;
case CELL_PNGDEC_GRAYSCALE_ALPHA: current_outParam.outputComponents = 2; break; case se32(CELL_PNGDEC_GRAYSCALE_ALPHA):
current_outParam.outputComponents = 2; break;
case CELL_PNGDEC_RGB: current_outParam.outputComponents = 3; break; case se32(CELL_PNGDEC_RGB):
current_outParam.outputComponents = 3; break;
case CELL_PNGDEC_RGBA: case se32(CELL_PNGDEC_RGBA):
case CELL_PNGDEC_ARGB: current_outParam.outputComponents = 4; break; case se32(CELL_PNGDEC_ARGB):
current_outParam.outputComponents = 4; break;
default: default:
cellPngDec->Error("pngDecSetParameter: Unsupported color space (%d)", current_outParam.outputColorSpace.ToLE()); cellPngDec->Error("pngDecSetParameter: Unsupported color space (%d)", current_outParam.outputColorSpace.ToLE());
@@ -248,7 +254,7 @@ s64 pngDecodeData(
vm::var<unsigned char[]> png((u32)fileSize); vm::var<unsigned char[]> png((u32)fileSize);
vm::var<be_t<u64>> pos, nread; vm::var<be_t<u64>> pos, nread;
switch (stream->src.srcSelect.ToBE()) switch ((u32)stream->src.srcSelect.ToBE())
{ {
case se32(CELL_PNGDEC_BUFFER): case se32(CELL_PNGDEC_BUFFER):
memmove(png.begin(), stream->src.streamPtr.get_ptr(), png.size()); memmove(png.begin(), stream->src.streamPtr.get_ptr(), png.size());
@@ -277,10 +283,10 @@ s64 pngDecodeData(
const int bytesPerLine = (u32)dataCtrlParam->outputBytesPerLine; const int bytesPerLine = (u32)dataCtrlParam->outputBytesPerLine;
uint image_size = width * height; uint image_size = width * height;
switch ((u32)current_outParam.outputColorSpace) switch ((u32)current_outParam.outputColorSpace.ToBE())
{ {
case CELL_PNGDEC_RGB: case se32(CELL_PNGDEC_RGB):
case CELL_PNGDEC_RGBA: case se32(CELL_PNGDEC_RGBA):
{ {
const char nComponents = current_outParam.outputColorSpace == CELL_PNGDEC_RGBA ? 4 : 3; const char nComponents = current_outParam.outputColorSpace == CELL_PNGDEC_RGBA ? 4 : 3;
image_size *= nComponents; image_size *= nComponents;
@@ -298,10 +304,10 @@ s64 pngDecodeData(
{ {
memcpy(data.get_ptr(), image.get(), image_size); memcpy(data.get_ptr(), image.get(), image_size);
} }
}
break; break;
}
case CELL_PNGDEC_ARGB: case se32(CELL_PNGDEC_ARGB):
{ {
const int nComponents = 4; const int nComponents = 4;
image_size *= nComponents; image_size *= nComponents;
@@ -340,12 +346,12 @@ s64 pngDecodeData(
memcpy(data.get_ptr(), img, image_size); memcpy(data.get_ptr(), img, image_size);
delete[] img; delete[] img;
} }
}
break; break;
}
case CELL_PNGDEC_GRAYSCALE: case se32(CELL_PNGDEC_GRAYSCALE):
case CELL_PNGDEC_PALETTE: case se32(CELL_PNGDEC_PALETTE):
case CELL_PNGDEC_GRAYSCALE_ALPHA: case se32(CELL_PNGDEC_GRAYSCALE_ALPHA):
cellPngDec->Error("pngDecodeData: Unsupported color space (%d)", current_outParam.outputColorSpace.ToLE()); cellPngDec->Error("pngDecodeData: Unsupported color space (%d)", current_outParam.outputColorSpace.ToLE());
break; break;
+65 -20
View File
@@ -1,8 +1,10 @@
#include "stdafx.h" #include "stdafx.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/SysCalls/Modules.h" #include "Emu/SysCalls/Modules.h"
#include "Emu/FS/vfsFile.h"
#include "cellSail.h" #include "cellSail.h"
#include "cellPamf.h"
Module *cellSail = nullptr; Module *cellSail = nullptr;
@@ -11,6 +13,7 @@ int cellSailMemAllocatorInitialize(vm::ptr<CellSailMemAllocator> pSelf, vm::ptr<
cellSail->Warning("cellSailMemAllocatorInitialize(pSelf_addr=0x%x, pCallbacks_addr=0x%x)", pSelf.addr(), pCallbacks.addr()); cellSail->Warning("cellSailMemAllocatorInitialize(pSelf_addr=0x%x, pCallbacks_addr=0x%x)", pSelf.addr(), pCallbacks.addr());
pSelf->callbacks = pCallbacks; pSelf->callbacks = pCallbacks;
// TODO: Create a cellSail thread
return CELL_OK; return CELL_OK;
} }
@@ -71,7 +74,7 @@ int cellSailDescriptorGetMediaInfo()
int cellSailDescriptorSetAutoSelection(vm::ptr<CellSailDescriptor> pSelf, bool autoSelection) int cellSailDescriptorSetAutoSelection(vm::ptr<CellSailDescriptor> pSelf, bool autoSelection)
{ {
cellSail->Todo("cellSailDescriptorSetAutoSelection(pSelf_addr=0x%x, autoSelection=%s)", pSelf.addr(), autoSelection ? "true" : "false"); cellSail->Warning("cellSailDescriptorSetAutoSelection(pSelf_addr=0x%x, autoSelection=%s)", pSelf.addr(), autoSelection ? "true" : "false");
if (pSelf) { if (pSelf) {
pSelf->autoSelection = autoSelection; pSelf->autoSelection = autoSelection;
@@ -91,9 +94,22 @@ int cellSailDescriptorIsAutoSelection(vm::ptr<CellSailDescriptor> pSelf)
return CELL_OK; return CELL_OK;
} }
int cellSailDescriptorCreateDatabase() int cellSailDescriptorCreateDatabase(vm::ptr<CellSailDescriptor> pSelf, vm::ptr<void> pDatabase, be_t<u32> size, be_t<u64> arg)
{ {
UNIMPLEMENTED_FUNC(cellSail); cellSail->Warning("cellSailDescriptorCreateDatabase(pSelf=0x%x, pDatabase=0x%x, size=0x%x, arg=0x%x", pSelf.addr(), pDatabase.addr(), size, arg);
switch ((s32)pSelf->streamType) {
case CELL_SAIL_STREAM_PAMF:
{
u32 addr = pSelf->internalData[1];
auto ptr = vm::ptr<CellPamfReader>::make(addr);
memcpy(pDatabase.get_ptr(), ptr.get_ptr(), sizeof(CellPamfReader));
break;
}
default:
cellSail->Error("Unhandled stream type: %d", pSelf->streamType);
}
return CELL_OK; return CELL_OK;
} }
@@ -616,23 +632,52 @@ int cellSailPlayerAddDescriptor(vm::ptr<CellSailPlayer> pSelf, vm::ptr<CellSailD
return CELL_OK; return CELL_OK;
} }
int cellSailPlayerCreateDescriptor(vm::ptr<CellSailPlayer> pSelf, s32 streamType, vm::ptr<u32> pMediaInfo, vm::ptr<const char> pUri, vm::ptr<CellSailDescriptor> ppDesc) int cellSailPlayerCreateDescriptor(vm::ptr<CellSailPlayer> pSelf, s32 streamType, vm::ptr<u32> pMediaInfo, vm::ptr<const char> pUri, vm::ptr<u32> ppDesc)
{ {
cellSail->Todo("cellSailPlayerCreateDescriptor(pSelf_addr=0x%x, streamType=%d, pMediaInfo_addr=0x%x, pUri_addr=0x%x, ppDesc_addr=0x%x)", pSelf.addr(), streamType, cellSail->Warning("cellSailPlayerCreateDescriptor(pSelf_addr=0x%x, streamType=%d, pMediaInfo_addr=0x%x, pUri_addr=0x%x, ppDesc_addr=0x%x)", pSelf.addr(), streamType,
pMediaInfo.addr(), pUri.addr(), ppDesc.addr()); pMediaInfo.addr(), pUri.addr(), ppDesc.addr());
// TODO: Let the game allocate memory for the descriptor, setup the descriptor and pass it back to the game u32 descriptorAddress = Memory.Alloc(sizeof(CellSailDescriptor), 1);
auto descriptor = vm::ptr<CellSailDescriptor>::make(descriptorAddress);
*ppDesc = descriptorAddress;
descriptor->streamType = streamType;
descriptor->registered = false;
//CellSailDescriptor *pDesc = new CellSailDescriptor(); //pSelf->descriptors = 0;
//u32 descriptorAddress = pSelf->allocator->callbacks->pAlloc(pSelf->allocator->pArg, 4, descriptorAddress);
//cellSail->Error("Address: 0x%x", descriptorAddress);
//vm::ptr<CellSailDescriptor> descriptor = vm::ptr<CellSailDescriptor>::make(Memory.RealToVirtualAddr(&descriptorAddress));
//descriptor->streamType = streamType;
//descriptor->registered = false;
pSelf->descriptors = 0;
pSelf->repeatMode = 0; pSelf->repeatMode = 0;
//ppDesc = descriptor;
switch (streamType)
{
case CELL_SAIL_STREAM_PAMF:
{
std::string uri = pUri.get_ptr();
if (uri.substr(0, 12) == "x-cell-fs://") {
std::string path = uri.substr(12);
vfsFile f;
if (f.Open(path)) {
u64 size = f.GetSize();
u32 buf_ = Memory.Alloc(size, 1);
auto bufPtr = vm::ptr<const PamfHeader>::make(buf_);
PamfHeader *buf = const_cast<PamfHeader*>(bufPtr.get_ptr());
assert(f.Read(buf, size) == size);
u32 sp_ = Memory.Alloc(sizeof(CellPamfReader), 1);
auto sp = vm::ptr<CellPamfReader>::make(sp_);
u32 r = cellPamfReaderInitialize(sp, bufPtr, size, 0);
descriptor->internalData[0] = buf_;
descriptor->internalData[1] = sp_;
}
else
cellSail->Warning("Couldn't open PAMF: %s", uri.c_str());
}
else
cellSail->Warning("Unhandled uri: %s", uri.c_str());
break;
}
default:
cellSail->Error("Unhandled stream type: %d", streamType);
}
//cellSail->Todo("pSelf_addr=0x%x, pDesc_addr=0x%x", pSelf.addr(), descriptor.addr()); //cellSail->Todo("pSelf_addr=0x%x, pDesc_addr=0x%x", pSelf.addr(), descriptor.addr());
//cellSailPlayerAddDescriptor(pSelf, ppDesc); //cellSailPlayerAddDescriptor(pSelf, ppDesc);
@@ -766,16 +811,16 @@ int cellSailPlayerCancel()
return CELL_OK; return CELL_OK;
} }
int cellSailPlayerSetPaused() int cellSailPlayerSetPaused(vm::ptr<CellSailPlayer> pSelf, bool paused)
{ {
UNIMPLEMENTED_FUNC(cellSail); cellSail->Todo("cellSailPlayerSetPaused(pSelf_addr=0x%x, paused=)", pSelf.addr(), paused);
return CELL_OK; return CELL_OK;
} }
int cellSailPlayerIsPaused() int cellSailPlayerIsPaused(vm::ptr<CellSailPlayer> pSelf)
{ {
UNIMPLEMENTED_FUNC(cellSail); cellSail->Warning("cellSailPlayerIsPaused(pSelf_addr=0x%x)", pSelf.addr());
return CELL_OK; return pSelf->paused;
} }
int cellSailPlayerSetRepeatMode(vm::ptr<CellSailPlayer> pSelf, s32 repeatMode, vm::ptr<CellSailStartCommand> pCommand) int cellSailPlayerSetRepeatMode(vm::ptr<CellSailPlayer> pSelf, s32 repeatMode, vm::ptr<CellSailStartCommand> pCommand)
+11 -5
View File
@@ -679,8 +679,8 @@ typedef void(*CellSailPlayerFuncNotified)(u32 pArg, vm::ptr<CellSailEvent> event
struct CellSailMemAllocatorFuncs struct CellSailMemAllocatorFuncs
{ {
CellSailMemAllocatorFuncAlloc pAlloc; vm::ptr<CellSailMemAllocatorFuncAlloc> pAlloc;
CellSailMemAllocatorFuncFree pFree; vm::ptr<CellSailMemAllocatorFuncFree> pFree;
}; };
struct CellSailMemAllocator struct CellSailMemAllocator
@@ -691,8 +691,8 @@ struct CellSailMemAllocator
struct CellSailFuture struct CellSailFuture
{ {
u32 mutex_id; be_t<u32> mutex_id;
u32 cond_id; be_t<u32> cond_id;
volatile be_t<u32> flags; volatile be_t<u32> flags;
be_t<s32> result; be_t<s32> result;
be_t<u64> userParam; be_t<u64> userParam;
@@ -1038,9 +1038,11 @@ struct CellSailDescriptor
bool autoSelection; bool autoSelection;
bool registered; bool registered;
be_t<s32> streamType; be_t<s32> streamType;
be_t<u64> internalData[32]; be_t<u64> internalData[31];
}; };
static_assert(sizeof(CellSailDescriptor) == 0x100, "Invalid CellSailDescriptor size");
struct CellSailStartCommand struct CellSailStartCommand
{ {
be_t<u32> startType; be_t<u32> startType;
@@ -1102,4 +1104,8 @@ struct CellSailPlayer
be_t<s32> repeatMode; be_t<s32> repeatMode;
be_t<s32> descriptors; be_t<s32> descriptors;
vm::ptr<CellSailDescriptor> registeredDescriptors[2]; vm::ptr<CellSailDescriptor> registeredDescriptors[2];
bool paused = true;
be_t<u64> internalData[26];
}; };
static_assert(sizeof(CellSailPlayer) == 0x100, "Invalid CellSailPlayer size");
+48 -12
View File
@@ -10,6 +10,14 @@
#include "Loader/PSF.h" #include "Loader/PSF.h"
#include "cellSaveData.h" #include "cellSaveData.h"
#ifdef _WIN32
#include <windows.h>
#undef CreateFile
#else
#include <sys/types.h>
#include <sys/stat.h>
#endif
extern Module *cellSysutil; extern Module *cellSysutil;
// Auxiliary Classes // Auxiliary Classes
@@ -39,7 +47,6 @@ public:
} }
}; };
// Auxiliary Functions // Auxiliary Functions
u64 getSaveDataSize(const std::string& dirName) u64 getSaveDataSize(const std::string& dirName)
{ {
@@ -69,6 +76,26 @@ void addSaveDataEntry(std::vector<SaveDataEntry>& saveEntries, const std::string
std::string localPath; std::string localPath;
Emu.GetVFS().GetDevice(saveDir + "/ICON0.PNG", localPath); Emu.GetVFS().GetDevice(saveDir + "/ICON0.PNG", localPath);
u64 atime = 0;
u64 mtime = 0;
u64 ctime = 0;
cellSysutil->Error("Running _stat in cellSaveData. Please report this to a RPCS3 developer!");
std::string real_path;
struct stat buf;
Emu.GetVFS().GetDevice(f.GetPath(), real_path);
if (stat(real_path.c_str(), &buf) != 0)
cellSysutil->Error("stat failed! (%s)", real_path.c_str());
else
{
atime = buf.st_atime;
mtime = buf.st_mtime;
ctime = buf.st_ctime;
}
SaveDataEntry saveEntry; SaveDataEntry saveEntry;
saveEntry.dirName = psf.GetString("SAVEDATA_DIRECTORY"); saveEntry.dirName = psf.GetString("SAVEDATA_DIRECTORY");
saveEntry.listParam = psf.GetString("SAVEDATA_LIST_PARAM"); saveEntry.listParam = psf.GetString("SAVEDATA_LIST_PARAM");
@@ -76,9 +103,9 @@ void addSaveDataEntry(std::vector<SaveDataEntry>& saveEntries, const std::string
saveEntry.subtitle = psf.GetString("SUB_TITLE"); saveEntry.subtitle = psf.GetString("SUB_TITLE");
saveEntry.details = psf.GetString("DETAIL"); saveEntry.details = psf.GetString("DETAIL");
saveEntry.sizeKB = (u32)(getSaveDataSize(saveDir) / 1024); saveEntry.sizeKB = (u32)(getSaveDataSize(saveDir) / 1024);
saveEntry.st_atime_ = 0; // TODO saveEntry.st_atime_ = atime;
saveEntry.st_mtime_ = 0; // TODO saveEntry.st_mtime_ = mtime;
saveEntry.st_ctime_ = 0; // TODO saveEntry.st_ctime_ = ctime;
saveEntry.iconBuf = NULL; // TODO: Here should be the PNG buffer saveEntry.iconBuf = NULL; // TODO: Here should be the PNG buffer
saveEntry.iconBufSize = 0; // TODO: Size of the PNG file saveEntry.iconBufSize = 0; // TODO: Size of the PNG file
saveEntry.isNew = false; saveEntry.isNew = false;
@@ -196,10 +223,15 @@ void getSaveDataStat(SaveDataEntry entry, vm::ptr<CellSaveDataStatGet> statGet)
CellSaveDataFileStat fileEntry; CellSaveDataFileStat fileEntry;
vfsFile file(saveDir + "/" + dirEntry->name); vfsFile file(saveDir + "/" + dirEntry->name);
if (dirEntry->name == "ICON0.PNG") fileEntry.fileType = CELL_SAVEDATA_FILETYPE_CONTENT_ICON0; if (dirEntry->name == "ICON0.PNG")
if (dirEntry->name == "ICON1.PAM") fileEntry.fileType = CELL_SAVEDATA_FILETYPE_CONTENT_ICON1; fileEntry.fileType = CELL_SAVEDATA_FILETYPE_CONTENT_ICON0;
if (dirEntry->name == "PIC1.PNG") fileEntry.fileType = CELL_SAVEDATA_FILETYPE_CONTENT_PIC1; else if (dirEntry->name == "ICON1.PAM")
if (dirEntry->name == "SND0.AT3") fileEntry.fileType = CELL_SAVEDATA_FILETYPE_CONTENT_SND0; fileEntry.fileType = CELL_SAVEDATA_FILETYPE_CONTENT_ICON1;
else if (dirEntry->name == "PIC1.PNG")
fileEntry.fileType = CELL_SAVEDATA_FILETYPE_CONTENT_PIC1;
else if (dirEntry->name == "SND0.AT3")
fileEntry.fileType = CELL_SAVEDATA_FILETYPE_CONTENT_SND0;
fileEntry.st_size = file.GetSize(); fileEntry.st_size = file.GetSize();
fileEntry.st_atime_ = 0; // TODO ? fileEntry.st_atime_ = 0; // TODO ?
fileEntry.st_mtime_ = 0; // TODO ? fileEntry.st_mtime_ = 0; // TODO ?
@@ -210,9 +242,11 @@ void getSaveDataStat(SaveDataEntry entry, vm::ptr<CellSaveDataStatGet> statGet)
} }
} }
statGet->fileList = vm::bptr<CellSaveDataFileStat>::make(be_t<u32>::make((u32)Memory.Alloc(sizeof(CellSaveDataFileStat) * (u32)fileEntries.size(), sizeof(CellSaveDataFileStat)))); statGet->fileList = vm::ptr<CellSaveDataFileStat>::make((u32)Memory.Alloc(sizeof(CellSaveDataFileStat) * fileEntries.size(), 8));
for (u32 i=0; i<fileEntries.size(); i++) for (u32 i = 0; i < fileEntries.size(); i++) {
memcpy(&statGet->fileList[i], &fileEntries[i], sizeof(CellSaveDataFileStat)); CellSaveDataFileStat *dst = &statGet->fileList[i];
memcpy(dst, &fileEntries[i], sizeof(CellSaveDataFileStat));
}
} }
s32 modifySaveDataFiles(vm::ptr<CellSaveDataFileCallback> funcFile, vm::ptr<CellSaveDataCBResult> result, const std::string& saveDataDir) s32 modifySaveDataFiles(vm::ptr<CellSaveDataFileCallback> funcFile, vm::ptr<CellSaveDataCBResult> result, const std::string& saveDataDir)
@@ -231,7 +265,7 @@ s32 modifySaveDataFiles(vm::ptr<CellSaveDataFileCallback> funcFile, vm::ptr<Cell
cellSysutil->Error("modifySaveDataFiles: CellSaveDataFileCallback failed."); // TODO: Once we verify that the entire SysCall is working, delete this debug error message. cellSysutil->Error("modifySaveDataFiles: CellSaveDataFileCallback failed."); // TODO: Once we verify that the entire SysCall is working, delete this debug error message.
return CELL_SAVEDATA_ERROR_CBRESULT; return CELL_SAVEDATA_ERROR_CBRESULT;
} }
if (result->result == CELL_SAVEDATA_CBRESULT_OK_LAST) { if (result->result == CELL_SAVEDATA_CBRESULT_OK_LAST || result->result == CELL_SAVEDATA_CBRESULT_OK_LAST_NOCONFIRM) {
break; break;
} }
@@ -637,7 +671,9 @@ int cellSaveDataAutoSave2(u32 version, vm::ptr<const char> dirName, u32 errDialo
result->userdata = userdata; result->userdata = userdata;
funcStat(result, statGet, statSet); funcStat(result, statGet, statSet);
if (statGet->fileList)
Memory.Free(statGet->fileList.addr()); Memory.Free(statGet->fileList.addr());
if (result->result < 0) { if (result->result < 0) {
cellSysutil->Error("cellSaveDataAutoSave2: CellSaveDataStatCallback failed."); // TODO: Once we verify that the entire SysCall is working, delete this debug error message. cellSysutil->Error("cellSaveDataAutoSave2: CellSaveDataStatCallback failed."); // TODO: Once we verify that the entire SysCall is working, delete this debug error message.
return CELL_SAVEDATA_ERROR_CBRESULT; return CELL_SAVEDATA_ERROR_CBRESULT;
+22 -12
View File
@@ -3,8 +3,13 @@
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/SysCalls/Modules.h" #include "Emu/SysCalls/Modules.h"
#include "Emu/SysCalls/CB_FUNC.h" #include "Emu/SysCalls/CB_FUNC.h"
#include "Emu/Memory/atomic_type.h"
#include "Emu/Cell/SPUThread.h" #include "Emu/Cell/SPUThread.h"
#include "Emu/SysCalls/lv2/sleep_queue_type.h"
#include "Emu/SysCalls/lv2/sys_lwmutex.h"
#include "Emu/SysCalls/lv2/sys_lwcond.h"
#include "Emu/SysCalls/lv2/sys_spu.h"
#include "Emu/SysCalls/lv2/sys_ppu_thread.h" #include "Emu/SysCalls/lv2/sys_ppu_thread.h"
#include "Emu/SysCalls/lv2/sys_memory.h" #include "Emu/SysCalls/lv2/sys_memory.h"
#include "Emu/SysCalls/lv2/sys_process.h" #include "Emu/SysCalls/lv2/sys_process.h"
@@ -251,13 +256,13 @@ s64 spursInit(
if (spurs->m.flags1 & SF1_EXIT_IF_NO_WORK) if (spurs->m.flags1 & SF1_EXIT_IF_NO_WORK)
{ {
if (s32 res = sys_lwmutex_lock(spurs->get_lwmutex(), 0)) if (s32 res = sys_lwmutex_lock(CPU, spurs->get_lwmutex(), 0))
{ {
assert(!"sys_lwmutex_lock() failed"); assert(!"sys_lwmutex_lock() failed");
} }
if (spurs->m.xD66.read_relaxed()) if (spurs->m.xD66.read_relaxed())
{ {
if (s32 res = sys_lwmutex_unlock(spurs->get_lwmutex())) if (s32 res = sys_lwmutex_unlock(CPU, spurs->get_lwmutex()))
{ {
assert(!"sys_lwmutex_unlock() failed"); assert(!"sys_lwmutex_unlock() failed");
} }
@@ -265,6 +270,8 @@ s64 spursInit(
} }
else while (true) else while (true)
{ {
if (Emu.IsStopped()) break;
spurs->m.xD64.exchange(0); spurs->m.xD64.exchange(0);
if (spurs->m.exception.ToBE() == 0) if (spurs->m.exception.ToBE() == 0)
{ {
@@ -311,7 +318,7 @@ s64 spursInit(
spurs->m.xD65.exchange(1); spurs->m.xD65.exchange(1);
if (spurs->m.xD64.read_relaxed() == 0) if (spurs->m.xD64.read_relaxed() == 0)
{ {
if (s32 res = sys_lwcond_wait(spurs->get_lwcond(), 0)) if (s32 res = sys_lwcond_wait(CPU, spurs->get_lwcond(), 0))
{ {
assert(!"sys_lwcond_wait() failed"); assert(!"sys_lwcond_wait() failed");
} }
@@ -319,14 +326,17 @@ s64 spursInit(
spurs->m.xD65.exchange(0); spurs->m.xD65.exchange(0);
if (spurs->m.xD66.read_relaxed()) if (spurs->m.xD66.read_relaxed())
{ {
if (s32 res = sys_lwmutex_unlock(spurs->get_lwmutex())) if (s32 res = sys_lwmutex_unlock(CPU, spurs->get_lwmutex()))
{ {
assert(!"sys_lwmutex_unlock() failed"); assert(!"sys_lwmutex_unlock() failed");
} }
return; return;
} }
} }
if (s32 res = sys_lwmutex_unlock(spurs->get_lwmutex()))
if (Emu.IsStopped()) continue;
if (s32 res = sys_lwmutex_unlock(CPU, spurs->get_lwmutex()))
{ {
assert(!"sys_lwmutex_unlock() failed"); assert(!"sys_lwmutex_unlock() failed");
} }
@@ -393,7 +403,7 @@ s64 spursInit(
} }
else if (flags & SAF_EXIT_IF_NO_WORK) // wakeup else if (flags & SAF_EXIT_IF_NO_WORK) // wakeup
{ {
return spursWakeUp(spurs); return spursWakeUp(GetCurrentPPUThread(), spurs);
} }
return CELL_OK; return CELL_OK;
@@ -953,7 +963,7 @@ s64 cellSpursGetInfo(vm::ptr<CellSpurs> spurs, vm::ptr<CellSpursInfo> info)
#endif #endif
} }
s64 spursWakeUp(vm::ptr<CellSpurs> spurs) s64 spursWakeUp(PPUThread& CPU, vm::ptr<CellSpurs> spurs)
{ {
#ifdef PRX_DEBUG_XXX #ifdef PRX_DEBUG_XXX
return cb_call<s32, vm::ptr<CellSpurs>>(GetCurrentPPUThread(), libsre + 0x84D8, libsre_rtoc, spurs); return cb_call<s32, vm::ptr<CellSpurs>>(GetCurrentPPUThread(), libsre + 0x84D8, libsre_rtoc, spurs);
@@ -975,7 +985,7 @@ s64 spursWakeUp(vm::ptr<CellSpurs> spurs)
spurs->m.xD64.exchange(1); spurs->m.xD64.exchange(1);
if (spurs->m.xD65.read_sync()) if (spurs->m.xD65.read_sync())
{ {
if (s32 res = sys_lwmutex_lock(spurs->get_lwmutex(), 0)) if (s32 res = sys_lwmutex_lock(CPU, spurs->get_lwmutex(), 0))
{ {
assert(!"sys_lwmutex_lock() failed"); assert(!"sys_lwmutex_lock() failed");
} }
@@ -983,7 +993,7 @@ s64 spursWakeUp(vm::ptr<CellSpurs> spurs)
{ {
assert(!"sys_lwcond_signal() failed"); assert(!"sys_lwcond_signal() failed");
} }
if (s32 res = sys_lwmutex_unlock(spurs->get_lwmutex())) if (s32 res = sys_lwmutex_unlock(CPU, spurs->get_lwmutex()))
{ {
assert(!"sys_lwmutex_unlock() failed"); assert(!"sys_lwmutex_unlock() failed");
} }
@@ -991,11 +1001,11 @@ s64 spursWakeUp(vm::ptr<CellSpurs> spurs)
return CELL_OK; return CELL_OK;
} }
s64 cellSpursWakeUp(vm::ptr<CellSpurs> spurs) s64 cellSpursWakeUp(PPUThread& CPU, vm::ptr<CellSpurs> spurs)
{ {
cellSpurs->Warning("%s(spurs_addr=0x%x)", __FUNCTION__, spurs.addr()); cellSpurs->Warning("%s(spurs_addr=0x%x)", __FUNCTION__, spurs.addr());
return spursWakeUp(spurs); return spursWakeUp(CPU, spurs);
} }
s32 spursAddWorkload( s32 spursAddWorkload(
@@ -2509,7 +2519,7 @@ s64 _cellSpursTaskAttribute2Initialize(vm::ptr<CellSpursTaskAttribute2> attribut
#else #else
attribute->revision = revision; attribute->revision = revision;
attribute->sizeContext = 0; attribute->sizeContext = 0;
attribute->eaContext = NULL; attribute->eaContext = 0;
for (s32 c = 0; c < 4; c++) for (s32 c = 0; c < 4; c++)
{ {
+1 -4
View File
@@ -1,7 +1,4 @@
#pragma once #pragma once
#include "Emu/SysCalls/lv2/sys_lwmutex.h"
#include "Emu/SysCalls/lv2/sys_lwcond.h"
#include "Emu/SysCalls/lv2/sys_spu.h"
// Core return codes. // Core return codes.
enum enum
@@ -820,4 +817,4 @@ struct SpursKernelMgmtData {
}; };
s64 spursAttachLv2EventQueue(vm::ptr<CellSpurs> spurs, u32 queue, vm::ptr<u8> port, s32 isDynamic, bool wasCreated); s64 spursAttachLv2EventQueue(vm::ptr<CellSpurs> spurs, u32 queue, vm::ptr<u8> port, s32 isDynamic, bool wasCreated);
s64 spursWakeUp(vm::ptr<CellSpurs> spurs); s64 spursWakeUp(PPUThread& CPU, vm::ptr<CellSpurs> spurs);
@@ -2,7 +2,12 @@
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/SysCalls/Modules.h" #include "Emu/SysCalls/Modules.h"
#include "Emu/Memory/atomic_type.h"
#include "Emu/SysCalls/lv2/sleep_queue_type.h"
#include "Emu/SysCalls/lv2/sys_lwmutex.h"
#include "Emu/SysCalls/lv2/sys_lwcond.h"
#include "Emu/SysCalls/lv2/sys_spu.h"
#include "cellSpurs.h" #include "cellSpurs.h"
#include "cellSpursJq.h" #include "cellSpursJq.h"
@@ -3,6 +3,9 @@
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/Cell/SPUThread.h" #include "Emu/Cell/SPUThread.h"
#include "Emu/SysCalls/Modules.h" #include "Emu/SysCalls/Modules.h"
#include "Emu/SysCalls/lv2/sys_lwmutex.h"
#include "Emu/SysCalls/lv2/sys_lwcond.h"
#include "Emu/SysCalls/lv2/sys_spu.h"
#include "Emu/SysCalls/Modules/cellSpurs.h" #include "Emu/SysCalls/Modules/cellSpurs.h"
// //
+28 -30
View File
@@ -1,21 +1,10 @@
#include "stdafx.h" #include "stdafx.h"
#if 0 #include "Emu/Memory/Memory.h"
#include "Emu/SysCalls/Modules.h"
void cellSubdisplay_init(); #include "cellSubdisplay.h"
Module cellSubdisplay(0x0034, cellSubdisplay_init);
// Return Codes Module *cellSubdisplay = nullptr;
enum
{
CELL_SUBDISPLAY_ERROR_OUT_OF_MEMORY = 0x80029851,
CELL_SUBDISPLAY_ERROR_FATAL = 0x80029852,
CELL_SUBDISPLAY_ERROR_NOT_FOUND = 0x80029853,
CELL_SUBDISPLAY_ERROR_INVALID_VALUE = 0x80029854,
CELL_SUBDISPLAY_ERROR_NOT_INITIALIZED = 0x80029855,
CELL_SUBDISPLAY_ERROR_SET_SAMPLE = 0x80029860,
CELL_SUBDISPLAY_ERROR_AUDIOOUT_IS_BUSY = 0x80029861,
CELL_SUBDISPLAY_ERROR_ZERO_REGISTERED = 0x80029813,
};
int cellSubDisplayInit() int cellSubDisplayInit()
{ {
@@ -29,10 +18,18 @@ int cellSubDisplayEnd()
return CELL_OK; return CELL_OK;
} }
int cellSubDisplayGetRequiredMemory() int cellSubDisplayGetRequiredMemory(vm::ptr<CellSubDisplayParam> pParam)
{ {
UNIMPLEMENTED_FUNC(cellSubdisplay); cellSubdisplay->Warning("cellSubDisplayGetRequiredMemory(pParam_addr=0x%x)", pParam.addr());
return CELL_OK;
if (pParam->version == CELL_SUBDISPLAY_VERSION_0002)
{
return CELL_SUBDISPLAY_0002_MEMORY_CONTAINER_SIZE;
}
else
{
return CELL_SUBDISPLAY_0001_MEMORY_CONTAINER_SIZE;
}
} }
int cellSubDisplayStart() int cellSubDisplayStart()
@@ -77,19 +74,20 @@ int cellSubDisplayGetPeerList()
return CELL_OK; return CELL_OK;
} }
void cellSubdisplay_init() void cellSubdisplay_init(Module *pxThis)
{ {
cellSubdisplay.AddFunc(0xf9a7e8a5, cellSubDisplayInit); cellSubdisplay = pxThis;
cellSubdisplay.AddFunc(0x551d80a5, cellSubDisplayEnd);
cellSubdisplay.AddFunc(0x6595ce22, cellSubDisplayGetRequiredMemory);
cellSubdisplay.AddFunc(0xa5bccb47, cellSubDisplayStart);
cellSubdisplay.AddFunc(0x6d85ddb3, cellSubDisplayStop);
cellSubdisplay.AddFunc(0x938ac642, cellSubDisplayGetVideoBuffer); cellSubdisplay->AddFunc(0xf9a7e8a5, cellSubDisplayInit);
cellSubdisplay.AddFunc(0xaee1e0c2, cellSubDisplayAudioOutBlocking); cellSubdisplay->AddFunc(0x551d80a5, cellSubDisplayEnd);
cellSubdisplay.AddFunc(0x5468d6b0, cellSubDisplayAudioOutNonBlocking); cellSubdisplay->AddFunc(0x6595ce22, cellSubDisplayGetRequiredMemory);
cellSubdisplay->AddFunc(0xa5bccb47, cellSubDisplayStart);
cellSubdisplay->AddFunc(0x6d85ddb3, cellSubDisplayStop);
cellSubdisplay.AddFunc(0x8a264d71, cellSubDisplayGetPeerNum); cellSubdisplay->AddFunc(0x938ac642, cellSubDisplayGetVideoBuffer);
cellSubdisplay.AddFunc(0xe2485f79, cellSubDisplayGetPeerList); cellSubdisplay->AddFunc(0xaee1e0c2, cellSubDisplayAudioOutBlocking);
cellSubdisplay->AddFunc(0x5468d6b0, cellSubDisplayAudioOutNonBlocking);
cellSubdisplay->AddFunc(0x8a264d71, cellSubDisplayGetPeerNum);
cellSubdisplay->AddFunc(0xe2485f79, cellSubDisplayGetPeerList);
} }
#endif
@@ -0,0 +1,83 @@
#pragma once
// Return Codes
enum
{
CELL_SUBDISPLAY_ERROR_OUT_OF_MEMORY = 0x80029851,
CELL_SUBDISPLAY_ERROR_FATAL = 0x80029852,
CELL_SUBDISPLAY_ERROR_NOT_FOUND = 0x80029853,
CELL_SUBDISPLAY_ERROR_INVALID_VALUE = 0x80029854,
CELL_SUBDISPLAY_ERROR_NOT_INITIALIZED = 0x80029855,
CELL_SUBDISPLAY_ERROR_SET_SAMPLE = 0x80029860,
CELL_SUBDISPLAY_ERROR_AUDIOOUT_IS_BUSY = 0x80029861,
CELL_SUBDISPLAY_ERROR_ZERO_REGISTERED = 0x80029813,
};
// Different constants
enum
{
CELL_SUBDISPLAY_STATUS_JOIN = 1,
CELL_SUBDISPLAY_STATUS_LEAVE = 2,
CELL_SUBDISPLAY_STATUS_FATALERROR = 3,
CELL_SUBDISPLAY_VERSION_0001 = 1,
CELL_SUBDISPLAY_VERSION_0002 = 2,
CELL_SUBDISPLAY_MODE_REMOTEPLAY = 1,
CELL_SUBDISPLAY_VIDEO_FORMAT_A8R8G8B8 = 1,
CELL_SUBDISPLAY_VIDEO_FORMAT_R8G8B8A8 = 2,
CELL_SUBDISPLAY_VIDEO_ASPECT_RATIO_16_9 = 0,
CELL_SUBDISPLAY_VIDEO_ASPECT_RATIO_4_3 = 1,
CELL_SUBDISPLAY_VIDEO_MODE_SETDATA = 0,
CELL_SUBDISPLAY_VIDEO_MODE_CAPTURE = 1,
CELL_SUBDISPLAY_AUDIO_MODE_SETDATA = 0,
CELL_SUBDISPLAY_AUDIO_MODE_CAPTURE = 1,
CELL_SUBDISPLAY_0001_MEMORY_CONTAINER_SIZE = 8 * 1024 * 1024,
CELL_SUBDISPLAY_0002_MEMORY_CONTAINER_SIZE = 10 * 1024 * 1024,
CELL_SUBDISPLAY_NICKNAME_LEN = 256,
CELL_SUBDISPLAY_PSPID_LEN = 16,
};
struct CellSubDisplayVideoParam
{
be_t<s32> format;
be_t<s32> width;
be_t<s32> height;
be_t<s32> pitch;
be_t<s32> aspectRatio;
be_t<s32> videoMode;
};
struct CellSubDisplayAudioParam
{
be_t<s32> ch;
be_t<s32> audioMode;
};
struct CellSubDisplayParam
{
be_t<s32> version;
be_t<s32> mode;
be_t<s32> nGroup;
be_t<s32> nPeer;
vm::ptr<CellSubDisplayVideoParam> videoParam;
vm::ptr<CellSubDisplayAudioParam> audioParam;
};
struct CellSubDisplayPSPId
{
char data[CELL_SUBDISPLAY_PSPID_LEN];
};
struct CellSubDisplayNickname
{
char data[CELL_SUBDISPLAY_NICKNAME_LEN];
};
struct CellSubDisplayPeerInfo
{
be_t<u64> sessionId;
be_t<u32> portNo;
CellSubDisplayPSPId pspId;
CellSubDisplayNickname pspNickname;
};
typedef void(*CellSubDisplayHandler)(s32 cbMsg, u64 cbParam, u32 *userdata);
+3
View File
@@ -3,7 +3,10 @@
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/SysCalls/Modules.h" #include "Emu/SysCalls/Modules.h"
#include "Emu/SysCalls/CB_FUNC.h" #include "Emu/SysCalls/CB_FUNC.h"
#include "Emu/Memory/atomic_type.h"
#include "Emu/SysCalls/lv2/sleep_queue_type.h"
#include "Emu/SysCalls/lv2/sys_event.h"
#include "Emu/SysCalls/lv2/sys_process.h" #include "Emu/SysCalls/lv2/sys_process.h"
#include "Emu/Event.h" #include "Emu/Event.h"
#include "cellSync.h" #include "cellSync.h"
+5 -5
View File
@@ -286,13 +286,13 @@ int cellVideoOutGetNumberOfDevice(u32 videoOut)
int cellVideoOutGetResolutionAvailability(u32 videoOut, u32 resolutionId, u32 aspect, u32 option) int cellVideoOutGetResolutionAvailability(u32 videoOut, u32 resolutionId, u32 aspect, u32 option)
{ {
cellSysutil->Warning("cellVideoOutGetResolutionAvailability(videoOut=%d, resolutionId=0x%x, option_addr=0x%x, aspect=0x%x, option=0x%x)", cellSysutil->Warning("cellVideoOutGetResolutionAvailability(videoOut=%d, resolutionId=0x%x, option_addr=0x%x, aspect=%d, option=%d)",
videoOut, resolutionId, aspect, option); videoOut, resolutionId, aspect, option);
if(!ResolutionIdToNum(resolutionId)) if (!Ini.GS3DTV.GetValue() && (resolutionId == CELL_VIDEO_OUT_RESOLUTION_720_3D_FRAME_PACKING || resolutionId == CELL_VIDEO_OUT_RESOLUTION_1024x720_3D_FRAME_PACKING ||
{ resolutionId == CELL_VIDEO_OUT_RESOLUTION_960x720_3D_FRAME_PACKING || resolutionId == CELL_VIDEO_OUT_RESOLUTION_800x720_3D_FRAME_PACKING ||
return CELL_EINVAL; resolutionId == CELL_VIDEO_OUT_RESOLUTION_640x720_3D_FRAME_PACKING))
} return 0;
switch(videoOut) switch(videoOut)
{ {
+248 -122
View File
@@ -19,6 +19,8 @@ extern "C"
Module *cellVdec = nullptr; Module *cellVdec = nullptr;
#define VDEC_ERROR(...) { cellVdec->Error(__VA_ARGS__); Emu.Pause(); return; } // only for decoder thread
VideoDecoder::VideoDecoder(CellVdecCodecType type, u32 profile, u32 addr, u32 size, vm::ptr<CellVdecCbMsg> func, u32 arg) VideoDecoder::VideoDecoder(CellVdecCodecType type, u32 profile, u32 addr, u32 size, vm::ptr<CellVdecCbMsg> func, u32 arg)
: type(type) : type(type)
, profile(profile) , profile(profile)
@@ -31,33 +33,59 @@ VideoDecoder::VideoDecoder(CellVdecCodecType type, u32 profile, u32 addr, u32 si
, is_closed(false) , is_closed(false)
, just_started(false) , just_started(false)
, just_finished(false) , just_finished(false)
, frc_set(0)
, codec(nullptr)
, input_format(nullptr)
, ctx(nullptr) , ctx(nullptr)
, vdecCb(nullptr) , vdecCb(nullptr)
{ {
av_register_all(); av_register_all();
avcodec_register_all(); avcodec_register_all();
AVCodec* codec = avcodec_find_decoder(AV_CODEC_ID_H264); switch (type)
{
case CELL_VDEC_CODEC_TYPE_MPEG2:
{
codec = avcodec_find_decoder(AV_CODEC_ID_MPEG2VIDEO);
input_format = av_find_input_format("mpeg");
break;
}
case CELL_VDEC_CODEC_TYPE_AVC:
{
codec = avcodec_find_decoder(AV_CODEC_ID_H264);
input_format = av_find_input_format("mpeg");
break;
}
case CELL_VDEC_CODEC_TYPE_DIVX:
{
codec = avcodec_find_decoder(AV_CODEC_ID_MPEG4);
input_format = av_find_input_format("mpeg");
break;
}
default:
{
VDEC_ERROR("VideoDecoder(): unknown type (0x%x)", type);
}
}
if (!codec) if (!codec)
{ {
cellVdec->Error("VideoDecoder(): avcodec_find_decoder(H264) failed"); VDEC_ERROR("VideoDecoder(): avcodec_find_decoder() failed");
Emu.Pause(); }
return; if (!input_format)
{
VDEC_ERROR("VideoDecoder(): av_find_input_format() failed");
} }
fmt = avformat_alloc_context(); fmt = avformat_alloc_context();
if (!fmt) if (!fmt)
{ {
cellVdec->Error("VideoDecoder(): avformat_alloc_context failed"); VDEC_ERROR("VideoDecoder(): avformat_alloc_context() failed");
Emu.Pause();
return;
} }
io_buf = (u8*)av_malloc(4096); io_buf = (u8*)av_malloc(4096);
fmt->pb = avio_alloc_context(io_buf, 4096, 0, this, vdecRead, NULL, NULL); fmt->pb = avio_alloc_context(io_buf, 4096, 0, this, vdecRead, NULL, NULL);
if (!fmt->pb) if (!fmt->pb)
{ {
cellVdec->Error("VideoDecoder(): avio_alloc_context failed"); VDEC_ERROR("VideoDecoder(): avio_alloc_context() failed");
Emu.Pause();
return;
} }
} }
@@ -65,7 +93,7 @@ VideoDecoder::~VideoDecoder()
{ {
// TODO: check finalization // TODO: check finalization
VdecFrame vf; VdecFrame vf;
while (frames.Pop(vf, &sq_no_wait)) while (frames.try_pop(vf))
{ {
av_frame_unref(vf.data); av_frame_unref(vf.data);
av_frame_free(&vf.data); av_frame_free(&vf.data);
@@ -96,7 +124,7 @@ next:
if (vdec.reader.size < (u32)buf_size /*&& !vdec.just_started*/) if (vdec.reader.size < (u32)buf_size /*&& !vdec.just_started*/)
{ {
VdecTask task; VdecTask task;
if (!vdec.job.Peek(task, &vdec.is_closed)) if (!vdec.job.peek(task, 0, &vdec.is_closed))
{ {
if (Emu.IsStopped()) cellVdec->Warning("vdecRead() aborted"); if (Emu.IsStopped()) cellVdec->Warning("vdecRead() aborted");
return 0; return 0;
@@ -121,7 +149,7 @@ next:
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, nullptr); vdec.job.pop(vdec.task);
vdec.reader.addr = vdec.task.addr; vdec.reader.addr = vdec.task.addr;
vdec.reader.size = vdec.task.size; vdec.reader.size = vdec.task.size;
@@ -163,8 +191,8 @@ u32 vdecQueryAttr(CellVdecCodecType type, u32 profile, u32 spec_addr /* may be 0
switch (type) // TODO: check profile levels switch (type) // TODO: check profile levels
{ {
case CELL_VDEC_CODEC_TYPE_AVC: cellVdec->Warning("cellVdecQueryAttr: AVC (profile=%d)", profile); break; case CELL_VDEC_CODEC_TYPE_AVC: cellVdec->Warning("cellVdecQueryAttr: AVC (profile=%d)", profile); break;
case CELL_VDEC_CODEC_TYPE_MPEG2: cellVdec->Todo("MPEG2 not supported"); break; case CELL_VDEC_CODEC_TYPE_MPEG2: cellVdec->Warning("cellVdecQueryAttr: MPEG2 (profile=%d)", profile); break;
case CELL_VDEC_CODEC_TYPE_DIVX: cellVdec->Todo("DIVX not supported"); break; case CELL_VDEC_CODEC_TYPE_DIVX: cellVdec->Warning("cellVdecQueryAttr: DivX (profile=%d)", profile); break;
default: return CELL_VDEC_ERROR_ARG; default: return CELL_VDEC_ERROR_ARG;
} }
@@ -176,11 +204,12 @@ u32 vdecQueryAttr(CellVdecCodecType type, u32 profile, u32 spec_addr /* may be 0
return CELL_OK; return CELL_OK;
} }
u32 vdecOpen(VideoDecoder* data) u32 vdecOpen(VideoDecoder* vdec_ptr)
{ {
VideoDecoder& vdec = *data; std::shared_ptr<VideoDecoder> sptr(vdec_ptr);
VideoDecoder& vdec = *vdec_ptr;
u32 vdec_id = cellVdec->GetNewId(data); u32 vdec_id = cellVdec->GetNewId(sptr);
vdec.id = vdec_id; vdec.id = vdec_id;
@@ -193,8 +222,9 @@ u32 vdecOpen(VideoDecoder* data)
vdec.vdecCb->InitRegs(); vdec.vdecCb->InitRegs();
vdec.vdecCb->DoRun(); vdec.vdecCb->DoRun();
thread t("Video Decoder[" + std::to_string(vdec_id) + "] Thread", [&]() thread t("Video Decoder[" + std::to_string(vdec_id) + "] Thread", [vdec_ptr, sptr]()
{ {
VideoDecoder& vdec = *vdec_ptr;
cellVdec->Notice("Video Decoder thread started"); cellVdec->Notice("Video Decoder thread started");
VdecTask& task = vdec.task; VdecTask& task = vdec.task;
@@ -206,13 +236,7 @@ u32 vdecOpen(VideoDecoder* data)
break; break;
} }
//if (!vdec.job.GetCountUnsafe() && vdec.is_running) if (!vdec.job.pop(task, &vdec.is_closed))
//{
// std::this_thread::sleep_for(std::chrono::milliseconds(1));
// continue;
//}
if (!vdec.job.Pop(task, &vdec.is_closed))
{ {
break; break;
} }
@@ -225,9 +249,10 @@ u32 vdecOpen(VideoDecoder* data)
cellVdec->Warning("vdecStartSeq:"); cellVdec->Warning("vdecStartSeq:");
vdec.reader = {}; vdec.reader = {};
vdec.frc_set = 0;
vdec.just_started = true; vdec.just_started = true;
}
break; break;
}
case vdecEndSeq: case vdecEndSeq:
{ {
@@ -237,8 +262,8 @@ u32 vdecOpen(VideoDecoder* data)
vdec.cbFunc.call(*vdec.vdecCb, vdec.id, CELL_VDEC_MSG_TYPE_SEQDONE, CELL_OK, vdec.cbArg); vdec.cbFunc.call(*vdec.vdecCb, vdec.id, CELL_VDEC_MSG_TYPE_SEQDONE, CELL_OK, vdec.cbArg);
vdec.just_finished = true; vdec.just_finished = true;
}
break; break;
}
case vdecDecodeAu: case vdecDecodeAu:
{ {
@@ -257,7 +282,7 @@ u32 vdecOpen(VideoDecoder* data)
if (vdec.just_started) if (vdec.just_started)
{ {
vdec.first_pts = task.pts; vdec.first_pts = task.pts;
vdec.last_pts = task.pts; vdec.last_pts = -1;
vdec.first_dts = task.dts; vdec.first_dts = task.dts;
} }
@@ -296,54 +321,42 @@ u32 vdecOpen(VideoDecoder* data)
} }
else if (vdec.just_started) // deferred initialization else if (vdec.just_started) // deferred initialization
{ {
err = avformat_open_input(&vdec.fmt, NULL, av_find_input_format("mpeg"), NULL); AVDictionary* opts = nullptr;
if (err) av_dict_set(&opts, "probesize", "4096", 0);
err = avformat_open_input(&vdec.fmt, NULL, NULL, &opts);
if (err || opts)
{ {
cellVdec->Error("vdecDecodeAu: avformat_open_input() failed"); VDEC_ERROR("vdecDecodeAu: avformat_open_input() failed (err=0x%x, opts=%d)", err, opts ? 1 : 0);
Emu.Pause();
break;
} }
AVCodec* codec = avcodec_find_decoder(AV_CODEC_ID_H264); // ??? if (vdec.type == CELL_VDEC_CODEC_TYPE_DIVX)
if (!codec)
{ {
cellVdec->Error("vdecDecodeAu: avcodec_find_decoder() failed"); err = avformat_find_stream_info(vdec.fmt, NULL);
Emu.Pause(); if (err || !vdec.fmt->nb_streams)
break; {
VDEC_ERROR("vdecDecodeAu: avformat_find_stream_info() failed (err=0x%x, nb_streams=%d)", err, vdec.fmt->nb_streams);
} }
/*err = avformat_find_stream_info(vdec.fmt, NULL);
if (err)
{
LOG_ERROR(HLE, "vdecDecodeAu: avformat_find_stream_info() failed");
Emu.Pause();
break;
} }
if (!vdec.fmt->nb_streams) else
{ {
LOG_ERROR(HLE, "vdecDecodeAu: no stream found"); if (!avformat_new_stream(vdec.fmt, vdec.codec))
Emu.Pause();
break;
}*/
if (!avformat_new_stream(vdec.fmt, codec))
{ {
cellVdec->Error("vdecDecodeAu: avformat_new_stream() failed"); VDEC_ERROR("vdecDecodeAu: avformat_new_stream() failed");
Emu.Pause(); }
break;
} }
vdec.ctx = vdec.fmt->streams[0]->codec; // TODO: check data vdec.ctx = vdec.fmt->streams[0]->codec; // TODO: check data
AVDictionary* opts = nullptr; opts = nullptr;
av_dict_set(&opts, "refcounted_frames", "1", 0); av_dict_set(&opts, "refcounted_frames", "1", 0);
{ {
std::lock_guard<std::mutex> lock(g_mutex_avcodec_open2); std::lock_guard<std::mutex> lock(g_mutex_avcodec_open2);
// not multithread-safe (???) // not multithread-safe (???)
err = avcodec_open2(vdec.ctx, codec, &opts); err = avcodec_open2(vdec.ctx, vdec.codec, &opts);
} }
if (err) if (err || opts)
{ {
cellVdec->Error("vdecDecodeAu: avcodec_open2() failed"); VDEC_ERROR("vdecDecodeAu: avcodec_open2() failed (err=0x%x, opts=%d)", err, opts ? 1 : 0);
Emu.Pause();
break;
} }
vdec.just_started = false; vdec.just_started = false;
} }
@@ -386,9 +399,7 @@ u32 vdecOpen(VideoDecoder* data)
if (!frame.data) if (!frame.data)
{ {
cellVdec->Error("vdecDecodeAu: av_frame_alloc() failed"); VDEC_ERROR("vdecDecodeAu: av_frame_alloc() failed");
Emu.Pause();
break;
} }
int got_picture = 0; int got_picture = 0;
@@ -397,7 +408,7 @@ u32 vdecOpen(VideoDecoder* data)
if (decode <= 0) if (decode <= 0)
{ {
if (!last_frame && decode < 0) if (decode < 0)
{ {
cellVdec->Error("vdecDecodeAu: AU decoding error(0x%x)", decode); cellVdec->Error("vdecDecodeAu: AU decoding error(0x%x)", decode);
} }
@@ -406,25 +417,103 @@ u32 vdecOpen(VideoDecoder* data)
if (got_picture) if (got_picture)
{ {
u64 ts = av_frame_get_best_effort_timestamp(frame.data); if (frame.data->interlaced_frame)
if (ts != AV_NOPTS_VALUE)
{ {
frame.pts = ts/* - vdec.first_pts*/; // ??? VDEC_ERROR("vdecDecodeAu: interlaced frames not supported (0x%x)", frame.data->interlaced_frame);
vdec.last_pts = frame.pts; }
if (frame.data->repeat_pict)
{
VDEC_ERROR("vdecDecodeAu: repeated frames not supported (0x%x)", frame.data->repeat_pict);
}
if (vdec.frc_set)
{
if (vdec.last_pts == -1)
{
vdec.last_pts = 0x8000; //av_frame_get_best_effort_timestamp(frame.data);
}
else switch (vdec.frc_set)
{
case CELL_VDEC_FRC_24000DIV1001: vdec.last_pts += 1001 * 90000 / 24000; break;
case CELL_VDEC_FRC_24: vdec.last_pts += 90000 / 24; break;
case CELL_VDEC_FRC_25: vdec.last_pts += 90000 / 25; break;
case CELL_VDEC_FRC_30000DIV1001: vdec.last_pts += 1001 * 90000 / 30000; break;
case CELL_VDEC_FRC_30: vdec.last_pts += 90000 / 30; break;
case CELL_VDEC_FRC_50: vdec.last_pts += 90000 / 50; break;
case CELL_VDEC_FRC_60000DIV1001: vdec.last_pts += 1001 * 90000 / 60000; break;
case CELL_VDEC_FRC_60: vdec.last_pts += 90000 / 60; break;
default:
{
VDEC_ERROR("vdecDecodeAu: invalid frame rate code set (0x%x)", vdec.frc_set);
}
}
frame.frc = vdec.frc_set;
} }
else else
{ {
vdec.last_pts += vdec.ctx->time_base.num * 90000 / (vdec.ctx->time_base.den / vdec.ctx->ticks_per_frame); u64 ts = av_frame_get_best_effort_timestamp(frame.data);
frame.pts = vdec.last_pts; if (ts != AV_NOPTS_VALUE)
{
vdec.last_pts = ts;
} }
//frame.pts = vdec.last_pts; else if (vdec.last_pts == -1)
//vdec.last_pts += 3754; {
vdec.last_pts = 0;
}
else
{
vdec.last_pts += vdec.ctx->time_base.num * 90000 * vdec.ctx->ticks_per_frame / vdec.ctx->time_base.den;
}
if (vdec.ctx->time_base.num == 1)
{
switch ((u64)vdec.ctx->time_base.den + (u64)(vdec.ctx->ticks_per_frame - 1) * 0x100000000ull)
{
case 24: case 0x100000000ull + 48: frame.frc = CELL_VDEC_FRC_24; break;
case 25: case 0x100000000ull + 50: frame.frc = CELL_VDEC_FRC_25; break;
case 30: case 0x100000000ull + 60: frame.frc = CELL_VDEC_FRC_30; break;
case 50: case 0x100000000ull + 100: frame.frc = CELL_VDEC_FRC_50; break;
case 60: case 0x100000000ull + 120: frame.frc = CELL_VDEC_FRC_60; break;
default:
{
VDEC_ERROR("vdecDecodeAu: unsupported time_base.den (%d/1, tpf=%d)", vdec.ctx->time_base.den, vdec.ctx->ticks_per_frame);
}
}
}
else if (vdec.ctx->time_base.num == 1001)
{
if (vdec.ctx->time_base.den / vdec.ctx->ticks_per_frame == 24000)
{
frame.frc = CELL_VDEC_FRC_24000DIV1001;
}
else if (vdec.ctx->time_base.den / vdec.ctx->ticks_per_frame == 30000)
{
frame.frc = CELL_VDEC_FRC_30000DIV1001;
}
else if (vdec.ctx->time_base.den / vdec.ctx->ticks_per_frame == 60000)
{
frame.frc = CELL_VDEC_FRC_60000DIV1001;
}
else
{
VDEC_ERROR("vdecDecodeAu: unsupported time_base.den (%d/1001, tpf=%d)", vdec.ctx->time_base.den, vdec.ctx->ticks_per_frame);
}
}
else
{
VDEC_ERROR("vdecDecodeAu: unsupported time_base.num (%d)", vdec.ctx->time_base.num);
}
}
frame.pts = vdec.last_pts;
frame.dts = (frame.pts - vdec.first_pts) + vdec.first_dts; frame.dts = (frame.pts - vdec.first_pts) + vdec.first_dts;
frame.userdata = task.userData; frame.userdata = task.userData;
//LOG_NOTICE(HLE, "got picture (pts=0x%llx, dts=0x%llx)", frame.pts, frame.dts); //LOG_NOTICE(HLE, "got picture (pts=0x%llx, dts=0x%llx)", frame.pts, frame.dts);
if (vdec.frames.Push(frame, &vdec.is_closed)) if (vdec.frames.push(frame, &vdec.is_closed))
{ {
frame.data = nullptr; // to prevent destruction frame.data = nullptr; // to prevent destruction
vdec.cbFunc.call(*vdec.vdecCb, vdec.id, CELL_VDEC_MSG_TYPE_PICOUT, CELL_OK, vdec.cbArg); vdec.cbFunc.call(*vdec.vdecCb, vdec.id, CELL_VDEC_MSG_TYPE_PICOUT, CELL_OK, vdec.cbArg);
@@ -433,23 +522,24 @@ u32 vdecOpen(VideoDecoder* data)
} }
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);
}
break; break;
}
case vdecSetFrameRate: case vdecSetFrameRate:
{ {
cellVdec->Error("TODO: vdecSetFrameRate(%d)", task.frc); cellVdec->Warning("vdecSetFrameRate(0x%x)", task.frc);
Emu.Pause(); vdec.frc_set = task.frc;
}
break; break;
}
case vdecClose: break; case vdecClose:
{
break;
}
default: default:
{ {
cellVdec->Error("Video Decoder thread error: unknown task(%d)", task.type); VDEC_ERROR("Video Decoder thread error: unknown task(%d)", task.type);
Emu.Pause();
return;
} }
} }
} }
@@ -502,14 +592,14 @@ int cellVdecClose(u32 handle)
{ {
cellVdec->Warning("cellVdecClose(handle=%d)", handle); cellVdec->Warning("cellVdecClose(handle=%d)", handle);
VideoDecoder* vdec; std::shared_ptr<VideoDecoder> vdec;
if (!Emu.GetIdManager().GetIDData(handle, vdec)) if (!Emu.GetIdManager().GetIDData(handle, vdec))
{ {
return CELL_VDEC_ERROR_ARG; return CELL_VDEC_ERROR_ARG;
} }
vdec->is_closed = true; vdec->is_closed = true;
vdec->job.Push(VdecTask(vdecClose), &sq_no_wait); vdec->job.try_push(VdecTask(vdecClose));
while (!vdec->is_finished) while (!vdec->is_finished)
{ {
@@ -518,7 +608,7 @@ int cellVdecClose(u32 handle)
cellVdec->Warning("cellVdecClose(%d) aborted", handle); cellVdec->Warning("cellVdecClose(%d) aborted", handle);
break; break;
} }
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
} }
if (vdec->vdecCb) Emu.GetCPU().RemoveThread(vdec->vdecCb->GetId()); if (vdec->vdecCb) Emu.GetCPU().RemoveThread(vdec->vdecCb->GetId());
@@ -530,13 +620,13 @@ int cellVdecStartSeq(u32 handle)
{ {
cellVdec->Log("cellVdecStartSeq(handle=%d)", handle); cellVdec->Log("cellVdecStartSeq(handle=%d)", handle);
VideoDecoder* vdec; std::shared_ptr<VideoDecoder> vdec;
if (!Emu.GetIdManager().GetIDData(handle, vdec)) if (!Emu.GetIdManager().GetIDData(handle, vdec))
{ {
return CELL_VDEC_ERROR_ARG; return CELL_VDEC_ERROR_ARG;
} }
vdec->job.Push(VdecTask(vdecStartSeq), &vdec->is_closed); vdec->job.push(VdecTask(vdecStartSeq), &vdec->is_closed);
return CELL_OK; return CELL_OK;
} }
@@ -544,13 +634,13 @@ int cellVdecEndSeq(u32 handle)
{ {
cellVdec->Warning("cellVdecEndSeq(handle=%d)", handle); cellVdec->Warning("cellVdecEndSeq(handle=%d)", handle);
VideoDecoder* vdec; std::shared_ptr<VideoDecoder> vdec;
if (!Emu.GetIdManager().GetIDData(handle, vdec)) if (!Emu.GetIdManager().GetIDData(handle, vdec))
{ {
return CELL_VDEC_ERROR_ARG; return CELL_VDEC_ERROR_ARG;
} }
vdec->job.Push(VdecTask(vdecEndSeq), &vdec->is_closed); vdec->job.push(VdecTask(vdecEndSeq), &vdec->is_closed);
return CELL_OK; return CELL_OK;
} }
@@ -558,7 +648,7 @@ int cellVdecDecodeAu(u32 handle, CellVdecDecodeMode mode, vm::ptr<const CellVdec
{ {
cellVdec->Log("cellVdecDecodeAu(handle=%d, mode=0x%x, auInfo_addr=0x%x)", handle, mode, auInfo.addr()); cellVdec->Log("cellVdecDecodeAu(handle=%d, mode=0x%x, auInfo_addr=0x%x)", handle, mode, auInfo.addr());
VideoDecoder* vdec; std::shared_ptr<VideoDecoder> vdec;
if (!Emu.GetIdManager().GetIDData(handle, vdec)) if (!Emu.GetIdManager().GetIDData(handle, vdec))
{ {
return CELL_VDEC_ERROR_ARG; return CELL_VDEC_ERROR_ARG;
@@ -574,7 +664,7 @@ int cellVdecDecodeAu(u32 handle, CellVdecDecodeMode mode, vm::ptr<const CellVdec
task.userData = auInfo->userData; task.userData = auInfo->userData;
task.specData = auInfo->codecSpecificData; task.specData = auInfo->codecSpecificData;
vdec->job.Push(task, &vdec->is_closed); vdec->job.push(task, &vdec->is_closed);
return CELL_OK; return CELL_OK;
} }
@@ -582,14 +672,14 @@ int cellVdecGetPicture(u32 handle, vm::ptr<const CellVdecPicFormat> format, vm::
{ {
cellVdec->Log("cellVdecGetPicture(handle=%d, format_addr=0x%x, outBuff_addr=0x%x)", handle, format.addr(), outBuff.addr()); cellVdec->Log("cellVdecGetPicture(handle=%d, format_addr=0x%x, outBuff_addr=0x%x)", handle, format.addr(), outBuff.addr());
VideoDecoder* vdec; std::shared_ptr<VideoDecoder> vdec;
if (!Emu.GetIdManager().GetIDData(handle, vdec)) if (!Emu.GetIdManager().GetIDData(handle, vdec))
{ {
return CELL_VDEC_ERROR_ARG; return CELL_VDEC_ERROR_ARG;
} }
VdecFrame vf; VdecFrame vf;
if (!vdec->frames.Pop(vf, &sq_no_wait)) if (!vdec->frames.try_pop(vf))
{ {
//std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack //std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
return CELL_VDEC_ERROR_EMPTY; return CELL_VDEC_ERROR_EMPTY;
@@ -624,7 +714,7 @@ int cellVdecGetPicture(u32 handle, vm::ptr<const CellVdecPicFormat> format, vm::
int err = av_image_copy_to_buffer(outBuff.get_ptr(), buf_size, frame.data, frame.linesize, vdec->ctx->pix_fmt, frame.width, frame.height, 1); int err = av_image_copy_to_buffer(outBuff.get_ptr(), buf_size, frame.data, frame.linesize, vdec->ctx->pix_fmt, frame.width, frame.height, 1);
if (err < 0) if (err < 0)
{ {
cellVdec->Error("cellVdecGetPicture: av_image_copy_to_buffer failed(%d)", err); cellVdec->Error("cellVdecGetPicture: av_image_copy_to_buffer failed (err=0x%x)", err);
Emu.Pause(); Emu.Pause();
} }
} }
@@ -638,14 +728,14 @@ int cellVdecGetPicItem(u32 handle, vm::ptr<u32> picItem_ptr)
{ {
cellVdec->Log("cellVdecGetPicItem(handle=%d, picItem_ptr_addr=0x%x)", handle, picItem_ptr.addr()); cellVdec->Log("cellVdecGetPicItem(handle=%d, picItem_ptr_addr=0x%x)", handle, picItem_ptr.addr());
VideoDecoder* vdec; std::shared_ptr<VideoDecoder> vdec;
if (!Emu.GetIdManager().GetIDData(handle, vdec)) if (!Emu.GetIdManager().GetIDData(handle, vdec))
{ {
return CELL_VDEC_ERROR_ARG; return CELL_VDEC_ERROR_ARG;
} }
VdecFrame vf; VdecFrame vf;
if (!vdec->frames.Peek(vf, &sq_no_wait)) if (!vdec->frames.try_peek(vf))
{ {
//std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack //std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
return CELL_VDEC_ERROR_EMPTY; return CELL_VDEC_ERROR_EMPTY;
@@ -667,18 +757,20 @@ int cellVdecGetPicItem(u32 handle, vm::ptr<u32> picItem_ptr)
info->auNum = 1; info->auNum = 1;
info->auPts[0].lower = (u32)vf.pts; info->auPts[0].lower = (u32)vf.pts;
info->auPts[0].upper = vf.pts >> 32; info->auPts[0].upper = vf.pts >> 32;
info->auPts[1].lower = 0xffffffff; info->auPts[1].lower = (u32)CODEC_TS_INVALID;
info->auPts[1].upper = 0xffffffff; info->auPts[1].upper = (u32)CODEC_TS_INVALID;
info->auDts[0].lower = (u32)vf.dts; info->auDts[0].lower = (u32)vf.dts;
info->auDts[0].upper = vf.dts >> 32; info->auDts[0].upper = vf.dts >> 32;
info->auDts[1].lower = 0xffffffff; info->auDts[1].lower = (u32)CODEC_TS_INVALID;
info->auDts[1].upper = 0xffffffff; info->auDts[1].upper = (u32)CODEC_TS_INVALID;
info->auUserData[0] = vf.userdata; info->auUserData[0] = vf.userdata;
info->auUserData[1] = 0; info->auUserData[1] = 0;
info->status = CELL_OK; info->status = CELL_OK;
info->attr = CELL_VDEC_PICITEM_ATTR_NORMAL; info->attr = CELL_VDEC_PICITEM_ATTR_NORMAL;
info->picInfo_addr = info.addr() + sizeof(CellVdecPicItem); info->picInfo_addr = info.addr() + sizeof(CellVdecPicItem);
if (vdec->type == CELL_VDEC_CODEC_TYPE_AVC)
{
auto avc = vm::ptr<CellVdecAvcInfo>::make(info.addr() + sizeof(CellVdecPicItem)); auto avc = vm::ptr<CellVdecAvcInfo>::make(info.addr() + sizeof(CellVdecPicItem));
avc->horizontalSize = frame.width; avc->horizontalSize = frame.width;
@@ -688,7 +780,7 @@ int cellVdecGetPicItem(u32 handle, vm::ptr<u32> picItem_ptr)
case AV_PICTURE_TYPE_I: avc->pictureType[0] = CELL_VDEC_AVC_PCT_I; break; case AV_PICTURE_TYPE_I: avc->pictureType[0] = CELL_VDEC_AVC_PCT_I; break;
case AV_PICTURE_TYPE_P: avc->pictureType[0] = CELL_VDEC_AVC_PCT_P; break; case AV_PICTURE_TYPE_P: avc->pictureType[0] = CELL_VDEC_AVC_PCT_P; break;
case AV_PICTURE_TYPE_B: avc->pictureType[0] = CELL_VDEC_AVC_PCT_B; break; case AV_PICTURE_TYPE_B: avc->pictureType[0] = CELL_VDEC_AVC_PCT_B; break;
default: avc->pictureType[0] = CELL_VDEC_AVC_PCT_UNKNOWN; break; // ??? default: cellVdec->Error("cellVdecGetPicItem(AVC): unknown pict_type value (0x%x)", frame.pict_type);
} }
avc->pictureType[1] = CELL_VDEC_AVC_PCT_UNKNOWN; // ??? avc->pictureType[1] = CELL_VDEC_AVC_PCT_UNKNOWN; // ???
avc->idrPictureFlag = false; // ??? avc->idrPictureFlag = false; // ???
@@ -708,27 +800,20 @@ int cellVdecGetPicItem(u32 handle, vm::ptr<u32> picItem_ptr)
avc->transfer_characteristics = CELL_VDEC_AVC_TC_ITU_R_BT_709_5; avc->transfer_characteristics = CELL_VDEC_AVC_TC_ITU_R_BT_709_5;
avc->matrix_coefficients = CELL_VDEC_AVC_MXC_ITU_R_BT_709_5; // important avc->matrix_coefficients = CELL_VDEC_AVC_MXC_ITU_R_BT_709_5; // important
avc->timing_info_present_flag = true; avc->timing_info_present_flag = true;
if (vdec->ctx->time_base.num == 1001)
switch (vf.frc)
{ {
if (vdec->ctx->time_base.den == 48000 && vdec->ctx->ticks_per_frame == 2) case CELL_VDEC_FRC_24000DIV1001: avc->frameRateCode = CELL_VDEC_AVC_FRC_24000DIV1001; break;
{ case CELL_VDEC_FRC_24: avc->frameRateCode = CELL_VDEC_AVC_FRC_24; break;
avc->frameRateCode = CELL_VDEC_AVC_FRC_24000DIV1001; case CELL_VDEC_FRC_25: avc->frameRateCode = CELL_VDEC_AVC_FRC_25; break;
} case CELL_VDEC_FRC_30000DIV1001: avc->frameRateCode = CELL_VDEC_AVC_FRC_30000DIV1001; break;
else if (vdec->ctx->time_base.den == 60000 && vdec->ctx->ticks_per_frame == 2) case CELL_VDEC_FRC_30: avc->frameRateCode = CELL_VDEC_AVC_FRC_30; break;
{ case CELL_VDEC_FRC_50: avc->frameRateCode = CELL_VDEC_AVC_FRC_50; break;
avc->frameRateCode = CELL_VDEC_AVC_FRC_30000DIV1001; case CELL_VDEC_FRC_60000DIV1001: avc->frameRateCode = CELL_VDEC_AVC_FRC_60000DIV1001; break;
} case CELL_VDEC_FRC_60: avc->frameRateCode = CELL_VDEC_AVC_FRC_60; break;
else default: cellVdec->Error("cellVdecGetPicItem(AVC): unknown frc value (0x%x)", vf.frc);
{
cellVdec->Error("cellVdecGetPicItem: unsupported time_base.den (%d)", vdec->ctx->time_base.den);
Emu.Pause();
}
}
else
{
cellVdec->Error("cellVdecGetPicItem: unsupported time_base.num (%d)", vdec->ctx->time_base.num);
Emu.Pause();
} }
avc->fixed_frame_rate_flag = true; avc->fixed_frame_rate_flag = true;
avc->low_delay_hrd_flag = true; // ??? avc->low_delay_hrd_flag = true; // ???
avc->entropy_coding_mode_flag = true; // ??? avc->entropy_coding_mode_flag = true; // ???
@@ -737,9 +822,50 @@ int cellVdecGetPicItem(u32 handle, vm::ptr<u32> picItem_ptr)
avc->ccDataLength[1] = 0; avc->ccDataLength[1] = 0;
avc->reserved[0] = 0; avc->reserved[0] = 0;
avc->reserved[1] = 0; avc->reserved[1] = 0;
}
else if (vdec->type == CELL_VDEC_CODEC_TYPE_DIVX)
{
auto dvx = vm::ptr<CellVdecDivxInfo>::make(info.addr() + sizeof(CellVdecPicItem));
switch (frame.pict_type)
{
case AV_PICTURE_TYPE_I: dvx->pictureType = CELL_VDEC_DIVX_VCT_I; break;
case AV_PICTURE_TYPE_P: dvx->pictureType = CELL_VDEC_DIVX_VCT_P; break;
case AV_PICTURE_TYPE_B: dvx->pictureType = CELL_VDEC_DIVX_VCT_B; break;
default: cellVdec->Error("cellVdecGetPicItem(DivX): unknown pict_type value (0x%x)", frame.pict_type);
}
dvx->horizontalSize = frame.width;
dvx->verticalSize = frame.height;
dvx->pixelAspectRatio = CELL_VDEC_DIVX_ARI_PAR_1_1; // ???
dvx->parHeight = 0;
dvx->parWidth = 0;
dvx->colourDescription = false; // ???
dvx->colourPrimaries = CELL_VDEC_DIVX_CP_ITU_R_BT_709; // ???
dvx->transferCharacteristics = CELL_VDEC_DIVX_TC_ITU_R_BT_709; // ???
dvx->matrixCoefficients = CELL_VDEC_DIVX_MXC_ITU_R_BT_709; // ???
dvx->pictureStruct = CELL_VDEC_DIVX_PSTR_FRAME; // ???
switch (vf.frc)
{
case CELL_VDEC_FRC_24000DIV1001: dvx->frameRateCode = CELL_VDEC_DIVX_FRC_24000DIV1001; break;
case CELL_VDEC_FRC_24: dvx->frameRateCode = CELL_VDEC_DIVX_FRC_24; break;
case CELL_VDEC_FRC_25: dvx->frameRateCode = CELL_VDEC_DIVX_FRC_25; break;
case CELL_VDEC_FRC_30000DIV1001: dvx->frameRateCode = CELL_VDEC_DIVX_FRC_30000DIV1001; break;
case CELL_VDEC_FRC_30: dvx->frameRateCode = CELL_VDEC_DIVX_FRC_30; break;
case CELL_VDEC_FRC_50: dvx->frameRateCode = CELL_VDEC_DIVX_FRC_50; break;
case CELL_VDEC_FRC_60000DIV1001: dvx->frameRateCode = CELL_VDEC_DIVX_FRC_60000DIV1001; break;
case CELL_VDEC_FRC_60: dvx->frameRateCode = CELL_VDEC_DIVX_FRC_60; break;
default: cellVdec->Error("cellVdecGetPicItem(DivX): unknown frc value (0x%x)", vf.frc);
}
}
else if (vdec->type == CELL_VDEC_CODEC_TYPE_MPEG2)
{
auto mp2 = vm::ptr<CellVdecMpeg2Info>::make(info.addr() + sizeof(CellVdecPicItem));
cellVdec->Todo("cellVdecGetPicItem(MPEG2)");
Emu.Pause();
}
*picItem_ptr = info.addr(); *picItem_ptr = info.addr();
return CELL_OK; return CELL_OK;
} }
@@ -747,7 +873,7 @@ int cellVdecSetFrameRate(u32 handle, CellVdecFrameRate frc)
{ {
cellVdec->Log("cellVdecSetFrameRate(handle=%d, frc=0x%x)", handle, frc); cellVdec->Log("cellVdecSetFrameRate(handle=%d, frc=0x%x)", handle, frc);
VideoDecoder* vdec; std::shared_ptr<VideoDecoder> vdec;
if (!Emu.GetIdManager().GetIDData(handle, vdec)) if (!Emu.GetIdManager().GetIDData(handle, vdec))
{ {
return CELL_VDEC_ERROR_ARG; return CELL_VDEC_ERROR_ARG;
@@ -757,7 +883,7 @@ int cellVdecSetFrameRate(u32 handle, CellVdecFrameRate frc)
VdecTask task(vdecSetFrameRate); VdecTask task(vdecSetFrameRate);
task.frc = frc; task.frc = frc;
vdec->job.Push(task, &vdec->is_closed); vdec->job.push(task, &vdec->is_closed);
return CELL_OK; return CELL_OK;
} }

Some files were not shown because too many files have changed in this diff Show More