Merge upstream

This commit is contained in:
S Gopal Rajagopal 2015-01-05 16:44:26 +05:30
commit 2d94db4945
169 changed files with 11377 additions and 7129 deletions

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)
__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__
* Install with Homebrew: `brew install glew wxwidgets`

View File

@ -11,13 +11,13 @@ using namespace Log;
LogManager *gLogManager = nullptr;
u32 LogMessage::size()
u32 LogMessage::size() const
{
//1 byte for NULL terminator
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();
memcpy(output, &size, sizeof(LogMessage::size_type));
@ -60,7 +60,7 @@ LogChannel::LogChannel(const std::string& name) :
, mLogLevel(Warning)
{}
void LogChannel::log(LogMessage msg)
void LogChannel::log(const LogMessage &msg)
{
std::lock_guard<std::mutex> lock(mListenerLock);
for (auto &listener : mListeners)
@ -82,7 +82,7 @@ void LogChannel::removeListener(std::shared_ptr<LogListener> listener)
struct CoutListener : LogListener
{
void log(LogMessage msg)
void log(const LogMessage &msg)
{
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)
{
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);
}
};

View File

@ -63,15 +63,15 @@ namespace Log
LogSeverity mServerity;
std::string mText;
u32 size();
void serialize(char *output);
u32 size() const;
void serialize(char *output) const;
static LogMessage deserialize(char *input, u32* size_out=nullptr);
};
struct LogListener
{
virtual ~LogListener() {};
virtual void log(LogMessage msg) = 0;
virtual void log(const LogMessage &msg) = 0;
};
struct LogChannel
@ -80,7 +80,7 @@ namespace Log
LogChannel(const std::string& name);
LogChannel(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 removeListener(std::shared_ptr<LogListener> listener);
std::string name;

View File

@ -30,7 +30,7 @@ public:
{
//wait until there's actually something to get
//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;
mGet = moveGet();
@ -45,7 +45,7 @@ public:
{
//if this is reached a lot it's time to increase the buffer size
//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);
mPut = movePut();
@ -94,7 +94,7 @@ public:
{
//if this is reached a lot it's time to increase the buffer size
//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())
{

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();
}

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;

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;
}
};

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 result;
for (auto &s : source)
if (!source.size())
{
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)
{
if (!sources.size())
{
return "";
}
std::string result;
bool first = true;
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;

View File

@ -249,7 +249,7 @@ bool waiter_map_t::is_stopped(u64 signal_id)
{
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 false;
@ -257,48 +257,56 @@ bool waiter_map_t::is_stopped(u64 signal_id)
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);
// add waiter
map.m_waiters.push_back({ signal_id, thread });
// add waiter
map.m_waiters.push_back({ signal_id, thread });
}
}
waiter_map_t::waiter_reg_t::~waiter_reg_t()
{
if (!thread) return;
std::lock_guard<std::mutex> lock(map.m_mutex);
// remove waiter
for (s64 i = map.m_waiters.size() - 1; i >= 0; i--)
if (thread)
{
if (map.m_waiters[i].signal_id == signal_id && map.m_waiters[i].thread == thread)
{
map.m_waiters.erase(map.m_waiters.begin() + i);
return;
}
}
std::lock_guard<std::mutex> lock(map.m_mutex);
LOG_ERROR(HLE, "%s(): waiter not found (signal_id=0x%llx, map='%s')", __FUNCTION__, signal_id, map.m_name.c_str());
Emu.Pause();
// remove waiter
for (s64 i = map.m_waiters.size() - 1; i >= 0; i--)
{
if (map.m_waiters[i].signal_id == signal_id && map.m_waiters[i].thread == thread)
{
map.m_waiters.erase(map.m_waiters.begin() + i);
return;
}
}
LOG_ERROR(HLE, "%s(): waiter not found (signal_id=0x%llx, map='%s')", __FUNCTION__, signal_id, map.m_name.c_str());
Emu.Pause();
}
}
void waiter_map_t::notify(u64 signal_id)
{
if (!m_waiters.size()) return;
std::lock_guard<std::mutex> lock(m_mutex);
// find waiter and signal
for (auto& v : m_waiters)
if (m_waiters.size())
{
if (v.signal_id == signal_id)
std::lock_guard<std::mutex> lock(m_mutex);
// find waiter and signal
for (auto& v : m_waiters)
{
v.thread->Notify();
if (v.signal_id == signal_id)
{
v.thread->Notify();
}
}
}
}
bool squeue_test_exit(const volatile bool* do_exit)
{
return Emu.IsStopped() || (do_exit && *do_exit);
}

View File

@ -1,4 +1,5 @@
#pragma once
#include "Emu/Memory/atomic_type.h"
static std::thread::id main_thread;
@ -71,33 +72,6 @@ public:
bool joinable() const;
};
class s_mutex_t
{
};
class s_shared_mutex_t
{
};
class s_cond_var_t
{
//public:
// s_cond_var_t();
// ~s_cond_var_t();
//
// s_cond_var_t(s_cond_var_t& right) = delete;
// s_cond_var_t& operator = (s_cond_var_t& right) = delete;
//
// void wait();
// void wait_for();
//
// void notify();
// void notify_all();
};
class slw_mutex_t
{
@ -160,10 +134,10 @@ public:
// register waiter
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))
{
// initialize waiter (only first time)
// initialize waiter (only once)
waiter.init();
// wait for 1 ms or until signal arrived
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)
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();
}
};

2
asmjit

@ -1 +1 @@
Subproject commit 1318c9aff7137b30aec7dee2ababb2b313ae0f06
Subproject commit 48da90ded775fa2ba0fd3f15522890ad631ad6de

2
ffmpeg

@ -1 +1 @@
Subproject commit 352fdfbbfa6d7b26142f00b43d7e1802a03c68a8
Subproject commit 79a2d7a9f780ad27d1622010cb1cb8396c3701e9

View File

@ -43,13 +43,13 @@ bool CheckHeader(rFile& pkg_f, PKGHeader* m_header)
}
if (m_header->pkg_size != pkg_f.Length()) {
LOG_ERROR(LOADER, "PKG: File size mismatch.");
return false;
LOG_WARNING(LOADER, "PKG: File size mismatch.");
//return false;
}
if (m_header->data_size + m_header->data_offset + 0x60 != pkg_f.Length()) {
LOG_ERROR(LOADER, "PKG: Data size mismatch.");
return false;
LOG_WARNING(LOADER, "PKG: Data size mismatch.");
//return false;
}
return true;

View File

@ -1,35 +1,48 @@
#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
{
ARMv7Opcodes& m_op;
u8 m_last_instr_size;
ARMv7Thread& m_thr;
public:
ARMv7Decoder(ARMv7Opcodes& op) : m_op(op)
ARMv7Decoder(ARMv7Thread& thr) : m_thr(thr)
{
}
virtual u8 DecodeMemory(const u32 address)
{
const u32 code0 = vm::psv::read16(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;
m_thr.update_code(address & ~1);
// 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)
{
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;
}
}
m_op.UNK(data);
return address & 1 ? 4 : 2;
ARMv7_instrs::UNK(&m_thr);
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;
}
};

View File

@ -12,10 +12,9 @@ static const char* g_arm_cond_name[16] =
class ARMv7DisAsm
: public CPUDisAsm
, public ARMv7Opcodes
{
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

View File

@ -10,7 +10,11 @@
#include "ARMv7DisAsm.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 2:
m_dec = new ARMv7Decoder(*new ARMv7Interpreter(*this));
m_dec = new ARMv7Decoder(*this);
break;
}
}

View File

@ -1,17 +1,23 @@
#pragma once
#include "Emu/CPU/CPUThread.h"
#include "Emu/Memory/Memory.h"
enum ARMv7InstructionSet
{
ARM,
Thumb,
Jazelle,
ThumbEE,
ThumbEE
};
class ARMv7Thread : public CPUThread
{
public:
u32 m_arg;
u8 m_last_instr_size;
const char* m_last_instr_name;
ARMv7Thread();
union
@ -61,6 +67,18 @@ public:
} IPSR;
union
{
struct
{
u32 code1 : 16;
u32 code0 : 16;
};
u32 data;
} code;
ARMv7InstructionSet ISET;
union
@ -119,6 +137,13 @@ public:
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:
virtual void InitRegs();
virtual void InitStack();

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());
CPUThread* t = Emu.GetCPU().GetThread(threadId);
std::shared_ptr<CPUThread> t = Emu.GetCPU().GetThread(threadId);
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
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);
// set SceKernelThreadEntry function arguments
static_cast<ARMv7Thread*>(t)->write_gpr(0, argSize);
static_cast<ARMv7Thread*>(t)->write_gpr(1, pos);
static_cast<ARMv7Thread*>(t.get())->write_gpr(0, argSize);
static_cast<ARMv7Thread*>(t.get())->write_gpr(1, pos);
t->Exec();
return SCE_OK;

View File

@ -1,4 +1,5 @@
#include "stdafx.h"
#include "Utilities/Log.h"
#include "Emu/System.h"
#include "Emu/Memory/Memory.h"
#include "Emu/ARMv7/PSVFuncList.h"

View File

@ -1,4 +1,5 @@
#include "stdafx.h"
#include "Utilities/Log.h"
#include "Emu/System.h"
#include "PSVFuncList.h"

View File

@ -82,6 +82,9 @@ struct AudioPortConfig
u64 attr;
u64 tag;
u64 counter; // copy of global counter
u32 addr;
u32 read_index_addr;
u32 size;
};
struct AudioConfig //custom structure

View File

@ -21,8 +21,6 @@ CPUThread::CPUThread(CPUThreadType type)
, m_stack_addr(0)
, m_offset(0)
, m_prio(0)
, m_sync_wait(false)
, m_wait_thread_id(-1)
, m_dec(nullptr)
, m_is_step(false)
, m_is_branch(false)
@ -44,7 +42,7 @@ bool CPUThread::IsStopped() const { return m_status == Stopped; }
void CPUThread::Close()
{
ThreadBase::Stop(m_sync_wait);
ThreadBase::Stop(false);
DoStop();
delete m_dec;
@ -55,9 +53,6 @@ void CPUThread::Reset()
{
CloseStack();
m_sync_wait = 0;
m_wait_thread_id = -1;
SetPc(0);
cycle = 0;
m_is_branch = false;
@ -89,24 +84,6 @@ void CPUThread::SetName(const std::string& 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()
{
if(Emu.IsStopped() || IsStopped() || IsPaused())
@ -124,7 +101,7 @@ int CPUThread::ThreadStatus()
return CPUThread_Step;
}
if (Emu.IsPaused() || Sync())
if (Emu.IsPaused())
{
return CPUThread_Sleeping;
}
@ -334,7 +311,7 @@ void CPUThread::Task()
if (status == CPUThread_Sleeping)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1));
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
continue;
}

View File

@ -136,23 +136,6 @@ protected:
public:
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();
void NextPc(u8 instr_size);
@ -280,7 +263,7 @@ public:
thread->SetJoinable(false);
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();
}

View File

@ -28,28 +28,28 @@ CPUThread& CPUThreadManager::AddThread(CPUThreadType type)
{
std::lock_guard<std::mutex> lock(m_mtx_thread);
CPUThread* new_thread;
std::shared_ptr<CPUThread> new_thread;
switch(type)
{
case CPU_THREAD_PPU:
{
new_thread = new PPUThread();
new_thread.reset(new PPUThread());
break;
}
case CPU_THREAD_SPU:
{
new_thread = new SPUThread();
new_thread.reset(new SPUThread());
break;
}
case CPU_THREAD_RAW_SPU:
{
new_thread = new RawSPUThread();
new_thread.reset(new RawSPUThread());
break;
}
case CPU_THREAD_ARMv7:
{
new_thread = new ARMv7Thread();
new_thread.reset(new ARMv7Thread());
break;
}
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));
m_threads.push_back(new_thread);
SendDbgCommand(DID_CREATE_THREAD, new_thread);
SendDbgCommand(DID_CREATE_THREAD, new_thread.get());
return *new_thread;
}
@ -67,17 +67,11 @@ void CPUThreadManager::RemoveThread(const u32 id)
{
std::lock_guard<std::mutex> lock(m_mtx_thread);
CPUThread* thr = nullptr;
std::shared_ptr<CPUThread> thr;
u32 thread_index = 0;
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;
thr = m_threads[i];
@ -86,7 +80,7 @@ void CPUThreadManager::RemoveThread(const u32 id)
if (thr)
{
SendDbgCommand(DID_REMOVE_THREAD, thr);
SendDbgCommand(DID_REMOVE_THREAD, thr.get());
thr->Close();
m_threads.erase(m_threads.begin() + thread_index);
@ -112,9 +106,9 @@ s32 CPUThreadManager::GetThreadNumById(CPUThreadType type, u32 id)
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;
@ -139,7 +133,7 @@ void CPUThreadManager::Exec()
{
std::lock_guard<std::mutex> lock(m_mtx_thread);
for(u32 i=0; i<m_threads.size(); ++i)
for(u32 i = 0; i < m_threads.size(); ++i)
{
m_threads[i]->Exec();
}

View File

@ -6,7 +6,7 @@ enum CPUThreadType : unsigned char;
class CPUThreadManager
{
std::vector<CPUThread*> m_threads;
std::vector<std::shared_ptr<CPUThread>> m_threads;
std::mutex m_mtx_thread;
public:
@ -18,9 +18,9 @@ public:
CPUThread& AddThread(CPUThreadType type);
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);
CPUThread* GetThread(u32 id);
std::shared_ptr<CPUThread> GetThread(u32 id);
RawSPUThread* GetRawSPUThread(u32 num);
void Exec();

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));
}
void SC(u32 sc_code)
void SC(u32 lev)
{
switch(sc_code)
switch (lev)
{
case 0x1: Write("HyperCall"); break;
case 0x2: Write("sc"); break;
case 0x22: Write("HyperCall LV1"); break;
default: Write(fmt::Format("Unknown sc: 0x%x", sc_code));
case 0x0: Write("sc"); break;
case 0x1: Write("HyperCall LV1"); break;
default: Write(fmt::Format("Unknown sc: 0x%x", lev));
}
}
void B(s32 ll, u32 aa, u32 lk)

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.
static CodeField<12, 19> CRM;
//
static CodeField<6, 31> SYS;
// This field is used to identify the system call level
static CodeField<20, 26> LEV;
//Immediate field specifying a 16-bit signed two's complement integer that is sign-extended to 64 bits
static CodeFieldSigned<16, 31> D;
@ -238,7 +238,7 @@ namespace PPU_instr
bind_instr(main_list, ADDI, 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, SC, SYS);
bind_instr(main_list, SC, LEV);
bind_instr(main_list, B, LI, AA, LK);
bind_instr(main_list, RLWIMI, RA, RS, SH, MB, ME, RC);
bind_instr(main_list, RLWINM, RA, RS, SH, MB, ME, RC);

View File

@ -2164,13 +2164,13 @@ private:
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 0x2: SysCall(); break;
case 0x3:
case 0x0: SysCall(); break;
case 0x1: UNK("HyperCall LV1"); break;
case 0x2:
Emu.GetSFuncManager().StaticExecute(CPU, (u32)CPU.GPR[11]);
if (Ini.HLELogging.GetValue())
{
@ -2178,9 +2178,8 @@ private:
Emu.GetSFuncManager()[CPU.GPR[11]]->name, CPU.GPR[3], CPU.PC);
}
break;
case 0x4: CPU.FastStop(); break;
case 0x22: UNK("HyperCall LV1"); break;
default: UNK(fmt::Format("Unknown sc: 0x%x", sc_code));
case 0x3: CPU.FastStop(); break;
default: UNK(fmt::Format("Unknown sc: 0x%x", lev)); break;
}
}
void B(s32 ll, u32 aa, u32 lk)
@ -3665,7 +3664,14 @@ private:
void DCBZ(u32 ra, u32 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)
memset(cache_line, 0, 128);
}

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);
}
void Compiler::SC(u32 sc_code) {
switch (sc_code) {
case 2:
void Compiler::SC(u32 lev) {
switch (lev) {
case 0:
Call<void>("SysCalls.DoSyscall", SysCalls::DoSyscall, m_state.args[CompileTaskState::Args::State], GetGpr(11));
break;
case 3:
case 2:
Call<void>("StaticFuncManager.StaticExecute", &StaticFuncManager::StaticExecute,
m_ir_builder->getInt64((u64)&Emu.GetSFuncManager()), m_state.args[CompileTaskState::Args::State], GetGpr(11, 32));
break;
case 4:
case 3:
Call<void>("PPUThread.FastStop", &PPUThread::FastStop, m_state.args[CompileTaskState::Args::State]);
break;
default:
CompilationError(fmt::Format("SC %u", sc_code));
CompilationError(fmt::Format("SC %u", lev));
break;
}
}

View File

@ -451,6 +451,8 @@ namespace PPU_opcodes
class PPUOpcodes
{
public:
virtual ~PPUOpcodes() {}
static u32 branchTarget(const u32 pc, const u32 imm)
{
return pc + (imm & ~0x3ULL);
@ -628,7 +630,7 @@ public:
virtual void ADDI(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 SC(u32 sc_code) = 0;
virtual void SC(u32 lev) = 0;
virtual void B(s32 ll, u32 aa, u32 lk) = 0;
virtual void MCRF(u32 crfd, u32 crfs) = 0;
virtual void BCLR(u32 bo, u32 bi, u32 bh, u32 lk) = 0;

View File

@ -229,6 +229,8 @@ namespace SPU_opcodes
class SPUOpcodes
{
public:
virtual ~SPUOpcodes() {}
static u32 branchTarget(const u32 pc, const s32 imm)
{
return (pc + (imm << 2)) & 0x3fffc;

View File

@ -1,7 +1,5 @@
#pragma once
#include "Emu/SysCalls/Modules/cellSpurs.h"
class SPURSManagerEventFlag
{
public:

View File

@ -25,7 +25,7 @@ SPURecompilerCore::SPURecompilerCore(SPUThread& cpu)
memset(entry, 0, sizeof(entry));
X86CpuInfo inf;
X86CpuUtil::detect(&inf);
if (!inf.hasFeature(kX86CpuFeatureSse41))
if (!inf.hasFeature(kX86CpuFeatureSSE4_1))
{
LOG_ERROR(SPU, "SPU JIT requires SSE4.1 instruction set support");
Emu.Pause();

View File

@ -3,6 +3,7 @@
#include "Utilities/Log.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "Emu/Memory/atomic_type.h"
#include "Emu/IdManager.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);
group = nullptr;
for (auto& p : SPUPs)
{
p.reset(new EventPort());
}
Reset();
}
@ -136,12 +141,12 @@ void SPUThread::DoClose()
}
for (u32 i = 0; i < 64; i++)
{
EventPort& port = SPUPs[i];
std::lock_guard<std::mutex> lock(port.m_mutex);
if (port.eq)
std::shared_ptr<EventPort> port = SPUPs[i];
std::lock_guard<std::mutex> lock(port->m_mutex);
if (port->eq)
{
port.eq->ports.remove(&port);
port.eq = nullptr;
port->eq->ports.remove(port);
port->eq = nullptr;
}
}
}
@ -208,17 +213,17 @@ void SPUThread::ProcessCmd(u32 cmd, u32 tag, u32 lsa, u64 ea, u32 size)
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;
if ((addr <= 0x3ffff) && (addr + size <= 0x40000))
{
// 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))
{
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;
}
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);
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())
{
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;
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)
{
@ -605,7 +610,7 @@ void SPUThread::WriteChannel(u32 ch, const u128& r)
Emu.Pause();
return;
}
PPUThread& ppu = *(PPUThread*)t;
PPUThread& ppu = *(PPUThread*)t.get();
ppu.GPR[3] = ppu.m_interrupt_arg;
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);
}
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);
SPU.In_MBox.PushUncond(CELL_ENOTCONN); // TODO: check error passing
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);
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);
}
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);
return;
}
// 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);
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);
}
EventFlag* ef;
std::shared_ptr<EventFlag> 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);
@ -720,21 +725,13 @@ void SPUThread::WriteChannel(u32 ch, const u128& r)
return;
}
const u32 tid = GetId();
std::lock_guard<std::mutex> lock(ef->mutex);
ef->m_mutex.lock(tid);
ef->flags |= (u64)1 << flag;
if (u32 target = ef->check())
{
// if signal, leave both mutexes locked...
ef->signal.lock(target);
ef->m_mutex.unlock(tid, target);
ef->signal.push(target);
}
else
{
ef->m_mutex.unlock(tid);
}
SPU.In_MBox.PushUncond(CELL_OK);
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);
}
EventFlag* ef;
std::shared_ptr<EventFlag> 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);
return;
}
const u32 tid = GetId();
std::lock_guard<std::mutex> lock(ef->mutex);
ef->m_mutex.lock(tid);
ef->flags |= (u64)1 << flag;
if (u32 target = ef->check())
{
// if signal, leave both mutexes locked...
ef->signal.lock(target);
ef->m_mutex.unlock(tid, target);
ef->signal.push(target);
}
else
{
ef->m_mutex.unlock(tid);
}
return;
}
else
@ -805,7 +794,10 @@ void SPUThread::WriteChannel(u32 ch, const u128& r)
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;
}
@ -916,13 +908,19 @@ void SPUThread::ReadChannel(u128& r, u32 ch)
{
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;
}
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;
}
@ -936,11 +934,17 @@ void SPUThread::ReadChannel(u128& r, u32 ch)
{
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
{
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;
}
@ -949,24 +953,36 @@ void SPUThread::ReadChannel(u128& r, u32 ch)
{
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
{
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;
}
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;
}
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;
}
@ -984,7 +1000,10 @@ void SPUThread::ReadChannel(u128& r, u32 ch)
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;
break;
}
@ -1057,7 +1076,7 @@ void SPUThread::StopAndSignal(u32 code)
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))
{
SPU.In_MBox.PushUncond(CELL_EINVAL); // TODO: check error value
@ -1066,47 +1085,61 @@ void SPUThread::StopAndSignal(u32 code)
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)
{
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:
if (!eq->events.count())
case 0:
{
const u32 next = eq->events.count() ? eq->sq.signal(eq->protocol) : 0;
if (next != tid)
{
eq->owner.unlock(tid);
if (!eq->owner.compare_and_swap_test(tid, next))
{
assert(!"sys_spu_thread_receive_event() failed (I)");
}
break;
}
else
{
u32 next = (eq->protocol == SYS_SYNC_FIFO) ? eq->sq.pop() : eq->sq.pop_prio();
if (next != tid)
{
eq->owner.unlock(tid, next);
break;
}
}
case SMR_SIGNAL:
// fallthrough
}
case 1:
{
sys_event_data 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((u32)event.data1);
SPU.In_MBox.PushUncond((u32)event.data2);
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;
}
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())
{
LOG_WARNING(Log::SPU, "sys_spu_thread_receive_event(spuq=0x%x) aborted", spuq);
eq->sq.invalidate(tid);
return;
}
}
@ -1135,7 +1168,7 @@ void SPUThread::StopAndSignal(u32 code)
group->m_exit_status = SPU.Out_MBox.GetValue();
for (auto& v : group->list)
{
if (CPUThread* t = Emu.GetCPU().GetThread(v))
if (std::shared_ptr<CPUThread> t = Emu.GetCPU().GetThread(v))
{
t->Stop();
}

View File

@ -1,6 +1,8 @@
#pragma once
#include "Emu/Memory/atomic_type.h"
#include "PPCThread.h"
#include "Emu/SysCalls/lv2/sleep_queue_type.h"
#include "Emu/SysCalls/lv2/sys_event.h"
#include "Emu/Event.h"
#include "MFC.h"
@ -281,9 +283,9 @@ public:
u64 R_ADDR; // reservation address
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
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
u32 m_dec_value; // written decrementer value

View File

@ -1,6 +1,9 @@
#include "stdafx.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"
void EventManager::Init()
@ -20,7 +23,7 @@ bool EventManager::CheckKey(u64 key)
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;
std::lock_guard<std::mutex> lock(m_lock);
@ -37,7 +40,7 @@ bool EventManager::RegisterKey(EventQueue* data, u64 key)
return true;
}
bool EventManager::GetEventQueue(u64 key, EventQueue*& data)
bool EventManager::GetEventQueue(u64 key, std::shared_ptr<EventQueue>& data)
{
data = nullptr;
if (!key) return false;
@ -76,8 +79,7 @@ bool EventManager::SendEvent(u64 key, u64 source, u64 d1, u64 d2, u64 d3)
{
return false;
}
EventQueue* eq = f->second;
eq->events.push(source, d1, d2, d3);
f->second->events.push(source, d1, d2, d3);
return true;
}

View File

@ -1,18 +1,19 @@
#pragma once
#include "Emu/SysCalls/lv2/sys_event.h"
#include <unordered_map>
struct EventQueue;
class EventManager
{
std::mutex m_lock;
std::unordered_map<u64, EventQueue*> key_map;
std::unordered_map<u64, std::shared_ptr<EventQueue>> key_map;
public:
void Init();
void Clear();
bool CheckKey(u64 key);
bool RegisterKey(EventQueue* data, u64 key);
bool GetEventQueue(u64 key, EventQueue*& data);
bool RegisterKey(std::shared_ptr<EventQueue>& data, u64 key);
bool GetEventQueue(u64 key, std::shared_ptr<EventQueue>& data);
bool UnregisterKey(u64 key);
bool SendEvent(u64 key, u64 source, u64 d1, u64 d2, u64 d3);
};

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::string result;
if (path_blocks.empty())
return result;
return "";
if (is_dir)
{
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];
}
std::string result = fmt::merge(path_blocks, "/");
return result;
return is_dir ? result + "/" : result;
}
VFS::~VFS()

View File

@ -75,7 +75,12 @@ bool vfsLocalFile::Create(const std::string& path)
if(m != '/' && m != '\\' && !rExists(path)) // ???
{
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;

View File

@ -4,6 +4,7 @@ struct GameInfo
{
std::string root;
std::string icon_path;
std::string name;
std::string serial;
std::string app_ver;

View File

@ -48,14 +48,14 @@ public:
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:
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_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)
@ -85,6 +85,7 @@ public:
m_data = other.m_data;
other.m_data = nullptr;
}
ID& operator=(ID&& other)
{
std::swap(m_name,other.m_name);
@ -159,7 +160,7 @@ public:
= char
#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);
@ -179,7 +180,7 @@ public:
}
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);
@ -226,15 +227,32 @@ public:
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 1;
else
{
assert(!"Invalid ID type");
return 0;
}
}
const std::set<u32>& GetTypeIDs(IDType type)
std::set<u32> GetTypeIDs(IDType type)
{
assert(type < TYPE_OTHER);
return m_types[type];
// you cannot simply return reference to existing set
std::lock_guard<std::mutex> lock(m_mtx_main);
if (type < TYPE_OTHER)
{
return m_types[type];
}
else
{
assert(!"Invalid ID type");
return{};
}
}
};

View File

@ -170,36 +170,28 @@ void MemoryBase::Close()
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] &&
((RawSPUThread*)RawSPUMem[(addr - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET])->Write32(addr, data))
{
return;
}
if (RawSPUMem[(addr - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET] && ((RawSPUThread*)RawSPUMem[(addr - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET])->Write32(addr, data))
{
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] &&
((RawSPUThread*)RawSPUMem[(addr - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET])->Read32(addr, &res))
{
return res;
}
if (RawSPUMem[(addr - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET] && ((RawSPUThread*)RawSPUMem[(addr - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET])->Read32(addr, &res))
{
return true;
}
res = re32(*(u32*)((u8*)GetBaseAddr() + addr)); // provoke error
return res;
return false;
}
bool MemoryBase::Map(const u64 addr, const u32 size)

View File

@ -127,9 +127,9 @@ public:
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()
{

View File

@ -64,26 +64,20 @@ namespace vm
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));
}
else
{
return Memory.ReadMMIO32((u32)addr);
res = re32(*(u32*)((u8*)g_base_addr + addr));
}
return res;
}
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;
}
else
{
Memory.WriteMMIO32((u32)addr, value);
}
}
static u64 read64(u32 addr)

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
{
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
{
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;
@ -160,17 +160,17 @@ namespace vm
__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
{
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
{
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; }
@ -224,7 +224,7 @@ namespace vm
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)
@ -356,9 +356,9 @@ namespace vm
public:
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
{

View File

@ -6,9 +6,9 @@
void GLFragmentDecompilerThread::SetDst(std::string code, bool append_mask)
{
if(!src0.exec_if_eq && !src0.exec_if_gr && !src0.exec_if_lt) return;
if (!src0.exec_if_eq && !src0.exec_if_gr && !src0.exec_if_lt) return;
switch(src1.scale)
switch (src1.scale)
{
case 0: break;
case 1: code = "(" + code + " * 2.0)"; break;
@ -21,27 +21,39 @@ void GLFragmentDecompilerThread::SetDst(std::string code, bool append_mask)
default:
LOG_ERROR(RSX, "Bad scale: %d", fmt::by_value(src1.scale));
Emu.Pause();
break;
break;
}
if(dst.saturate)
if (dst.saturate)
{
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)
{
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)
@ -58,17 +70,17 @@ std::string GLFragmentDecompilerThread::GetMask()
'x', 'y', 'z', 'w',
};
if(dst.mask_x) ret += dst_mask[0];
if(dst.mask_y) ret += dst_mask[1];
if(dst.mask_z) ret += dst_mask[2];
if(dst.mask_w) ret += dst_mask[3];
if (dst.mask_x) ret += dst_mask[0];
if (dst.mask_y) ret += dst_mask[1];
if (dst.mask_z) ret += dst_mask[2];
if (dst.mask_w) ret += dst_mask[3];
return ret.empty() || strncmp(ret.c_str(), dst_mask, 4) == 0 ? "" : ("." + ret);
}
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)
@ -79,13 +91,13 @@ bool GLFragmentDecompilerThread::HasReg(u32 index, int fp16)
std::string GLFragmentDecompilerThread::AddCond()
{
return m_parr.AddParam(PARAM_NONE , "vec4", "cc" + std::to_string(src0.cond_reg_index));
return m_parr.AddParam(PARAM_NONE, "vec4", "cc" + std::to_string(src0.cond_reg_index));
}
std::string GLFragmentDecompilerThread::AddConst()
{
std::string name = std::string("fc") + std::to_string(m_size + 4 * 4);
if(m_parr.HasParam(PARAM_UNIFORM, "vec4", name))
if (m_parr.HasParam(PARAM_UNIFORM, "vec4", name))
{
return name;
}
@ -118,11 +130,11 @@ std::string GLFragmentDecompilerThread::Format(const std::string& code)
{ "$t", std::bind(std::mem_fn(&GLFragmentDecompilerThread::AddTex), this) },
{ "$m", std::bind(std::mem_fn(&GLFragmentDecompilerThread::GetMask), this) },
{ "$ifcond ", [this]() -> std::string
{
const std::string& cond = GetCond();
if (cond == "true") return "";
return "if(" + cond + ") ";
}
{
const std::string& cond = GetCond();
if (cond == "true") return "";
return "if(" + cond + ") ";
}
},
{ "$cond", std::bind(std::mem_fn(&GLFragmentDecompilerThread::GetCond), this) },
{ "$c", std::bind(std::mem_fn(&GLFragmentDecompilerThread::AddConst), this) }
@ -179,15 +191,83 @@ std::string GLFragmentDecompilerThread::GetCond()
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)
{
std::string ret;
switch(src.reg_type)
switch (src.reg_type)
{
case 0: //tmp
ret += AddReg(src.tmp_reg_index, src.fp16);
break;
break;
case 1: //input
{
@ -200,11 +280,11 @@ template<typename T> std::string GLFragmentDecompilerThread::GetSRC(T src)
"ssa"
};
switch(dst.src_attr_reg_num)
switch (dst.src_attr_reg_num)
{
case 0x00: ret += reg_table[0]; break;
default:
if(dst.src_attr_reg_num < sizeof(reg_table)/sizeof(reg_table[0]))
if (dst.src_attr_reg_num < sizeof(reg_table) / sizeof(reg_table[0]))
{
ret += m_parr.AddParam(PARAM_IN, "vec4", reg_table[dst.src_attr_reg_num]);
}
@ -214,22 +294,22 @@ template<typename T> std::string GLFragmentDecompilerThread::GetSRC(T src)
ret += m_parr.AddParam(PARAM_IN, "vec4", "unk");
Emu.Pause();
}
break;
break;
}
}
break;
case 2: //const
ret += AddConst();
break;
break;
default:
LOG_ERROR(RSX, "Bad src type %d", fmt::by_value(src.reg_type));
Emu.Pause();
break;
break;
}
static const char f[4] = {'x', 'y', 'z', 'w'};
static const char f[4] = { 'x', 'y', 'z', 'w' };
std::string swizzle = "";
swizzle += f[src.swizzle_x];
@ -237,10 +317,10 @@ template<typename T> std::string GLFragmentDecompilerThread::GetSRC(T src)
swizzle += f[src.swizzle_z];
swizzle += f[src.swizzle_w];
if(strncmp(swizzle.c_str(), f, 4) != 0) ret += "." + swizzle;
if (strncmp(swizzle.c_str(), f, 4) != 0) ret += "." + swizzle;
if(src.abs) ret = "abs(" + ret + ")";
if(src.neg) ret = "-" + ret;
if (src.abs) ret = "abs(" + ret + ")";
if (src.neg) ret = "-" + ret;
return ret;
}
@ -251,10 +331,9 @@ std::string GLFragmentDecompilerThread::BuildCode()
const std::pair<std::string, std::string> table[] =
{
{ "ocol0", m_ctrl & 0x40 ? "r0" : "h0" },
{ "ocol1", m_ctrl & 0x40 ? "r2" : "h2" },
{ "ocol2", m_ctrl & 0x40 ? "r3" : "h4" },
{ "ocol3", m_ctrl & 0x40 ? "r4" : "h6" },
{ "ocol4", m_ctrl & 0x40 ? "r5" : "h8" },
{ "ocol1", m_ctrl & 0x40 ? "r2" : "h4" },
{ "ocol2", m_ctrl & 0x40 ? "r3" : "h6" },
{ "ocol3", m_ctrl & 0x40 ? "r4" : "h8" },
};
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 + ";");
}
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;
@ -285,7 +364,16 @@ void GLFragmentDecompilerThread::Task()
m_loop_count = 0;
m_code_level = 1;
while(true)
enum
{
FORCE_NONE,
FORCE_SCT,
FORCE_SCB,
};
int forced_unit = FORCE_NONE;
while (true)
{
for (auto finded = std::find(m_end_offsets.begin(), m_end_offsets.end(), m_size);
finded != m_end_offsets.end();
@ -318,126 +406,201 @@ void GLFragmentDecompilerThread::Task()
const u32 opcode = dst.opcode | (src1.opcode_is_branch << 6);
switch(opcode)
auto SCT = [&]()
{
switch (opcode)
{
case RSX_FP_OPCODE_ADD: 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_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_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_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:
AddCode("if($cond)");
m_else_offsets.push_back(src1.else_offset << 2);
m_end_offsets.push_back(src2.end_offset << 2);
AddCode("{");
m_code_level++;
break;
case RSX_FP_OPCODE_LOOP:
if (!src0.exec_if_eq && !src0.exec_if_gr && !src0.exec_if_lt)
{
AddCode(fmt::Format("$ifcond for(int i%u = %u; i%u < %u; i%u += %u) {} //-> %u //LOOP",
m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment, src2.end_offset));
}
else
{
AddCode(fmt::Format("$ifcond for(int i%u = %u; i%u < %u; i%u += %u) //LOOP",
m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment));
m_loop_count++;
m_end_offsets.push_back(src2.end_offset << 2);
AddCode("{");
m_code_level++;
}
break;
case RSX_FP_OPCODE_REP:
if (!src0.exec_if_eq && !src0.exec_if_gr && !src0.exec_if_lt)
{
AddCode(fmt::Format("$ifcond for(int i%u = %u; i%u < %u; i%u += %u) {} //-> %u //REP",
m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment, src2.end_offset));
}
else
{
AddCode(fmt::Format("if($cond) for(int i%u = %u; i%u < %u; i%u += %u) //REP",
m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment));
m_loop_count++;
m_end_offsets.push_back(src2.end_offset << 2);
AddCode("{");
m_code_level++;
}
break;
case RSX_FP_OPCODE_RET: SetDst("return"); break;
default:
return false;
}
return true;
};
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_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_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_FENCT: break;
case RSX_FP_OPCODE_FENCB: break;
case RSX_FP_OPCODE_BRK: SetDst("break"); break;
//case RSX_FP_OPCODE_CAL: break;
case RSX_FP_OPCODE_IFE:
AddCode("if($cond)");
m_else_offsets.push_back(src1.else_offset << 2);
m_end_offsets.push_back(src2.end_offset << 2);
AddCode("{");
m_code_level++;
break;
case RSX_FP_OPCODE_LOOP:
if(!src0.exec_if_eq && !src0.exec_if_gr && !src0.exec_if_lt)
{
AddCode(fmt::Format("$ifcond for(int i%u = %u; i%u < %u; i%u += %u) {} //-> %u //LOOP",
m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment, src2.end_offset));
}
else
{
AddCode(fmt::Format("$ifcond for(int i%u = %u; i%u < %u; i%u += %u) //LOOP",
m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment));
m_loop_count++;
m_end_offsets.push_back(src2.end_offset << 2);
AddCode("{");
m_code_level++;
}
break;
case RSX_FP_OPCODE_REP:
if(!src0.exec_if_eq && !src0.exec_if_gr && !src0.exec_if_lt)
{
AddCode(fmt::Format("$ifcond for(int i%u = %u; i%u < %u; i%u += %u) {} //-> %u //REP",
m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment, src2.end_offset));
}
else
{
AddCode(fmt::Format("if($cond) for(int i%u = %u; i%u < %u; i%u += %u) //REP",
m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment));
m_loop_count++;
m_end_offsets.push_back(src2.end_offset << 2);
AddCode("{");
m_code_level++;
}
break;
//case RSX_FP_OPCODE_RET: SetDst("return"); break;
default:
LOG_ERROR(RSX, "Unknown fp opcode 0x%x (inst %d)", opcode, m_size / (4 * 4));
//Emu.Pause();
break;
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;
}
m_size += m_offset;
if(dst.end) break;
if (dst.end) break;
assert(m_offset % sizeof(u32) == 0);
data += m_offset / sizeof(u32);
@ -450,18 +613,18 @@ void GLFragmentDecompilerThread::Task()
m_parr.params.clear();
}
GLShaderProgram::GLShaderProgram()
GLFragmentProgram::GLFragmentProgram()
: m_decompiler_thread(nullptr)
, m_id(0)
, id(0)
{
}
GLShaderProgram::~GLShaderProgram()
GLFragmentProgram::~GLFragmentProgram()
{
if(m_decompiler_thread)
if (m_decompiler_thread)
{
Wait();
if(m_decompiler_thread->IsAlive())
if (m_decompiler_thread->IsAlive())
{
m_decompiler_thread->Stop();
}
@ -473,26 +636,26 @@ GLShaderProgram::~GLShaderProgram()
Delete();
}
void GLShaderProgram::Wait()
void GLFragmentProgram::Wait()
{
if(m_decompiler_thread && m_decompiler_thread->IsAlive())
if (m_decompiler_thread && m_decompiler_thread->IsAlive())
{
m_decompiler_thread->Join();
}
}
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();
}
void GLShaderProgram::DecompileAsync(RSXShaderProgram& prog)
void GLFragmentProgram::DecompileAsync(RSXFragmentProgram& prog)
{
if(m_decompiler_thread)
if (m_decompiler_thread)
{
Wait();
if(m_decompiler_thread->IsAlive())
if (m_decompiler_thread->IsAlive())
{
m_decompiler_thread->Stop();
}
@ -501,65 +664,68 @@ void GLShaderProgram::DecompileAsync(RSXShaderProgram& prog)
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();
}
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 int strlen = m_shader.length();
const char* str = shader.c_str();
const int strlen = shader.length();
glShaderSource(m_id, 1, &str, &strlen);
glCompileShader(m_id);
glShaderSource(id, 1, &str, &strlen);
glCompileShader(id);
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...
{
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)
{
GLsizei len;
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
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
}
}
void GLShaderProgram::Delete()
void GLFragmentProgram::Delete()
{
for (auto& param : m_parr.params) {
for (auto& param : parr.params) {
param.items.clear();
param.type.clear();
}
m_parr.params.clear();
m_shader.clear();
parr.params.clear();
shader.clear();
if (m_id)
if (id)
{
if (Emu.IsStopped())
{
LOG_WARNING(RSX, "GLShaderProgram::Delete(): glDeleteShader(%d) avoided", m_id);
LOG_WARNING(RSX, "GLFragmentProgram::Delete(): glDeleteShader(%d) avoided", id);
}
else
{
glDeleteShader(m_id);
glDeleteShader(id);
}
m_id = 0;
id = 0;
}
}

View File

@ -155,6 +155,7 @@ struct GLFragmentDecompilerThread : public ThreadBase
std::string AddTex();
std::string Format(const std::string& code);
void AddCodeCond(const std::string& dst, const std::string& src);
std::string GetCond();
template<typename T> std::string GetSRC(T src);
std::string BuildCode();
@ -167,24 +168,28 @@ struct GLFragmentDecompilerThread : public ThreadBase
/** 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.
*/
class GLShaderProgram
class GLFragmentProgram
{
public:
GLShaderProgram();
~GLShaderProgram();
GLFragmentProgram();
~GLFragmentProgram();
GLParamArray parr;
u32 id;
std::string shader;
/**
* 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
*/
void Decompile(RSXShaderProgram& prog);
void Decompile(RSXFragmentProgram& prog);
/**
* 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.
* @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. */
void Wait();
@ -192,37 +197,10 @@ public:
/** Compile the decompiled fragment shader into a format we can use with OpenGL. */
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:
/** Threaded fragment shader decompiler responsible for decompiling this program */
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 */
void Delete();
};

File diff suppressed because it is too large Load Diff

View File

@ -67,7 +67,7 @@ public:
class PostDrawObj
{
protected:
GLShaderProgram m_fp;
GLFragmentProgram m_fp;
GLVertexProgram m_vp;
GLProgram m_program;
GLfbo m_fbo;
@ -144,10 +144,11 @@ private:
int m_vp_buf_num;
GLProgramBuffer m_prog_buffer;
GLShaderProgram m_shader_prog;
GLFragmentProgram m_fragment_prog;
GLVertexProgram m_vertex_prog;
GLTexture m_gl_textures[m_textures_count];
GLTexture m_gl_vertex_textures[m_textures_count];
GLvao m_vao;
GLvbo m_vbo;
@ -170,7 +171,6 @@ private:
void InitVertexData();
void InitFragmentData();
void Enable(bool enable, const u32 cap);
virtual void Close();
bool LoadProgram();
void WriteBuffers();
@ -189,7 +189,34 @@ protected:
virtual void OnInitThread();
virtual void OnExitThread();
virtual void OnReset();
virtual void ExecCMD(u32 cmd);
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();
};

View File

@ -98,6 +98,13 @@ void GLProgram::SetTex(u32 index)
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()
{
if(!IsCreated()) return;

View File

@ -24,5 +24,6 @@ public:
void Use();
void UnUse();
void SetTex(u32 index);
void SetVTex(u32 index);
void Delete();
};

View File

@ -4,14 +4,14 @@
#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)
{
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.SetShaderText(m_buf[i].fp_shader);
gl_fp.id = m_buf[i].fp_id;
gl_fp.shader = m_buf[i].fp_shader.c_str();
return i;
}
@ -85,37 +85,37 @@ u32 GLProgramBuffer::GetProg(u32 fp, u32 vp) const
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;
LOG_NOTICE(RSX, "Add program (%d):", m_buf.size());
LOG_NOTICE(RSX, "*** prog id = %d", prog.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, "*** fp data size = %d", rsx_fp.size);
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.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.vp_data = rsx_vp.data;
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);
}
void GLProgramBuffer::Clear()
{
for(u32 i=0; i<m_buf.size(); ++i)
for (u32 i = 0; i < m_buf.size(); ++i)
{
glDetachShader(m_buf[i].prog_id, m_buf[i].fp_id);
glDetachShader(m_buf[i].prog_id, m_buf[i].vp_id);

View File

@ -16,7 +16,7 @@ struct GLProgramBuffer
{
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);
bool CmpVP(const u32 a, const u32 b) const;
@ -24,6 +24,6 @@ struct GLProgramBuffer
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();
};

View File

@ -1,5 +1,6 @@
#pragma once
#include "OpenGL.h"
#include <unordered_map>
enum GLParamFlag
{
@ -41,9 +42,9 @@ struct GLParamType
bool SearchName(const std::string& name)
{
for(u32 i=0; i<items.size(); ++i)
for (u32 i = 0; i<items.size(); ++i)
{
if(items[i].name.compare(name) == 0) return true;
if (items[i].name.compare(name) == 0) return true;
}
return false;
@ -53,10 +54,10 @@ struct GLParamType
{
std::string ret = "";
for(u32 n=0; n<items.size(); ++n)
for (u32 n = 0; n<items.size(); ++n)
{
ret += items[n].location + type + " " + items[n].name;
if(!items[n].value.empty())
if (!items[n].value.empty())
{
ret += " = " + items[n].value;
}
@ -73,7 +74,7 @@ struct GLParamArray
GLParamType* SearchParam(const std::string& type)
{
for(u32 i=0; i<params.size(); ++i)
for (u32 i = 0; i<params.size(); ++i)
{
if (params[i].type.compare(type) == 0)
return &params[i];
@ -84,7 +85,7 @@ struct GLParamArray
std::string GetParamFlag(const GLParamFlag flag)
{
switch(flag)
switch (flag)
{
case PARAM_OUT: return "out ";
case PARAM_IN: return "in ";
@ -106,9 +107,9 @@ struct GLParamArray
type = GetParamFlag(flag) + type;
GLParamType* t = SearchParam(type);
if(t)
if (t)
{
if(!t->SearchName(name)) t->items.emplace_back(name, -1, value);
if (!t->SearchName(name)) t->items.emplace_back(name, -1, value);
}
else
{
@ -125,9 +126,9 @@ struct GLParamArray
type = GetParamFlag(flag) + type;
GLParamType* t = SearchParam(type);
if(t)
if (t)
{
if(!t->SearchName(name)) t->items.emplace_back(name, location);
if (!t->SearchName(name)) t->items.emplace_back(name, location);
}
else
{
@ -139,3 +140,90 @@ struct GLParamArray
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 }, ".");
}
};

View File

@ -8,19 +8,19 @@ std::string GLVertexDecompilerThread::GetMask(bool is_sca)
{
std::string ret;
if(is_sca)
if (is_sca)
{
if(d3.sca_writemask_x) ret += "x";
if(d3.sca_writemask_y) ret += "y";
if(d3.sca_writemask_z) ret += "z";
if(d3.sca_writemask_w) ret += "w";
if (d3.sca_writemask_x) ret += "x";
if (d3.sca_writemask_y) ret += "y";
if (d3.sca_writemask_z) ret += "z";
if (d3.sca_writemask_w) ret += "w";
}
else
{
if(d3.vec_writemask_x) ret += "x";
if(d3.vec_writemask_y) ret += "y";
if(d3.vec_writemask_z) ret += "z";
if(d3.vec_writemask_w) ret += "w";
if (d3.vec_writemask_x) ret += "x";
if (d3.vec_writemask_y) ret += "y";
if (d3.vec_writemask_z) ret += "z";
if (d3.vec_writemask_w) ret += "w";
}
return ret.empty() || ret == "xyzw" ? "" : ("." + ret);
@ -40,17 +40,17 @@ std::string GLVertexDecompilerThread::GetDST(bool isSca)
{
std::string ret;
switch(isSca ? 0x1f : d3.dst)
switch (isSca ? 0x1f : d3.dst)
{
case 0x1f:
ret += m_parr.AddParam(PARAM_NONE, "vec4", std::string("tmp") + std::to_string(isSca ? d3.sca_dst_tmp : d0.dst_tmp));
break;
break;
default:
if (d3.dst > 15)
LOG_ERROR(RSX, "dst index out of range: %u", d3.dst);
ret += m_parr.AddParam(PARAM_NONE, "vec4", std::string("dst_reg") + std::to_string(d3.dst), d3.dst == 0 ? "vec4(0.0f, 0.0f, 0.0f, 1.0f)" : "vec4(0.0)");
break;
break;
}
return ret;
@ -70,13 +70,13 @@ std::string GLVertexDecompilerThread::GetSRC(const u32 n)
std::string ret;
switch(src[n].reg_type)
switch (src[n].reg_type)
{
case 1: //temp
ret += m_parr.AddParam(PARAM_NONE, "vec4", "tmp" + std::to_string(src[n].tmp_src));
break;
break;
case 2: //input
if (d1.input_src < (sizeof(reg_table)/sizeof(reg_table[0])))
if (d1.input_src < (sizeof(reg_table) / sizeof(reg_table[0])))
{
ret += m_parr.AddParam(PARAM_IN, "vec4", reg_table[d1.input_src], d1.input_src);
}
@ -85,16 +85,16 @@ std::string GLVertexDecompilerThread::GetSRC(const u32 n)
LOG_ERROR(RSX, "Bad input src num: %d", fmt::by_value(d1.input_src));
ret += m_parr.AddParam(PARAM_IN, "vec4", "in_unk", d1.input_src);
}
break;
break;
case 3: //const
m_parr.AddParam(PARAM_UNIFORM, "vec4", std::string("vc[468]"));
ret += std::string("vc[") + std::to_string(d1.const_src) + (d3.index_const ? " + " + AddAddrReg() : "") + "]";
break;
break;
default:
LOG_ERROR(RSX, "Bad src%u reg type: %d", n, fmt::by_value(src[n].reg_type));
Emu.Pause();
break;
break;
}
static const std::string f = "xyzw";
@ -106,26 +106,26 @@ std::string GLVertexDecompilerThread::GetSRC(const u32 n)
swizzle += f[src[n].swz_z];
swizzle += f[src[n].swz_w];
if(swizzle != f) ret += '.' + swizzle;
if (swizzle != f) ret += '.' + swizzle;
bool abs;
switch(n)
switch (n)
{
case 0: abs = d0.src0_abs; break;
case 1: abs = d0.src1_abs; break;
case 2: abs = d0.src2_abs; break;
}
if(abs) ret = "abs(" + ret + ")";
if(src[n].neg) ret = "-" + ret;
if (abs) ret = "abs(" + ret + ")";
if (src[n].neg) ret = "-" + ret;
return ret;
}
void GLVertexDecompilerThread::SetDST(bool is_sca, std::string value)
{
if(d0.cond == 0) return;
if (d0.cond == 0) return;
enum
{
@ -138,12 +138,12 @@ void GLVertexDecompilerThread::SetDST(bool is_sca, std::string value)
value += mask;
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)
{
value = "clamp(" + value + ", 0.0, 1.0)";
}
@ -152,22 +152,20 @@ void GLVertexDecompilerThread::SetDST(bool is_sca, std::string value)
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;
}
if (d3.dst != 0x1f || (is_sca ? d3.sca_dst_tmp != 0x3f : d0.dst_tmp != 0x3f))
else 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)
code += "$ifcond ";
code += dest + value;
AddCode(code + ";");
AddCodeCond(Format(dest), value);
}
std::string GLVertexDecompilerThread::GetFunc()
@ -188,6 +186,11 @@ std::string GLVertexDecompilerThread::GetFunc()
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)
{
const std::pair<std::string, std::function<std::string()>> repl_list[] =
@ -200,14 +203,16 @@ std::string GLVertexDecompilerThread::Format(const std::string& code)
{ "$am", std::bind(std::mem_fn(&GLVertexDecompilerThread::AddAddrMask), this) },
{ "$a", std::bind(std::mem_fn(&GLVertexDecompilerThread::AddAddrReg), this) },
{ "$fa", [this]()->std::string {return std::to_string(GetAddr()); } },
{ "$t", std::bind(std::mem_fn(&GLVertexDecompilerThread::GetTex), this) },
{ "$fa", [this]()->std::string { return std::to_string(GetAddr()); } },
{ "$f()", std::bind(std::mem_fn(&GLVertexDecompilerThread::GetFunc), this) },
{ "$ifcond ", [this]() -> std::string
{
const std::string& cond = GetCond();
if (cond == "true") return "";
return "if(" + cond + ") ";
}
{
const std::string& cond = GetCond();
if (cond == "true") return "";
return "if(" + cond + ") ";
}
},
{ "$cond", std::bind(std::mem_fn(&GLVertexDecompilerThread::GetCond), this) }
};
@ -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());
}
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()
{
@ -290,21 +359,21 @@ std::string GLVertexDecompilerThread::BuildFuncBody(const FuncInfo& func)
{
std::string result;
for(uint i=func.offset; i<m_body.size(); ++i)
for (uint i = func.offset; i<m_body.size(); ++i)
{
if(i != func.offset)
if (i != func.offset)
{
uint call_func = -1;
for(uint j=0; j<m_funcs.size(); ++j)
for (uint j = 0; j<m_funcs.size(); ++j)
{
if(m_funcs[j].offset == i)
if (m_funcs[j].offset == i)
{
call_func = j;
break;
}
}
if(call_func != -1)
if (call_func != -1)
{
result += '\t' + m_funcs[call_func].name + "();\n";
break;
@ -352,7 +421,7 @@ std::string GLVertexDecompilerThread::BuildCode()
{ "tc6", true, "dst_reg13", "", false },
{ "tc7", true, "dst_reg14", "", false },
{ "tc8", true, "dst_reg15", "", false },
{ "tc9", true, "dst_reg6", "", false } // In this line, dst_reg6 is correct since dst_reg goes from 0 to 15.
{ "tc9", true, "dst_reg6", "", false } // In this line, dst_reg6 is correct since dst_reg goes from 0 to 15.
};
std::string f;
@ -385,7 +454,7 @@ std::string GLVertexDecompilerThread::BuildCode()
std::string fp;
for (int i = m_funcs.size() - 1; i>0; --i)
for (int i = m_funcs.size() - 1; i > 0; --i)
{
fp += fmt::Format("void %s();\n", m_funcs[i].name.c_str());
}
@ -423,7 +492,7 @@ std::string GLVertexDecompilerThread::BuildCode()
f += fmt::Format("\nvoid %s()\n{\n%s}\n", m_funcs[1].name.c_str(), main_body.c_str());
for(uint i=2; i<m_funcs.size(); ++i)
for (uint i = 2; i<m_funcs.size(); ++i)
{
f += fmt::Format("\nvoid %s()\n{\n%s}\n", m_funcs[i].name.c_str(), BuildFuncBody(m_funcs[i]).c_str());
}
@ -445,16 +514,85 @@ void GLVertexDecompilerThread::Task()
m_instr_count = 0;
for (int i = 0; i < m_max_instr_count; ++i)
{
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];
d0.HEX = m_data[i++];
d1.HEX = m_data[i++];
d2.HEX = m_data[i++];
d3.HEX = m_data[i++];
if (is_has_BRA)
{
d3.HEX = m_data[i];
i += 4;
}
else
{
d1.HEX = m_data[i++];
switch (d1.sca_opcode)
{
case 0x08: //BRA
LOG_WARNING(RSX, "BRA found. Please report to RPCS3 team.");
is_has_BRA = true;
m_jump_lvls.clear();
d3.HEX = m_data[++i];
i += 4;
break;
case 0x09: //BRI
d2.HEX = m_data[i++];
d3.HEX = m_data[i];
i += 2;
m_jump_lvls.emplace(GetAddr());
break;
default:
d3.HEX = m_data[++i];
i += 2;
break;
}
}
if (d3.end)
{
m_instr_count++;
if (i < m_data.size())
{
LOG_ERROR(RSX, "Program end before buffer end.");
}
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;
@ -462,107 +600,168 @@ void GLVertexDecompilerThread::Task()
src[2].src2l = d3.src2l;
src[2].src2h = d2.src2h;
if(!d1.sca_opcode && !d1.vec_opcode)
if (i && (is_has_BRA || std::find(m_jump_lvls.begin(), m_jump_lvls.end(), i) != m_jump_lvls.end()))
{
m_body.push_back("//nop");
m_cur_instr->close_scopes++;
AddCode("}");
AddCode("");
AddCode(fmt::Format("if (jump_position <= %u)", jump_position++));
AddCode("{");
m_cur_instr->open_scopes++;
}
switch(d1.sca_opcode)
if (!d1.sca_opcode && !d1.vec_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("//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)
{
AddCode("if(!$cond)");
AddCode("{");
m_cur_instr->open_scopes++;
m_instructions[GetAddr()].put_close_scopes++;
jump_position = GetAddr();
}
else
{
AddCode("} while ($cond);");
m_cur_instr->close_scopes++;
m_instructions[GetAddr()].do_count++;
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 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;)
*/
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:
m_body.push_back(fmt::Format("//Unknown vp sca_opcode 0x%x", fmt::by_value(d1.sca_opcode)));
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;
break;
}
switch(d1.vec_opcode)
switch (d1.vec_opcode)
{
case 0x00: break; //NOP
case 0x01: SetDSTVec("$0"); break; //MOV
case 0x02: SetDSTVec("($0 * $1)"); break; //MUL
case 0x03: SetDSTVec("($0 + $2)"); break; //ADD
case 0x04: SetDSTVec("($0 * $1 + $2)"); break; //MAD
case 0x05: SetDSTVec("vec4(dot($0.xyz, $1.xyz))"); break; //DP3
case 0x06: SetDSTVec("vec4(dot(vec4($0.xyz, 1.0), $1))"); break; //DPH
case 0x07: SetDSTVec("vec4(dot($0, $1))"); break; //DP4
case 0x08: SetDSTVec("vec4(distance($0, $1))"); break; //DST
case 0x09: SetDSTVec("min($0, $1)"); break; //MIN
case 0x0a: SetDSTVec("max($0, $1)"); break; //MAX
case 0x0b: SetDSTVec("vec4(lessThan($0, $1))"); break; //SLT
case 0x0c: SetDSTVec("vec4(greaterThanEqual($0, $1))"); break; //SGE
case 0x0d: AddCode("$ifcond $a = ivec4($0)$am;"); break; //ARL
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
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:
m_body.push_back(fmt::Format("//Unknown vp opcode 0x%x", fmt::by_value(d1.vec_opcode)));
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(d3.end)
{
m_instr_count++;
if(i < m_data.size())
LOG_ERROR(RSX, "Program end before buffer end.");
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_jump_lvls.clear();
m_body.clear();
if (m_funcs.size() > 2)
{
m_funcs.erase(m_funcs.begin()+2, m_funcs.end());
m_funcs.erase(m_funcs.begin() + 2, m_funcs.end());
}
}
@ -574,10 +773,10 @@ GLVertexProgram::GLVertexProgram()
GLVertexProgram::~GLVertexProgram()
{
if(m_decompiler_thread)
if (m_decompiler_thread)
{
Wait();
if(m_decompiler_thread->IsAlive())
if (m_decompiler_thread->IsAlive())
{
m_decompiler_thread->Stop();
}
@ -591,7 +790,7 @@ GLVertexProgram::~GLVertexProgram()
void GLVertexProgram::Wait()
{
if(m_decompiler_thread && m_decompiler_thread->IsAlive())
if (m_decompiler_thread && m_decompiler_thread->IsAlive())
{
m_decompiler_thread->Join();
}
@ -623,7 +822,10 @@ void GLVertexProgram::DecompileAsync(RSXVertexProgram& prog)
void GLVertexProgram::Compile()
{
if(id) glDeleteShader(id);
if (id)
{
glDeleteShader(id);
}
id = glCreateShader(GL_VERTEX_SHADER);
@ -635,13 +837,13 @@ void GLVertexProgram::Compile()
GLint r = GL_FALSE;
glGetShaderiv(id, GL_COMPILE_STATUS, &r);
if(r != GL_TRUE)
if (r != GL_TRUE)
{
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &r);
if(r)
if (r)
{
char* buf = new char[r+1]();
char* buf = new char[r + 1]();
GLsizei len;
glGetShaderInfoLog(id, r, &len, buf);
LOG_ERROR(RSX, "Failed to compile vertex shader: %s", buf);
@ -660,7 +862,7 @@ void GLVertexProgram::Delete()
parr.params.clear();
shader.clear();
if(id)
if (id)
{
if (Emu.IsStopped())
{

View File

@ -2,6 +2,60 @@
#include "GLShaderParam.h"
#include "Emu/RSX/RSXVertexProgram.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
{
@ -154,8 +208,8 @@ struct GLVertexDecompilerThread : public ThreadBase
Instruction* m_cur_instr;
size_t m_instr_count;
std::set<int> m_jump_lvls;
std::vector<std::string> m_body;
std::vector<FuncInfo> m_funcs;
//wxString main;
@ -184,12 +238,14 @@ struct GLVertexDecompilerThread : public ThreadBase
std::string GetDST(bool is_sca = false);
std::string GetSRC(const u32 n);
std::string GetFunc();
std::string GetTex();
std::string GetCond();
std::string AddAddrMask();
std::string AddAddrReg();
u32 GetAddr();
std::string Format(const std::string& code);
void AddCodeCond(const std::string& dst, const std::string& src);
void AddCode(const std::string& code);
void SetDST(bool is_sca, std::string value);
void SetDSTVec(const std::string& code);

View File

@ -6,44 +6,43 @@ class NullGSRender
{
public:
NullGSRender()
{
}
virtual ~NullGSRender()
{
}
NullGSRender() {}
virtual ~NullGSRender() {}
private:
virtual void OnInit()
{
}
virtual void OnInitThread()
{
}
virtual void OnExitThread()
{
}
virtual void OnReset()
{
}
virtual void ExecCMD(u32 cmd)
{
}
virtual void ExecCMD()
{
}
virtual void Flip()
{
}
virtual void Close()
{
}
virtual void OnInit() {}
virtual void OnInitThread() {}
virtual void OnExitThread() {}
virtual void OnReset() {}
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 ExecCMD() {}
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 Close() {}
};

View File

@ -49,7 +49,7 @@ enum
RSX_FP_OPCODE_PKG = 0x2C, // Pack with sRGB transformation
RSX_FP_OPCODE_UPG = 0x2D, // Unpack gamma
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_TEXBEM = 0x33,
RSX_FP_OPCODE_TXPBEM = 0x34,
@ -71,14 +71,14 @@ enum
RSX_FP_OPCODE_RET = 0x45, // Return
};
struct RSXShaderProgram
struct RSXFragmentProgram
{
u32 size;
u32 addr;
u32 offset;
u32 ctrl;
RSXShaderProgram()
RSXFragmentProgram()
: size(0)
, addr(0)
, offset(0)

View File

@ -210,3 +210,206 @@ void RSXTexture::SetControl3(u16 depth, u32 pitch)
m_depth = depth;
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)];
}

View File

@ -2,6 +2,7 @@
class RSXTexture
{
protected:
u8 m_index;
public:
@ -11,6 +12,64 @@ public:
public:
RSXTexture();
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();
// Offset
@ -60,6 +119,4 @@ public:
// Border Color
u32 GetBorderColor() const;
void SetControl3(u16 depth, u32 pitch);
};

File diff suppressed because it is too large Load Diff

View File

@ -7,6 +7,7 @@
#include <stack>
#include "Utilities/SSemaphore.h"
#include "Utilities/Thread.h"
#include "Utilities/Timer.h"
enum Method
{
@ -101,19 +102,22 @@ public:
protected:
std::stack<u32> m_call_stack;
CellGcmControl* m_ctrl;
Timer m_timer_sync;
double m_fps_limit = 59.94;
public:
GcmTileInfo m_tiles[m_tiles_count];
GcmZcullInfo m_zculls[m_zculls_count];
RSXTexture m_textures[m_textures_count];
RSXVertexTexture m_vertex_textures[m_textures_count];
RSXVertexData m_vertex_data[m_vertex_count];
RSXIndexArrayData m_indexed_array;
std::vector<RSXTransformConstant> m_fragment_constants;
std::vector<RSXTransformConstant> m_transform_constants;
u32 m_shader_ctrl, m_cur_shader_prog_num;
RSXShaderProgram m_shader_progs[m_fragment_count];
RSXShaderProgram* m_cur_shader_prog;
u32 m_shader_ctrl, m_cur_fragment_prog_num;
RSXFragmentProgram m_fragment_progs[m_fragment_count];
RSXFragmentProgram* m_cur_fragment_prog;
RSXVertexProgram m_vertex_progs[m_vertex_count];
RSXVertexProgram* m_cur_vertex_prog;
@ -492,7 +496,7 @@ protected:
m_front_face = 0x0901; // GL_CCW
m_cull_face = 0x0405; // GL_BACK
m_alpha_func = 0x0207; // GL_ALWAYS
m_alpha_ref = 0;
m_alpha_ref = 0.0;
m_logic_op = 0x1503; // GL_COPY
m_shade_mode = 0x1D01; // GL_SMOOTH
m_depth_mask = 1;
@ -515,12 +519,15 @@ protected:
m_line_stipple_factor = 1;
m_vertex_data_base_offset = 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;
}
// Construct Textures
for(int i=0; i<16; i++)
for (int i = 0; i < 16; i++)
{
m_textures[i] = RSXTexture(i);
}
@ -607,7 +614,7 @@ protected:
m_clear_surface_mask = 0;
m_begin_end = 0;
for(uint i=0; i<m_textures_count; ++i)
for (uint i = 0; i < m_textures_count; ++i)
{
m_textures[i].Init();
}
@ -618,19 +625,46 @@ protected:
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 nativeRescale(float width, float height);
void NativeRescale(float width, float height);
virtual void OnInit() = 0;
virtual void OnInitThread() = 0;
virtual void OnExitThread() = 0;
virtual void OnReset() = 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;
void LoadVertexData(u32 first, u32 count)
{
for(u32 i=0; i<m_vertex_count; ++i)
for (u32 i = 0; i < m_vertex_count; ++i)
{
if(!m_vertex_data[i].IsEnabled()) continue;

View File

@ -31,11 +31,12 @@ enum CellVideoOutResolutionId
CELL_VIDEO_OUT_RESOLUTION_1440x1080 = 11,
CELL_VIDEO_OUT_RESOLUTION_1280x1080 = 12,
CELL_VIDEO_OUT_RESOLUTION_960x1080 = 13,
CELL_VIDEO_OUT_RESOLUTION_720_3D_FRAME_PACKING = 0x81,
CELL_VIDEO_OUT_RESOLUTION_1024x720_3D_FRAME_PACKING = 0x88,
CELL_VIDEO_OUT_RESOLUTION_960x720_3D_FRAME_PACKING = 0x89,
CELL_VIDEO_OUT_RESOLUTION_800x720_3D_FRAME_PACKING = 0x8a,
CELL_VIDEO_OUT_RESOLUTION_640x720_3D_FRAME_PACKING = 0x8b,
CELL_VIDEO_OUT_RESOLUTION_720_3D_FRAME_PACKING = 0x81,
CELL_VIDEO_OUT_RESOLUTION_1024x720_3D_FRAME_PACKING = 0x88,
CELL_VIDEO_OUT_RESOLUTION_960x720_3D_FRAME_PACKING = 0x89,
CELL_VIDEO_OUT_RESOLUTION_800x720_3D_FRAME_PACKING = 0x8a,
CELL_VIDEO_OUT_RESOLUTION_640x720_3D_FRAME_PACKING = 0x8b,
CELL_VIDEO_OUT_RESOLUTION_720_SIMULVIEW_FRAME_PACKING = 0x91,
};
enum CellVideoOutScanMode

View File

@ -3783,6 +3783,7 @@ std::string SysCalls::GetHLEFuncName(const u32 fid)
case 0x8bb03ab8: return "sys_game_board_storage_write";
case 0x8c2bb498: return "sys_spinlock_initialize";
case 0x96328741: return "_sys_process_at_Exitspawn";
case 0x4f7172c9: return "sys_process_is_stack";
case 0x996f7cf8: return "_sys_strncat";
case 0x99c88692: return "_sys_strcpy";
case 0x9d3c0f81: return "sys_mempool_destroy";

View File

@ -36,7 +36,7 @@ public:
template<typename... Targs> __noinline void Notice(const char* fmt, Targs... args) const
{
LogOutput(LogNotice, " : ", fmt::Format(fmt, args...));
LogOutput(LogNotice, ": ", fmt::Format(fmt, args...));
}
template<typename... Targs> __forceinline void Log(const char* fmt, Targs... args) const
@ -62,7 +62,7 @@ public:
template<typename... Targs> __noinline void Success(const char* fmt, Targs... args) const
{
LogOutput(LogSuccess, " : ", fmt::Format(fmt, args...));
LogOutput(LogSuccess, ": ", fmt::Format(fmt, args...));
}
template<typename... Targs> __noinline void Warning(const u32 id, const char* fmt, Targs... args) const

View File

@ -38,6 +38,7 @@ extern void cellRtc_init(Module *pxThis);
extern void cellSail_init(Module *pxThis);
extern void cellSpurs_init(Module *pxThis);
extern void cellSpursJq_init(Module *pxThis);
extern void cellSubdisplay_init(Module *pxThis);
extern void cellSync_init(Module *pxThis);
extern void cellSync2_init(Module *pxThis);
extern void cellSysutil_init(Module *pxThis);
@ -125,7 +126,7 @@ static const g_modules_list[] =
{ 0x0031, "cellAvconfExt", cellAvconfExt_init, nullptr, nullptr },
{ 0x0032, "cellUserInfo", cellUserInfo_init, nullptr, nullptr },
{ 0x0033, "cellSysutilSavedata", nullptr, nullptr, nullptr },
{ 0x0034, "cellSubdisplay", nullptr, nullptr, nullptr },
{ 0x0034, "cellSubdisplay", cellSubdisplay_init, nullptr, nullptr },
{ 0x0035, "cellSysutilRec", nullptr, nullptr, nullptr },
{ 0x0036, "cellVideoExport", nullptr, nullptr, nullptr },
{ 0x0037, "cellGameExec", nullptr, nullptr, nullptr },

View File

@ -188,7 +188,7 @@ void fix_import(Module* module, u32 func, u32 addr)
*ptr++ = ORI(11, 11, func & 0xffff);
*ptr++ = NOP();
++ptr;
*ptr++ = SC(2);
*ptr++ = SC(0);
*ptr++ = BLR();
*ptr++ = NOP();
*ptr++ = NOP();

View File

@ -95,7 +95,8 @@ public:
public:
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;
@ -106,7 +107,7 @@ public:
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;
@ -117,10 +118,11 @@ public:
return true;
}
bool CheckID(u32 id, ID*& _id) const;
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);
}

View File

@ -19,6 +19,8 @@ extern "C"
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)
: type(type)
, memAddr(addr)
@ -31,33 +33,55 @@ AudioDecoder::AudioDecoder(AudioCodecType type, u32 addr, u32 size, vm::ptr<Cell
, is_finished(false)
, just_started(false)
, just_finished(false)
, codec(nullptr)
, input_format(nullptr)
, ctx(nullptr)
, fmt(nullptr)
{
av_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)
{
cellAdec->Error("AudioDecoder(): avcodec_find_decoder(ATRAC3P) failed");
Emu.Pause();
return;
ADEC_ERROR("AudioDecoder(): avcodec_find_decoder() failed");
}
if (!input_format)
{
ADEC_ERROR("AudioDecoder(): av_find_input_format() failed");
}
fmt = avformat_alloc_context();
if (!fmt)
{
cellAdec->Error("AudioDecoder(): avformat_alloc_context failed");
Emu.Pause();
return;
ADEC_ERROR("AudioDecoder(): avformat_alloc_context() failed");
}
io_buf = (u8*)av_malloc(4096);
fmt->pb = avio_alloc_context(io_buf, 256, 0, this, adecRead, NULL, NULL);
if (!fmt->pb)
{
cellAdec->Error("AudioDecoder(): avio_alloc_context failed");
Emu.Pause();
return;
ADEC_ERROR("AudioDecoder(): avio_alloc_context() failed");
}
}
@ -65,7 +89,7 @@ AudioDecoder::~AudioDecoder()
{
// TODO: check finalization
AdecFrame af;
while (frames.Pop(af, &sq_no_wait))
while (frames.try_pop(af))
{
av_frame_unref(af.data);
av_frame_free(&af.data);
@ -93,11 +117,11 @@ int adecRead(void* opaque, u8* buf, int buf_size)
int res = 0;
next:
if (adec.reader.has_ats)
if (adecIsAtracX(adec.type) && adec.reader.has_ats)
{
u8 code1 = vm::read8(adec.reader.addr + 2);
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.sample_rate = at3freq[code1 >> 5];
@ -106,9 +130,9 @@ next:
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))
{
cellAdec->Error("adecRead(): OMAHeader writing failed");
@ -127,7 +151,7 @@ next:
if (adec.reader.size < (u32)buf_size /*&& !adec.just_started*/)
{
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");
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.job.Pop(adec.task, nullptr);
adec.job.pop(adec.task);
adec.reader.addr = adec.task.au.addr;
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;
@ -207,8 +232,9 @@ u32 adecOpen(AudioDecoder* data)
adec.adecCb->InitRegs();
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");
AdecTask& task = adec.task;
@ -220,13 +246,7 @@ u32 adecOpen(AudioDecoder* data)
break;
}
//if (!adec.job.GetCountUnsafe() && adec.is_running)
//{
// std::this_thread::sleep_for(std::chrono::milliseconds(1));
// continue;
//}
if (!adec.job.Pop(task, &adec.is_closed))
if (!adec.job.pop(task, &adec.is_closed))
{
break;
}
@ -244,12 +264,16 @@ u32 adecOpen(AudioDecoder* data)
adec.reader.has_ats = false;
adec.just_started = true;
adec.channels = task.at3p.channels;
adec.frame_size = task.at3p.frame_size;
adec.sample_rate = task.at3p.sample_rate;
adec.use_ats_headers = task.at3p.ats_header == 1;
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.sample_rate = task.at3p.sample_rate;
adec.use_ats_headers = task.at3p.ats_header == 1;
}
break;
}
break;
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.just_finished = true;
break;
}
break;
case adecDecodeAu:
{
@ -273,7 +297,8 @@ u32 adecOpen(AudioDecoder* data)
if (adec.just_started)
{
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
@ -313,39 +338,19 @@ u32 adecOpen(AudioDecoder* data)
{
AVDictionary* opts = nullptr;
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)
{
cellAdec->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;
ADEC_ERROR("adecDecodeAu: avformat_open_input() failed (err=0x%x, opts=%d)", err, opts ? 1 : 0);
}
//err = avformat_find_stream_info(adec.fmt, NULL);
//if (err)
//if (err || !adec.fmt->nb_streams)
//{
// cellAdec->Error("adecDecodeAu: avformat_find_stream_info() failed");
// Emu.Pause();
// break;
// ADEC_ERROR("adecDecodeAu: avformat_find_stream_info() failed (err=0x%x, nb_streams=%d)", err, adec.fmt->nb_streams);
//}
//if (!adec.fmt->nb_streams)
//{
// cellAdec->Error("adecDecodeAu: no stream found");
// Emu.Pause();
// break;
//}
if (!avformat_new_stream(adec.fmt, codec))
if (!avformat_new_stream(adec.fmt, adec.codec))
{
cellAdec->Error("adecDecodeAu: avformat_new_stream() failed");
Emu.Pause();
break;
ADEC_ERROR("adecDecodeAu: avformat_new_stream() failed");
}
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);
// not multithread-safe (???)
err = avcodec_open2(adec.ctx, codec, &opts);
err = avcodec_open2(adec.ctx, adec.codec, &opts);
}
if (err || opts)
{
cellAdec->Error("adecDecodeAu: avcodec_open2() failed");
Emu.Pause();
break;
ADEC_ERROR("adecDecodeAu: avcodec_open2() failed (err=0x%x, opts=%d)", err, opts ? 1 : 0);
}
adec.just_started = false;
}
@ -404,9 +407,7 @@ u32 adecOpen(AudioDecoder* data)
if (!frame.data)
{
cellAdec->Error("adecDecodeAu: av_frame_alloc() failed");
Emu.Pause();
break;
ADEC_ERROR("adecDecodeAu: av_frame_alloc() failed");
}
int got_frame = 0;
@ -415,7 +416,7 @@ u32 adecOpen(AudioDecoder* data)
if (decode <= 0)
{
if (!last_frame && decode < 0)
if (decode < 0)
{
cellAdec->Error("adecDecodeAu: AU decoding error(0x%x)", decode);
}
@ -424,36 +425,34 @@ u32 adecOpen(AudioDecoder* data)
if (got_frame)
{
u64 ts = av_frame_get_best_effort_timestamp(frame.data);
if (ts != AV_NOPTS_VALUE)
//u64 ts = av_frame_get_best_effort_timestamp(frame.data);
//if (ts != AV_NOPTS_VALUE)
//{
// frame.pts = ts/* - adec.first_pts*/;
// adec.last_pts = frame.pts;
//}
adec.last_pts += ((u64)frame.data->nb_samples) * 90000 / frame.data->sample_rate;
frame.pts = adec.last_pts;
s32 nbps = av_get_bytes_per_sample((AVSampleFormat)frame.data->format);
switch (frame.data->format)
{
frame.pts = ts/* - adec.first_pts*/;
adec.last_pts = frame.pts;
}
else
case AV_SAMPLE_FMT_FLTP: break;
case AV_SAMPLE_FMT_S16P: break;
default:
{
adec.last_pts += ((u64)frame.data->nb_samples) * 90000 / frame.data->sample_rate;
frame.pts = adec.last_pts;
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.auSize = task.au.size;
frame.userdata = task.au.userdata;
frame.size = frame.data->nb_samples * frame.data->channels * sizeof(float);
if (frame.data->format != AV_SAMPLE_FMT_FLTP)
{
cellAdec->Error("adecDecodeaAu: unsupported frame format(%d)", frame.data->format);
Emu.Pause();
break;
}
frame.size = frame.data->nb_samples * frame.data->channels * nbps;
//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,
//av_get_bytes_per_sample((AVSampleFormat)frame.data->format));
//frame.pts, frame.data->nb_samples, frame.data->channels, frame.data->sample_rate, nbps);
if (adec.frames.Push(frame, &adec.is_closed))
if (adec.frames.push(frame, &adec.is_closed))
{
frame.data = nullptr; // to prevent destruction
adec.cbFunc.call(*adec.adecCb, adec.id, CELL_ADEC_MSG_TYPE_PCMOUT, CELL_OK, adec.cbArg);
@ -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);
break;
}
break;
case adecClose: break;
case adecClose:
{
break;
}
default:
{
cellAdec->Error("Audio Decoder thread error: unknown task(%d)", task.type);
Emu.Pause();
return;
ADEC_ERROR("Audio Decoder thread error: unknown task(%d)", task.type);
}
}
}
@ -490,23 +490,25 @@ bool adecCheckType(AudioCodecType type)
{
switch (type)
{
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: cellAdec->Notice("adecCheckType(): ATRAC3plus"); 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_AC3:
case CELL_ADEC_TYPE_MP3:
case CELL_ADEC_TYPE_ATRAC3:
case CELL_ADEC_TYPE_MPEG_L2:
case CELL_ADEC_TYPE_CELP:
case CELL_ADEC_TYPE_M4AAC:
case CELL_ADEC_TYPE_CELP8:
{
cellAdec->Todo("Unimplemented audio codec type (%d)", type);
Emu.Pause();
break;
default:
return false;
}
default: return false;
}
return true;
@ -554,14 +556,14 @@ int cellAdecClose(u32 handle)
{
cellAdec->Warning("cellAdecClose(handle=%d)", handle);
AudioDecoder* adec;
std::shared_ptr<AudioDecoder> adec;
if (!Emu.GetIdManager().GetIDData(handle, adec))
{
return CELL_ADEC_ERROR_ARG;
}
adec->is_closed = true;
adec->job.Push(AdecTask(adecClose), &sq_no_wait);
adec->job.try_push(AdecTask(adecClose));
while (!adec->is_finished)
{
@ -570,7 +572,7 @@ int cellAdecClose(u32 handle)
cellAdec->Warning("cellAdecClose(%d) aborted", handle);
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());
@ -582,7 +584,7 @@ int cellAdecStartSeq(u32 handle, u32 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))
{
return CELL_ADEC_ERROR_ARG;
@ -592,7 +594,10 @@ int cellAdecStartSeq(u32 handle, u32 param_addr)
switch (adec->type)
{
case CELL_ADEC_TYPE_ATRACX:
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);
@ -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);
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:
{
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;
}
@ -624,13 +636,13 @@ int cellAdecEndSeq(u32 handle)
{
cellAdec->Warning("cellAdecEndSeq(handle=%d)", handle);
AudioDecoder* adec;
std::shared_ptr<AudioDecoder> adec;
if (!Emu.GetIdManager().GetIDData(handle, adec))
{
return CELL_ADEC_ERROR_ARG;
}
adec->job.Push(AdecTask(adecEndSeq), &adec->is_closed);
adec->job.push(AdecTask(adecEndSeq), &adec->is_closed);
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());
AudioDecoder* adec;
std::shared_ptr<AudioDecoder> adec;
if (!Emu.GetIdManager().GetIDData(handle, adec))
{
return CELL_ADEC_ERROR_ARG;
@ -652,7 +664,7 @@ int cellAdecDecodeAu(u32 handle, vm::ptr<CellAdecAuInfo> auInfo)
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);
adec->job.Push(task, &adec->is_closed);
adec->job.push(task, &adec->is_closed);
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());
AudioDecoder* adec;
std::shared_ptr<AudioDecoder> adec;
if (!Emu.GetIdManager().GetIDData(handle, adec))
{
return CELL_ADEC_ERROR_ARG;
}
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
return CELL_ADEC_ERROR_EMPTY;
@ -678,7 +690,7 @@ int cellAdecGetPcm(u32 handle, vm::ptr<float> outBuffer)
if (outBuffer)
{
// 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];
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];
}
}
else if (frame->channels == 2)
else if (frame->format == AV_SAMPLE_FMT_FLTP && frame->channels == 2)
{
float* in_f[2];
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];
}
}
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
{
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();
}
}
@ -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());
AudioDecoder* adec;
std::shared_ptr<AudioDecoder> adec;
if (!Emu.GetIdManager().GetIDData(handle, adec))
{
return CELL_ADEC_ERROR_ARG;
}
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
return CELL_ADEC_ERROR_EMPTY;
@ -747,21 +820,40 @@ int cellAdecGetPcmItem(u32 handle, vm::ptr<u32> pcmItem_ptr)
pcm->auInfo.startAddr = af.auAddr;
pcm->auInfo.userData = af.userdata;
auto atx = vm::ptr<CellAdecAtracXInfo>::make(pcm.addr() + sizeof(CellAdecPcmItem));
atx->samplingFreq = frame->sample_rate;
atx->nbytes = frame->nb_samples * sizeof(float);
if (frame->channels == 1)
if (adecIsAtracX(adec->type))
{
atx->channelConfigIndex = 1;
auto atx = vm::ptr<CellAdecAtracXInfo>::make(pcm.addr() + sizeof(CellAdecPcmItem));
atx->samplingFreq = frame->sample_rate;
atx->nbytes = frame->nb_samples * sizeof(float);
if (frame->channels == 1)
{
atx->channelConfigIndex = 1;
}
else if (frame->channels == 2)
{
atx->channelConfigIndex = 2;
}
else if (frame->channels == 6)
{
atx->channelConfigIndex = 6;
}
else if (frame->channels == 8)
{
atx->channelConfigIndex = 7;
}
else
{
cellAdec->Error("cellAdecGetPcmItem(): unsupported channel count (%d)", frame->channels);
Emu.Pause();
}
}
else if (frame->channels == 2)
else if (adec->type == CELL_ADEC_TYPE_MP3)
{
atx->channelConfigIndex = 2;
}
else
{
cellAdec->Error("cellAdecGetPcmItem(): unsupported channel count (%d)", frame->channels);
Emu.Pause();
auto mp3 = vm::ptr<CellAdecMP3Info>::make(pcm.addr() + sizeof(CellAdecPcmItem));
// TODO
memset(mp3.get_ptr(), 0, sizeof(CellAdecMP3Info));
}
*pcmItem_ptr = pcm.addr();

View File

@ -1,7 +1,5 @@
#pragma once
#include "Utilities/SQueue.h"
// Error Codes
enum
{
@ -284,6 +282,14 @@ enum AudioCodecType
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
enum CellAdecChannel
{
@ -1093,13 +1099,15 @@ static_assert(sizeof(OMAHeader) == 96, "Wrong OMAHeader size");
class AudioDecoder
{
public:
SQueue<AdecTask> job;
squeue_t<AdecTask> job;
u32 id;
volatile bool is_closed;
volatile bool is_finished;
bool just_started;
bool just_finished;
AVCodec* codec;
AVInputFormat* input_format;
AVCodecContext* ctx;
AVFormatContext* fmt;
u8* io_buf;
@ -1118,7 +1126,7 @@ public:
} reader;
SQueue<AdecFrame> frames;
squeue_t<AdecFrame> frames;
const AudioCodecType type;
const u32 memAddr;
@ -1130,7 +1138,8 @@ public:
AdecTask task;
u64 last_pts, first_pts;
u32 channels;
u32 ch_out;
u32 ch_cfg;
u32 frame_size;
u32 sample_rate;
bool use_ats_headers;

View File

@ -2,11 +2,13 @@
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "Emu/SysCalls/Modules.h"
#include "Emu/Memory/atomic_type.h"
#include "rpcs3/Ini.h"
#include "Utilities/SQueue.h"
#include "Emu/Event.h"
#include "Emu/SysCalls/lv2/sleep_queue_type.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/AudioDumper.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] {} );
}
SQueue<s16*, 31> queue;
queue.Clear();
SQueue<float*, 31> queue_float;
queue_float.Clear();
squeue_t<s16*, 31> queue;
squeue_t<float*, 31> queue_float;
std::vector<u64> keys;
@ -105,9 +104,9 @@ int cellAudioInit()
float* oal_buffer_float = nullptr;
if (g_is_u16)
queue.Pop(oal_buffer, nullptr);
queue.pop(oal_buffer);
else
queue_float.Pop(oal_buffer_float, nullptr);
queue_float.pop(oal_buffer_float);
if (g_is_u16)
{
@ -370,9 +369,9 @@ int cellAudioInit()
if(m_audio_out)
{
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;
@ -438,8 +437,8 @@ int cellAudioInit()
}
cellAudio->Notice("Audio thread ended");
abort:
queue.Push(nullptr, nullptr);
queue_float.Push(nullptr, nullptr);
queue.push(nullptr);
queue_float.push(nullptr);
if(do_dump)
m_dump.Finalize();
@ -457,7 +456,7 @@ abort:
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;
@ -471,7 +470,7 @@ abort:
cellAudio->Warning("cellAudioInit() aborted");
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;
@ -490,7 +489,7 @@ int cellAudioQuit()
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())
{
cellAudio->Warning("cellAudioQuit(): aborted");
@ -527,6 +526,9 @@ int cellAudioPortOpen(vm::ptr<CellAudioPortParam> audioParam, vm::ptr<u32> portN
port.channel = (u8)audioParam->nChannel;
port.block = (u8)audioParam->nBlock;
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)
{
port.level = audioParam->level;
@ -578,9 +580,9 @@ int cellAudioGetPortConfig(u32 portNum, vm::ptr<CellAudioPortConfig> portConfig)
portConfig->nChannel = port.channel;
portConfig->nBlock = port.block;
portConfig->portSize = port.channel * port.block * 256 * sizeof(float);
portConfig->portAddr = m_config.m_buffer + (128 * 1024 * portNum); // 0x20020000
portConfig->readIndexAddr = m_config.m_indexes + (sizeof(u64) * portNum); // 0x20010010 on ps3
portConfig->portSize = port.size;
portConfig->portAddr = port.addr; // 0x20020000
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",
(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)
{
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;
}
@ -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 ...
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))
{
delete eq;
return CELL_AUDIO_ERROR_EVENT_QUEUE;
}
@ -841,21 +864,117 @@ int cellAudioRemoveNotifyEventQueueEx(u64 key, u32 iFlags)
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;
}
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;
}
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;
}

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());
if (!videoOut == CELL_VIDEO_OUT_PRIMARY)
if (videoOut != CELL_VIDEO_OUT_PRIMARY)
{
return CELL_VIDEO_OUT_ERROR_UNSUPPORTED_VIDEO_OUT;
}
//TODO: Use virtual screen size
#ifdef _WIN32
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
// 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
if (Ini.GS3DTV.GetValue())
@ -55,7 +57,8 @@ void cellAvconfExt_init(Module *pxThis)
{
cellAvconfExt = pxThis;
cellAvconfExt->AddFunc(0x4ec8c141, cellVideoOutConvertCursorColor);
cellAvconfExt->AddFunc(0xfaa275a4, cellVideoOutGetScreenSize);
cellAvconfExt->AddFunc(0xc7020f62, cellVideoOutSetGamma);
REG_FUNC(cellAvconfExt, cellVideoOutConvertCursorColor);
REG_FUNC(cellAvconfExt, cellVideoOutGetScreenSize);
REG_FUNC(cellAvconfExt, cellVideoOutGetGamma);
REG_FUNC(cellAvconfExt, cellVideoOutSetGamma);
}

View File

@ -10,67 +10,112 @@
Module *cellDmux = nullptr;
#define DMUX_ERROR(...) { cellDmux->Error(__VA_ARGS__); Emu.Pause(); return; } // only for demuxer thread
PesHeader::PesHeader(DemuxerStream& stream)
: pts(0xffffffffffffffffull)
, dts(0xffffffffffffffffull)
: pts(CODEC_TS_INVALID)
, dts(CODEC_TS_INVALID)
, size(0)
, has_ts(false)
, is_ok(false)
{
u16 header;
stream.get(header);
stream.get(size);
if (size)
if (!stream.get(header))
{
u8 empty = 0;
u8 v;
while (true)
{
stream.get(v);
if (v != 0xFF) break; // skip padding bytes
empty++;
if (empty == size) return;
};
DMUX_ERROR("PesHeader(): end of stream (header)");
}
if (!stream.get(size))
{
DMUX_ERROR("PesHeader(): end of stream (size)");
}
if (!stream.check(size))
{
DMUX_ERROR("PesHeader(): end of stream (size=%d)", size);
}
if ((v & 0xF0) == 0x20 && (size - empty) >= 5) // pts only
u8 pos = 0;
while (pos++ < size)
{
u8 v;
if (!stream.get(v))
{
has_ts = true;
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);
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
{
has_ts = true;
if ((v & 0xF0) != 0x30 || (size - empty) < 10)
{
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);
cellDmux->Warning("PesHeader(): unknown code (v=0x%x, size=%d, pos=%d)", v, size, pos - 1);
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)
{
}
bool ElementaryStream::is_full(u32 space)
{
if (released < put_count)
{
if (entries.IsFull())
if (entries.is_full())
{
return true;
}
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)
{
@ -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);
if (is_full(size))
{
throw "es::push_au() error: buffer is full";
}
assert(!is_full(size));
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++;
}
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;
if (!entries.Pop(addr, &dmux->is_closed) || !addr)
if (!entries.pop(addr, &dmux->is_closed) || !addr)
{
cellDmux->Error("es::release() error: entries.Pop() failed");
Emu.Pause();
@ -206,7 +248,7 @@ bool ElementaryStream::peek(u32& out_data, bool no_ex, u32& out_spec, bool updat
}
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");
Emu.Pause();
@ -227,7 +269,7 @@ void ElementaryStream::reset()
{
std::lock_guard<std::mutex> lock(m_mutex);
put = memAddr;
entries.Clear();
entries.clear();
put_count = 0;
got_count = 0;
released = 0;
@ -248,17 +290,18 @@ void dmuxQueryEsAttr(u32 info_addr /* may be 0 */, vm::ptr<const CellCodecEsFilt
if (esFilterId->filterIdMajor >= 0xe0)
attr->memSize = 0x500000; // 0x45fa49 from ps3
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,
(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;
@ -271,19 +314,20 @@ u32 dmuxOpen(Demuxer* data)
dmux.dmuxCb->InitRegs();
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);
DemuxerTask task;
DemuxerStream stream = {};
ElementaryStream* esALL[192]; memset(esALL, 0, sizeof(esALL));
ElementaryStream** esAVC = &esALL[0]; // AVC (max 16)
ElementaryStream** esM2V = &esALL[16]; // MPEG-2 (max 16)
ElementaryStream* esALL[96]; memset(esALL, 0, sizeof(esALL));
ElementaryStream** esAVC = &esALL[0]; // AVC (max 16 minus M2V count)
ElementaryStream** esM2V = &esALL[16]; // M2V (max 16 minus AVC count)
ElementaryStream** esDATA = &esALL[32]; // user data (max 16)
ElementaryStream** esATX = &esALL[48]; // ATRAC3+ (max 48)
ElementaryStream** esAC3 = &esALL[96]; // AC3 (max 48)
ElementaryStream** esPCM = &esALL[144]; // LPCM (max 48)
ElementaryStream** esATX = &esALL[48]; // ATRAC3+ (max 16)
ElementaryStream** esAC3 = &esALL[64]; // AC3 (max 16)
ElementaryStream** esPCM = &esALL[80]; // LPCM (max 16)
u32 cb_add = 0;
@ -294,12 +338,11 @@ u32 dmuxOpen(Demuxer* data)
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)
be_t<u32> code;
be_t<u16> len;
u8 ch;
if (!stream.peek(code))
{
@ -310,64 +353,119 @@ u32 dmuxOpen(Demuxer* data)
dmux.cbFunc.call(*dmux.dmuxCb, dmux.id, dmuxMsg, dmux.cbArg);
dmux.is_running = false;
continue;
}
else switch (code.ToLE())
switch (code.ToLE())
{
case PACK_START_CODE:
{
if (!stream.check(14))
{
DMUX_ERROR("End of stream (PACK_START_CODE)");
}
stream.skip(14);
break;
}
break;
case SYSTEM_HEADER_START_CODE:
{
if (!stream.check(18))
{
DMUX_ERROR("End of stream (SYSTEM_HEADER_START_CODE)");
}
stream.skip(18);
break;
}
break;
case PADDING_STREAM:
{
if (!stream.check(6))
{
DMUX_ERROR("End of stream (PADDING_STREAM)");
}
stream.skip(4);
stream.get(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:
{
if (!stream.check(6))
{
DMUX_ERROR("End of stream (PRIVATE_STREAM_2)");
}
stream.skip(4);
stream.get(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:
{
// audio and user data 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.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:
stream.peek(ch); // ???
//stream.skip(4);
//pes.size += 4;
const PesHeader pes(stream);
if (!pes.is_ok)
{
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];
if (es.raw_data.size() > 1024 * 1024)
{
stream = backup;
std::this_thread::sleep_for(std::chrono::milliseconds(1));
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
continue;
}
stream.skip(4);
len -= 4;
if (len < 3 || !stream.check(3))
{
DMUX_ERROR("End of block (ATX, unknown header, len=%d)", len.ToLE());
}
len -= 3;
stream.skip(3);
if (pes.has_ts)
{
@ -375,7 +473,7 @@ u32 dmuxOpen(Demuxer* data)
es.last_pts = pes.pts;
}
es.push(stream, len - pes.size - 3);
es.push(stream, len);
while (true)
{
@ -386,9 +484,7 @@ u32 dmuxOpen(Demuxer* data)
if (data[0] != 0x0f || data[1] != 0xd0)
{
cellDmux->Error("ATX: 0x0fd0 header not found (ats=0x%llx)", ((be_t<u64>*)data)->ToLE());
Emu.Pause();
return;
DMUX_ERROR("ATX: 0x0fd0 header not found (ats=0x%llx)", ((be_t<u64>*)data)->ToLE());
}
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);
//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));
esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_AU_FOUND;
esMsg->supplementalInfo = stream.userdata;
@ -407,38 +505,60 @@ u32 dmuxOpen(Demuxer* data)
}
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 0x1e4: case 0x1e5: case 0x1e6: case 0x1e7:
case 0x1e8: case 0x1e9: case 0x1ea: case 0x1eb:
case 0x1ec: case 0x1ed: case 0x1ee: case 0x1ef:
{
// video AVC
ch = code - 0x1e0;
// video stream (AVC or M2V)
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])
{
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();
if (es.isfull(old_size))
{
stream = backup;
std::this_thread::sleep_for(std::chrono::milliseconds(1));
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
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);
// callback
@ -456,54 +576,35 @@ u32 dmuxOpen(Demuxer* data)
}
// 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;
es.push(stream, size);
}
else
{
stream.skip(4);
stream.get(len);
cellDmux->Notice("Video stream (code=0x%x, len=%d)", code.ToLE(), len.ToLE());
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);
}
break;
case USER_DATA_START_CODE:
{
cellDmux->Error("USER_DATA_START_CODE found");
Emu.Pause();
return;
break;
}
default:
{
if ((code.ToLE() & PACKET_START_CODE_MASK) == PACKET_START_CODE_PREFIX)
{
DMUX_ERROR("Unknown code found (0x%x)", code.ToLE());
}
// search
stream.skip(1);
}
}
continue;
}
// wait for task with yielding (if no default work)
if (!dmux.job.Pop(task, &dmux.is_closed))
// wait for task if no work
if (!dmux.job.pop(task, &dmux.is_closed))
{
break; // Emu is stopped
}
@ -515,7 +616,7 @@ u32 dmuxOpen(Demuxer* data)
if (task.stream.discontinuity)
{
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])
{
@ -527,8 +628,8 @@ u32 dmuxOpen(Demuxer* data)
stream = task.stream;
//LOG_NOTICE(HLE, "*** stream updated(addr=0x%x, size=0x%x, discont=%d, userdata=0x%llx)",
//stream.addr, stream.size, stream.discontinuity, stream.userdata);
break;
}
break;
case dmuxResetStream:
case dmuxResetStreamAndWaitDone:
@ -543,44 +644,55 @@ u32 dmuxOpen(Demuxer* data)
//if (task.type == dmuxResetStreamAndWaitDone)
//{
//}
break;
}
break;
case dmuxEnableEs:
{
ElementaryStream& es = *task.es.es_ptr;
if (es.fidMajor >= 0xe0 &&
es.fidMajor <= 0xef &&
es.fidMinor == 0 &&
es.sup1 == 1 &&
es.sup2 == 0)
// TODO: uncomment when ready to use
if ((es.fidMajor & -0x10) == 0xe0 && es.fidMinor == 0 && es.sup1 == 1 && !es.sup2)
{
esAVC[es.fidMajor - 0xe0] = task.es.es_ptr;
esAVC[es.fidMajor % 16] = task.es.es_ptr;
}
else if (es.fidMajor == 0xbd &&
es.fidMinor == 0 &&
es.sup1 == 0 &&
es.sup2 == 0)
//else if ((es.fidMajor & -0x10) == 0xe0 && es.fidMinor == 0 && !es.sup1 && !es.sup2)
//{
// esM2V[es.fidMajor % 16] = task.es.es_ptr;
//}
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
{
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;
break;
}
break;
case dmuxDisableEs:
{
ElementaryStream& es = *task.es.es_ptr;
if (es.dmux != &dmux)
{
cellDmux->Warning("dmuxDisableEs: invalid elementary stream");
break;
DMUX_ERROR("dmuxDisableEs: invalid elementary stream");
}
for (u32 i = 0; i < 192; i++)
for (u32 i = 0; i < sizeof(esALL) / sizeof(esALL[0]); i++)
{
if (esALL[i] == &es)
{
@ -589,22 +701,22 @@ u32 dmuxOpen(Demuxer* data)
}
es.dmux = nullptr;
Emu.GetIdManager().RemoveID(task.es.es);
break;
}
break;
case dmuxFlushEs:
{
ElementaryStream& es = *task.es.es_ptr;
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)
while (es.isfull(old_size))
{
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);
@ -626,22 +738,23 @@ u32 dmuxOpen(Demuxer* data)
esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_FLUSH_DONE;
esMsg->supplementalInfo = stream.userdata;
es.cbFunc.call(*dmux.dmuxCb, dmux.id, es.id, esMsg, es.cbArg);
break;
}
break;
case dmuxResetEs:
{
task.es.es_ptr->reset();
break;
}
break;
case dmuxClose: break;
case dmuxClose:
{
break;
}
default:
{
cellDmux->Error("Demuxer thread error: unknown task(%d)", task.type);
Emu.Pause();
return;
DMUX_ERROR("Demuxer thread error: unknown task (0x%x)", task.type);
}
}
}
@ -740,14 +853,14 @@ int cellDmuxClose(u32 demuxerHandle)
{
cellDmux->Warning("cellDmuxClose(demuxerHandle=%d)", demuxerHandle);
Demuxer* dmux;
std::shared_ptr<Demuxer> dmux;
if (!Emu.GetIdManager().GetIDData(demuxerHandle, dmux))
{
return CELL_DMUX_ERROR_ARG;
}
dmux->is_closed = true;
dmux->job.Push(DemuxerTask(dmuxClose), &sq_no_wait);
dmux->job.try_push(DemuxerTask(dmuxClose));
while (!dmux->is_finished)
{
@ -757,7 +870,7 @@ int cellDmuxClose(u32 demuxerHandle)
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());
@ -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",
demuxerHandle, streamAddress, streamSize, discontinuity, userData);
Demuxer* dmux;
std::shared_ptr<Demuxer> dmux;
if (!Emu.GetIdManager().GetIDData(demuxerHandle, dmux))
{
return CELL_DMUX_ERROR_ARG;
@ -789,7 +902,7 @@ int cellDmuxSetStream(u32 demuxerHandle, const u32 streamAddress, u32 streamSize
info.discontinuity = discontinuity;
info.userdata = userData;
dmux->job.Push(task, &dmux->is_closed);
dmux->job.push(task, &dmux->is_closed);
return CELL_OK;
}
@ -797,13 +910,13 @@ int cellDmuxResetStream(u32 demuxerHandle)
{
cellDmux->Warning("cellDmuxResetStream(demuxerHandle=%d)", demuxerHandle);
Demuxer* dmux;
std::shared_ptr<Demuxer> dmux;
if (!Emu.GetIdManager().GetIDData(demuxerHandle, dmux))
{
return CELL_DMUX_ERROR_ARG;
}
dmux->job.Push(DemuxerTask(dmuxResetStream), &dmux->is_closed);
dmux->job.push(DemuxerTask(dmuxResetStream), &dmux->is_closed);
return CELL_OK;
}
@ -811,13 +924,13 @@ int cellDmuxResetStreamAndWaitDone(u32 demuxerHandle)
{
cellDmux->Warning("cellDmuxResetStreamAndWaitDone(demuxerHandle=%d)", demuxerHandle);
Demuxer* dmux;
std::shared_ptr<Demuxer> dmux;
if (!Emu.GetIdManager().GetIDData(demuxerHandle, dmux))
{
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
{
if (Emu.IsStopped())
@ -825,7 +938,7 @@ int cellDmuxResetStreamAndWaitDone(u32 demuxerHandle)
cellDmux->Warning("cellDmuxResetStreamAndWaitDone(%d) aborted", demuxerHandle);
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;
}
@ -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(),
esCb.addr(), esSpecificInfo_addr, esHandle.addr());
Demuxer* dmux;
std::shared_ptr<Demuxer> dmux;
if (!Emu.GetIdManager().GetIDData(demuxerHandle, dmux))
{
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
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,
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);
es->id = id;
@ -891,9 +1004,9 @@ int cellDmuxEnableEs(u32 demuxerHandle, vm::ptr<const CellCodecEsFilterId> esFil
DemuxerTask task(dmuxEnableEs);
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;
}
@ -901,7 +1014,7 @@ int cellDmuxDisableEs(u32 esHandle)
{
cellDmux->Warning("cellDmuxDisableEs(esHandle=0x%x)", esHandle);
ElementaryStream* es;
std::shared_ptr<ElementaryStream> es;
if (!Emu.GetIdManager().GetIDData(esHandle, es))
{
return CELL_DMUX_ERROR_ARG;
@ -909,9 +1022,9 @@ int cellDmuxDisableEs(u32 esHandle)
DemuxerTask task(dmuxDisableEs);
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;
}
@ -919,7 +1032,7 @@ int cellDmuxResetEs(u32 esHandle)
{
cellDmux->Log("cellDmuxResetEs(esHandle=0x%x)", esHandle);
ElementaryStream* es;
std::shared_ptr<ElementaryStream> es;
if (!Emu.GetIdManager().GetIDData(esHandle, es))
{
return CELL_DMUX_ERROR_ARG;
@ -927,9 +1040,9 @@ int cellDmuxResetEs(u32 esHandle)
DemuxerTask task(dmuxResetEs);
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;
}
@ -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)",
esHandle, auInfo_ptr.addr(), auSpecificInfo_ptr.addr());
ElementaryStream* es;
std::shared_ptr<ElementaryStream> es;
if (!Emu.GetIdManager().GetIDData(esHandle, es))
{
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)",
esHandle, auInfo_ptr.addr(), auSpecificInfo_ptr.addr());
ElementaryStream* es;
std::shared_ptr<ElementaryStream> es;
if (!Emu.GetIdManager().GetIDData(esHandle, es))
{
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)",
esHandle, auInfoEx_ptr.addr(), auSpecificInfo_ptr.addr());
ElementaryStream* es;
std::shared_ptr<ElementaryStream> es;
if (!Emu.GetIdManager().GetIDData(esHandle, es))
{
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)",
esHandle, auInfoEx_ptr.addr(), auSpecificInfo_ptr.addr());
ElementaryStream* es;
std::shared_ptr<ElementaryStream> es;
if (!Emu.GetIdManager().GetIDData(esHandle, es))
{
return CELL_DMUX_ERROR_ARG;
@ -1029,7 +1142,7 @@ int cellDmuxReleaseAu(u32 esHandle)
{
cellDmux->Log("cellDmuxReleaseAu(esHandle=0x%x)", esHandle);
ElementaryStream* es;
std::shared_ptr<ElementaryStream> es;
if (!Emu.GetIdManager().GetIDData(esHandle, es))
{
return CELL_DMUX_ERROR_ARG;
@ -1046,7 +1159,7 @@ int cellDmuxFlushEs(u32 esHandle)
{
cellDmux->Warning("cellDmuxFlushEs(esHandle=0x%x)", esHandle);
ElementaryStream* es;
std::shared_ptr<ElementaryStream> es;
if (!Emu.GetIdManager().GetIDData(esHandle, es))
{
return CELL_DMUX_ERROR_ARG;
@ -1054,9 +1167,9 @@ int cellDmuxFlushEs(u32 esHandle)
DemuxerTask task(dmuxFlushEs);
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;
}

View File

@ -1,7 +1,5 @@
#pragma once
#include "Utilities/SQueue.h"
// align size or address to 128
#define a128(x) ((x + 127) & (~127))
@ -288,15 +286,8 @@ enum
PACKET_START_CODE_MASK = 0xffffff00,
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,
SYSTEM_HEADER_START_CODE = 0x000001bb,
PROGRAM_STREAM_MAP = 0x000001bc,
PRIVATE_STREAM_1 = 0x000001bd,
PADDING_STREAM = 0x000001be,
PRIVATE_STREAM_2 = 0x000001bf,
@ -336,6 +327,11 @@ struct DemuxerStream
size = size > count ? size - count : 0;
}
bool check(u32 count) const
{
return count <= size;
}
u64 get_ts(u8 c)
{
u8 v[4]; get((u32&)v);
@ -345,12 +341,6 @@ struct DemuxerStream
(((u64)v[1] & 0x7e) << 15) |
(((u64)v[2]) << 7) | ((u64)v[3] >> 1);
}
u64 get_ts()
{
u8 v; get(v);
return get_ts(v);
}
};
struct PesHeader
@ -359,6 +349,7 @@ struct PesHeader
u64 dts;
u8 size;
bool has_ts;
bool is_ok;
PesHeader(DemuxerStream& stream);
};
@ -407,7 +398,7 @@ struct DemuxerTask
class Demuxer
{
public:
SQueue<DemuxerTask, 32> job;
squeue_t<DemuxerTask, 32> job;
const u32 memAddr;
const u32 memSize;
const vm::ptr<CellDmuxCbMsg> cbFunc;
@ -436,7 +427,7 @@ class ElementaryStream
{
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 got_count; // number of AU obtained by GetAu(Ex)
u32 released; // number of AU released
@ -446,6 +437,8 @@ class ElementaryStream
bool is_full(u32 space);
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;
u32 id;
const u32 memAddr;
@ -465,27 +458,6 @@ public:
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);
void push_au(u32 size, u64 dts, u64 pts, u64 userdata, bool rap, u32 specific);

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)
{
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());
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());
// TODO: ?
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)
{
cellFont->Log("cellFontGetCharGlyphMetrics(font_addr=0x%x, code=0x%x, metrics_addr=0x%x",
font.addr(), code, metrics.addr());
cellFont->Log("cellFontGetCharGlyphMetrics(font_addr=0x%x, code=0x%x, metrics_addr=0x%x)", font.addr(), code, metrics.addr());
int x0, y0, x1, y1;
int advanceWidth, leftSideBearing;

View File

@ -92,7 +92,7 @@ vm::ptr<CellGcmReportData> cellGcmGetReportDataAddressLocation(u32 index, u32 lo
}
if (location == CELL_GCM_LOCATION_MAIN) {
if (index >= 1024*1024) {
if (index >= 1024 * 1024) {
cellGcmSys->Error("cellGcmGetReportDataAddressLocation: Wrong main index (%d)", index);
return vm::ptr<CellGcmReportData>::make(0);
}
@ -195,7 +195,7 @@ u64 cellGcmGetTimeStampLocation(u32 index, u32 location)
}
if (location == CELL_GCM_LOCATION_MAIN) {
if (index >= 1024*1024) {
if (index >= 1024 * 1024) {
cellGcmSys->Error("cellGcmGetTimeStampLocation: Wrong main index (%d)", index);
return 0;
}
@ -300,7 +300,7 @@ u32 cellGcmGetTiledPitchSize(u32 size)
{
cellGcmSys->Log("cellGcmGetTiledPitchSize(size=%d)", size);
for (size_t i=0; i < sizeof(tiled_pitches)/sizeof(tiled_pitches[0]) - 1; i++) {
for (size_t i=0; i < sizeof(tiled_pitches) / sizeof(tiled_pitches[0]) - 1; i++) {
if (tiled_pitches[i] < size && size <= tiled_pitches[i+1]) {
return tiled_pitches[i+1];
}
@ -369,7 +369,7 @@ s32 _cellGcmInitBody(vm::ptr<CellGcmContextData> context, u32 cmdSize, u32 ioSiz
u32 ctx_begin = ioAddress/* + 0x1000*/;
u32 ctx_size = 0x6ffc;
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.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());
// Address not on main memory or local memory
if (!address || address >= 0xD0000000) {
cellGcmSys->Error("cellGcmAddressToOffset(address=0x%x,offset_addr=0x%x)", address, offset.addr());
if (address >= 0xD0000000) {
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);
GSLockCurrent gslock(GS_LOCK_WAIT_FLUSH);
if (1)
{
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());
if (res != 0)
{
GSLockCurrent gslock(GS_LOCK_WAIT_FLUSH);
}
memmove(vm::get_ptr<void>(context->begin), vm::get_ptr<void>(context->current - res), res);
context->current = context->begin + res;

View File

@ -4,7 +4,7 @@
#include "stblib/stb_image.h"
#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"
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)",
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->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)",
mainHandle, subHandle, info.addr());
CellGifDecSubHandle* subHandle_data;
std::shared_ptr<CellGifDecSubHandle> subHandle_data;
if(!cellGifDec->CheckId(subHandle, subHandle_data))
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)",
mainHandle, subHandle, inParam.addr(), outParam.addr());
CellGifDecSubHandle* subHandle_data;
std::shared_ptr<CellGifDecSubHandle> subHandle_data;
if(!cellGifDec->CheckId(subHandle, subHandle_data))
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;
CellGifDecSubHandle* subHandle_data;
std::shared_ptr<CellGifDecSubHandle> subHandle_data;
if(!cellGifDec->CheckId(subHandle, subHandle_data))
return CELL_GIFDEC_ERROR_FATAL;
@ -259,7 +259,7 @@ int cellGifDecClose(u32 mainHandle, u32 subHandle)
cellGifDec->Warning("cellGifDecClose(mainHandle=0x%x, subHandle=0x%x)",
mainHandle, subHandle);
CellGifDecSubHandle* subHandle_data;
std::shared_ptr<CellGifDecSubHandle> subHandle_data;
if(!cellGifDec->CheckId(subHandle, subHandle_data))
return CELL_GIFDEC_ERROR_FATAL;

View File

@ -3,7 +3,7 @@
#include "Emu/SysCalls/Modules.h"
#include "stblib/stb_image.h"
#include "Emu/SysCalls/lv2/lv2Fs.h"
#include "Emu/SysCalls/lv2/cellFs.h"
#include "cellJpgDec.h"
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)",
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->src = *src;
@ -68,7 +68,7 @@ int cellJpgDecClose(u32 mainHandle, u32 subHandle)
cellJpgDec->Warning("cellJpgDecOpen(mainHandle=0x%x, subHandle=0x%x)",
mainHandle, subHandle);
CellJpgDecSubHandle* subHandle_data;
std::shared_ptr<CellJpgDecSubHandle> subHandle_data;
if(!cellJpgDec->CheckId(subHandle, subHandle_data))
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());
CellJpgDecSubHandle* subHandle_data;
std::shared_ptr<CellJpgDecSubHandle> subHandle_data;
if(!cellJpgDec->CheckId(subHandle, subHandle_data))
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());
dataOutInfo->status = CELL_JPGDEC_DEC_STATUS_STOP;
CellJpgDecSubHandle* subHandle_data;
std::shared_ptr<CellJpgDecSubHandle> subHandle_data;
if(!cellJpgDec->CheckId(subHandle, subHandle_data))
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)",
mainHandle, subHandle, inParam.addr(), outParam.addr());
CellJpgDecSubHandle* subHandle_data;
std::shared_ptr<CellJpgDecSubHandle> subHandle_data;
if(!cellJpgDec->CheckId(subHandle, subHandle_data))
return CELL_JPGDEC_ERROR_FATAL;

View File

@ -32,29 +32,13 @@ MsgDialogProgressBarSetMsgCb MsgDialogProgressBarSetMsg = nullptr;
MsgDialogProgressBarResetCb MsgDialogProgressBarReset = nullptr;
MsgDialogProgressBarIncCb MsgDialogProgressBarInc = nullptr;
void SetMsgDialogCreateCallback(MsgDialogCreateCb cb)
void SetMsgDialogCallbacks(MsgDialogCreateCb ccb, MsgDialogDestroyCb dcb, MsgDialogProgressBarSetMsgCb pbscb, MsgDialogProgressBarResetCb pbrcb, MsgDialogProgressBarIncCb pbicb)
{
MsgDialogCreate = cb;
}
void SetMsgDialogDestroyCallback(MsgDialogDestroyCb cb)
{
MsgDialogDestroy = cb;
}
void SetMsgDialogProgressBarSetMsgCallback(MsgDialogProgressBarSetMsgCb cb)
{
MsgDialogProgressBarSetMsg = cb;
}
void SetMsgDialogProgressBarResetCallback(MsgDialogProgressBarResetCb cb)
{
MsgDialogProgressBarReset = cb;
}
void SetMsgDialogProgressBarIncCallback(MsgDialogProgressBarIncCb cb)
{
MsgDialogProgressBarInc = cb;
MsgDialogCreate = ccb;
MsgDialogDestroy = dcb;
MsgDialogProgressBarSetMsg = pbscb;
MsgDialogProgressBarReset = pbrcb;
MsgDialogProgressBarInc = pbicb;
}
void MsgDialogClose()
@ -63,13 +47,64 @@ void MsgDialogClose()
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)",
type, msgString.addr(), callback.addr(), userData, extParam);
//type |= CELL_MSGDIALOG_TYPE_PROGRESSBAR_SINGLE | CELL_MSGDIALOG_TYPE_BG_INVISIBLE;
//type |= CELL_MSGDIALOG_TYPE_BUTTON_TYPE_YESNO | CELL_MSGDIALOG_TYPE_DEFAULT_CURSOR_NO;
if (!msgString || strlen(msgString.get_ptr()) >= 0x200 || type & -0x33f8)
{
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;
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_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();
@ -121,7 +156,7 @@ int cellMsgDialogOpen2(u32 type, vm::ptr<const char> msgString, vm::ptr<CellMsgD
cellSysutil->Warning("MsgDialog thread aborted");
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)
@ -131,7 +166,7 @@ int cellMsgDialogOpen2(u32 type, vm::ptr<const char> msgString, vm::ptr<CellMsgD
g_msg_dialog_state = msgDialogAbort;
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))
@ -156,7 +191,7 @@ int cellMsgDialogOpen2(u32 type, vm::ptr<const char> msgString, vm::ptr<CellMsgD
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)",
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 0x80010008: errorMessage = "Resource deadlock is avoided."; break;
case 0x80010009: errorMessage = "Operation not permitted."; break;
case 0x8001000A: errorMessage = "The device or resource is bus."; break;
case 0x8001000B: errorMessage = "The operation is timed ou."; break;
case 0x8001000C: errorMessage = "The operation is aborte."; break;
case 0x8001000A: errorMessage = "The device or resource is busy."; break;
case 0x8001000B: errorMessage = "The operation is timed out."; break;
case 0x8001000C: errorMessage = "The operation is aborted."; break;
case 0x8001000D: errorMessage = "Invalid memory access."; break;
case 0x8001000F: errorMessage = "State of the target thread is invalid."; break;
case 0x80010010: errorMessage = "Alignment is invalid."; break;
case 0x80010011: errorMessage = "Shortage of the kernel resources."; 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 0x80010015: errorMessage = "Port is already 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;
}
int cellMsgDialogClose(float delay)
s32 cellMsgDialogClose(float delay)
{
cellSysutil->Warning("cellMsgDialogClose(delay=%f)", delay);
@ -277,7 +312,7 @@ int cellMsgDialogClose(float delay)
return CELL_OK;
}
int cellMsgDialogAbort()
s32 cellMsgDialogAbort()
{
cellSysutil->Warning("cellMsgDialogAbort()");
@ -298,7 +333,7 @@ int cellMsgDialogAbort()
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'])",
progressBarIndex, msgString.addr(), msgString.get_ptr());
@ -322,7 +357,7 @@ int cellMsgDialogProgressBarSetMsg(u32 progressBarIndex, vm::ptr<const char> msg
return CELL_OK;
}
int cellMsgDialogProgressBarReset(u32 progressBarIndex)
s32 cellMsgDialogProgressBarReset(u32 progressBarIndex)
{
cellSysutil->Warning("cellMsgDialogProgressBarReset(progressBarIndex=%d)", progressBarIndex);
@ -343,7 +378,7 @@ int cellMsgDialogProgressBarReset(u32 progressBarIndex)
return CELL_OK;
}
int cellMsgDialogProgressBarInc(u32 progressBarIndex, u32 delta)
s32 cellMsgDialogProgressBarInc(u32 progressBarIndex, u32 delta)
{
cellSysutil->Warning("cellMsgDialogProgressBarInc(progressBarIndex=%d, delta=%d)", progressBarIndex, delta);

View File

@ -2,7 +2,7 @@
enum
{
CELL_MSGDIALOG_ERROR_PARAM = 0x8002b301,
CELL_MSGDIALOG_ERROR_PARAM = 0x8002b301,
CELL_MSGDIALOG_ERROR_DIALOG_NOT_OPENED = 0x8002b302,
};
@ -18,28 +18,28 @@ enum CellMsgDialogType
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_NORMAL = 1 << 0,
};
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_ON = 1 << 1,
};
enum
{
CELL_MSGDIALOG_TYPE_BG = 1 << 2,
CELL_MSGDIALOG_TYPE_BG = 0x4,
CELL_MSGDIALOG_TYPE_BG_VISIBLE = 0 << 2,
CELL_MSGDIALOG_TYPE_BG_INVISIBLE = 1 << 2,
};
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_YESNO = 1 << 4,
CELL_MSGDIALOG_TYPE_BUTTON_TYPE_OK = 2 << 4,
@ -47,14 +47,14 @@ 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_ON = 1 << 7,
};
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_YES = 0 << 8,
CELL_MSGDIALOG_TYPE_DEFAULT_CURSOR_NO = 1 << 8,
@ -63,7 +63,7 @@ enum
enum
{
CELL_MSGDIALOG_TYPE_PROGRESSBAR = 3 << 12,
CELL_MSGDIALOG_TYPE_PROGRESSBAR = 0x3000,
CELL_MSGDIALOG_TYPE_PROGRESSBAR_NONE = 0 << 12,
CELL_MSGDIALOG_TYPE_PROGRESSBAR_SINGLE = 1 << 12,
CELL_MSGDIALOG_TYPE_PROGRESSBAR_DOUBLE = 2 << 12,
@ -81,14 +81,14 @@ enum
typedef void(*CellMsgDialogCallback)(s32 buttonType, u32 userData);
int 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 cellMsgDialogOpen2(u32 type, vm::ptr<const char> msgString, 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);
int cellMsgDialogProgressBarReset(u32 progressBarIndex);
int cellMsgDialogProgressBarInc(u32 progressBarIndex, u32 delta);
int cellMsgDialogClose(float delay);
int cellMsgDialogAbort();
s32 cellMsgDialogProgressBarSetMsg(u32 progressBarIndex, vm::ptr<const char> msgString);
s32 cellMsgDialogProgressBarReset(u32 progressBarIndex);
s32 cellMsgDialogProgressBarInc(u32 progressBarIndex, u32 delta);
s32 cellMsgDialogClose(float delay);
s32 cellMsgDialogAbort();
typedef void(*MsgDialogCreateCb)(u32 type, const char* msg, u64& status);
typedef void(*MsgDialogDestroyCb)();
@ -96,10 +96,5 @@ typedef void(*MsgDialogProgressBarSetMsgCb)(u32 progressBarIndex, const char* ms
typedef void(*MsgDialogProgressBarResetCb)(u32 progressBarIndex);
typedef void(*MsgDialogProgressBarIncCb)(u32 progressBarIndex, u32 delta);
void SetMsgDialogCreateCallback(MsgDialogCreateCb cb);
void SetMsgDialogDestroyCallback(MsgDialogDestroyCb cb);
void SetMsgDialogProgressBarSetMsgCallback(MsgDialogProgressBarSetMsgCb cb);
void SetMsgDialogProgressBarResetCallback(MsgDialogProgressBarResetCb cb);
void SetMsgDialogProgressBarIncCallback(MsgDialogProgressBarIncCb cb);
void SetMsgDialogCallbacks(MsgDialogCreateCb ccb, MsgDialogDestroyCb dcb, MsgDialogProgressBarSetMsgCb pbscb, MsgDialogProgressBarResetCb pbrcb, MsgDialogProgressBarIncCb pbicb);
void MsgDialogClose();

View File

@ -54,16 +54,39 @@ int cellPadClearBuf(u32 port_no)
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)
{
sys_io->Log("cellPadGetData(port_no=%d, data_addr=0x%x)", port_no, data.addr());
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();
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
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];
@ -409,6 +432,7 @@ void cellPad_init()
sys_io->AddFunc(0xf65544ee, cellPadSetActDirect);
sys_io->AddFunc(0x3aaad464, cellPadGetInfo);
sys_io->AddFunc(0xa703a51d, cellPadGetInfo2);
sys_io->AddFunc(0x4cc9b68d, cellPadPeriphGetInfo);
sys_io->AddFunc(0x578e3c98, cellPadSetPortSetting);
sys_io->AddFunc(0x0e2dfaad, cellPadInfoPressMode);
sys_io->AddFunc(0x78200559, cellPadInfoSensorMode);

View File

@ -14,6 +14,17 @@ enum CELL_PAD_ERROR_CODE
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
{
be_t<s32> len;
@ -41,6 +52,19 @@ struct CellPadInfo2
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
{
be_t<u32> info[CELL_PAD_MAX_CAPABILITY_INFO];

View File

@ -1,157 +1,203 @@
#include "stdafx.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "Emu/SysCalls/Modules.h"
#include "cellPamf.h"
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
pEsFilterId->filterIdMajor = 0;
pEsFilterId->filterIdMinor = 0;
pEsFilterId->supplementalInfo1 = 0;
pEsFilterId->supplementalInfo2 = 0;
// convert type and ch to EsFilterId
assert(ch < 16);
pEsFilterId.supplementalInfo1 = type == CELL_PAMF_STREAM_TYPE_AVC;
pEsFilterId.supplementalInfo2 = 0;
switch (type)
{
case CELL_PAMF_STREAM_TYPE_AVC:
{
if (ch < 16)
{
pEsFilterId->filterIdMajor = 0xe0 + ch;
pEsFilterId->filterIdMinor = 0;
pEsFilterId->supplementalInfo1 = 0x01;
pEsFilterId->supplementalInfo2 = 0;
}
else
cellPamf->Error("pamfStreamTypeToEsFilterId: invalid CELL_PAMF_STREAM_TYPE_AVC channel (ch=%d)", ch);
}
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);
{
// code = 0x1b
pEsFilterId.filterIdMajor = 0xe0 | ch;
pEsFilterId.filterIdMinor = 0;
break;
}
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;
}
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:
{
cellPamf->Error("pamfStreamTypeToEsFilterId(): unknown type (%d, ch=%d)", type, ch);
Emu.Pause();
return CELL_PAMF_ERROR_INVALID_ARG;
}
}
return CELL_OK;
}
u8 pamfGetStreamType(vm::ptr<CellPamfReader> pSelf, u8 stream)
u8 pamfGetStreamType(vm::ptr<CellPamfReader> pSelf, u32 stream)
{
//TODO: get stream type correctly
switch (pSelf->pAddr->stream_headers[stream].type)
// TODO: get stream type correctly
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 0x02: return CELL_PAMF_STREAM_TYPE_M2V;
case 0xdc: return CELL_PAMF_STREAM_TYPE_ATRAC3PLUS;
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;
default:
cellPamf->Todo("pamfGetStreamType: unsupported stream type found(0x%x)", pSelf->pAddr->stream_headers[stream].type);
return 0;
}
cellPamf->Todo("pamfGetStreamType(): unsupported stream type found(0x%x)", header.type);
Emu.Pause();
return 0xff;
}
u8 pamfGetStreamChannel(vm::ptr<CellPamfReader> pSelf, u8 stream)
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:
if ((pSelf->pAddr->stream_headers[stream].stream_id >= 0xe0) && (pSelf->pAddr->stream_headers[stream].stream_id <= 0xef))
{
return pSelf->pAddr->stream_headers[stream].stream_id - 0xe0;
}
else
{
cellPamf->Error("pamfGetStreamChannel: stream type 0x%x got invalid stream id=0x%x",
pSelf->pAddr->stream_headers[stream].type, pSelf->pAddr->stream_headers[stream].stream_id);
return 0;
}
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:
cellPamf->Todo("pamfGetStreamChannel: CELL_PAMF_STREAM_TYPE_USER_DATA");
return 0;
default:
cellPamf->Todo("pamfGetStreamType: unsupported stream type found(0x%x)", pSelf->pAddr->stream_headers[stream].type);
return 0;
case 0x1b: // AVC
case 0x02: // M2V
{
assert((header.fid_major & 0xf0) == 0xe0 && header.fid_minor == 0);
return header.fid_major % 16;
}
case 0xdc: // ATRAC3PLUS
{
assert(header.fid_major == 0xbd && (header.fid_minor & 0xf0) == 0);
return header.fid_minor % 16;
}
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 0xdd:
{
assert(header.fid_major == 0xbd && (header.fid_minor & 0xf0) == 0x20);
return header.fid_minor % 16;
}
}
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());
//if ((u32)pAddr->magic != 0x464d4150)
//return CELL_PAMF_ERROR_UNKNOWN_TYPE;
//if ((u32)pAddr->magic != 0x464d4150) return CELL_PAMF_ERROR_UNKNOWN_TYPE;
const u64 offset = (u64)pAddr->data_offset << 11;
*pSize = offset;
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());
//if ((u32)pAddr->magic != 0x464d4150)
//return CELL_PAMF_ERROR_UNKNOWN_TYPE;
//if ((u32)pAddr->magic != 0x464d4150) return CELL_PAMF_ERROR_UNKNOWN_TYPE;
const u64 offset = (u64)pAddr->data_offset << 11;
*pSize = offset;
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());
//if ((u32)pAddr->magic != 0x464d4150)
//return CELL_PAMF_ERROR_UNKNOWN_TYPE;
//if ((u32)pAddr->magic != 0x464d4150) return CELL_PAMF_ERROR_UNKNOWN_TYPE;
const u64 offset = (u64)pAddr->data_offset << 11;
*pOffset = offset;
@ -160,14 +206,15 @@ int cellPamfGetStreamOffsetAndSize(vm::ptr<PamfHeader> pAddr, u64 fileSize, vm::
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;
}
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);
@ -175,7 +222,7 @@ int cellPamfReaderInitialize(vm::ptr<CellPamfReader> pSelf, vm::ptr<const PamfHe
{
pSelf->fileSize = fileSize;
}
else //if fileSize is unknown
else // if fileSize is unknown
{
pSelf->fileSize = ((u64)pAddr->data_offset << 11) + ((u64)pAddr->data_size << 11);
}
@ -183,70 +230,59 @@ int cellPamfReaderInitialize(vm::ptr<CellPamfReader> pSelf, vm::ptr<const PamfHe
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;
}
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());
if (!pSelf->pAddr) {
return CELL_PAMF_ERROR_INVALID_PAMF;
}
// always returns CELL_OK
pTimeStamp->upper = (u32)(u16)pSelf->pAddr->start_pts_high;
pTimeStamp->lower = pSelf->pAddr->start_pts_low;
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());
if (!pSelf->pAddr) {
return CELL_PAMF_ERROR_INVALID_PAMF;
}
// always returns CELL_OK
pTimeStamp->upper = (u32)(u16)pSelf->pAddr->end_pts_high;
pTimeStamp->lower = pSelf->pAddr->end_pts_low;
return CELL_OK;
}
int cellPamfReaderGetMuxRateBound(vm::ptr<CellPamfReader> pSelf)
u32 cellPamfReaderGetMuxRateBound(vm::ptr<CellPamfReader> pSelf)
{
cellPamf->Warning("cellPamfReaderGetMuxRateBound(pSelf=0x%x)", pSelf.addr());
if (!pSelf->pAddr) {
return CELL_PAMF_ERROR_INVALID_PAMF;
}
// cannot return error code
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());
if (!pSelf->pAddr) {
return CELL_PAMF_ERROR_INVALID_PAMF;
}
// cannot return error code
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);
if (!pSelf->pAddr) {
return CELL_PAMF_ERROR_INVALID_PAMF;
}
// cannot return error code
int counts[6] = {0, 0, 0, 0, 0, 0};
u8 counts[256] = {};
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_AC3:
case CELL_PAMF_STREAM_TYPE_USER_DATA:
{
return counts[streamType];
case CELL_PAMF_STREAM_TYPE_VIDEO:
return counts[CELL_PAMF_STREAM_TYPE_AVC] + counts[CELL_PAMF_STREAM_TYPE_M2V];
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];
default:
return 0;
}
case CELL_PAMF_STREAM_TYPE_VIDEO:
{
return counts[CELL_PAMF_STREAM_TYPE_AVC] + counts[CELL_PAMF_STREAM_TYPE_M2V];
}
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];
}
}
cellPamf->Todo("cellPamfReaderGetNumberOfSpecificStreams(): unsupported stream type (0x%x)", streamType);
Emu.Pause();
return 0;
}
int cellPamfReaderSetStreamWithIndex(vm::ptr<CellPamfReader> pSelf, u8 streamIndex)
s32 cellPamfReaderSetStreamWithIndex(vm::ptr<CellPamfReader> pSelf, u8 streamIndex)
{
cellPamf->Warning("cellPamfReaderSetStreamWithIndex(pSelf=0x%x, streamIndex=%d)", pSelf.addr(), streamIndex);
if (!pSelf->pAddr) {
return CELL_PAMF_ERROR_INVALID_PAMF;
}
if (streamIndex < pSelf->pAddr->stream_count)
if (streamIndex >= pSelf->pAddr->stream_count)
{
pSelf->stream = streamIndex;
return CELL_OK;
return CELL_PAMF_ERROR_INVALID_ARG;
}
cellPamf->Error("cellPamfReaderSetStreamWithIndex: CELL_PAMF_ERROR_INVALID_ARG");
return CELL_PAMF_ERROR_INVALID_ARG;
pSelf->stream = streamIndex;
return CELL_OK;
}
int cellPamfReaderSetStreamWithTypeAndChannel(vm::ptr<CellPamfReader> pSelf, u8 streamType, u8 ch)
s32 cellPamfReaderSetStreamWithTypeAndChannel(vm::ptr<CellPamfReader> pSelf, u8 streamType, u8 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)
// it probably doesn't support "any audio" or "any video" argument
if (streamType > 5 || ch >= 16)
{
cellPamf->Error("cellPamfReaderSetStreamWithTypeAndChannel: invalid stream type(%d)", streamType);
//it probably doesn't support "any audio" or "any video" argument
cellPamf->Error("cellPamfReaderSetStreamWithTypeAndChannel(): invalid arguments (streamType=%d, ch=%d)", streamType, ch);
Emu.Pause();
return CELL_PAMF_ERROR_INVALID_ARG;
}
@ -319,14 +357,10 @@ int cellPamfReaderSetStreamWithTypeAndChannel(vm::ptr<CellPamfReader> pSelf, u8
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);
if (!pSelf->pAddr) {
return CELL_PAMF_ERROR_INVALID_PAMF;
}
u32 found = 0;
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)
{
case CELL_PAMF_STREAM_TYPE_VIDEO:
{
if (type == CELL_PAMF_STREAM_TYPE_AVC || type == CELL_PAMF_STREAM_TYPE_M2V)
{
found++;
}
break;
}
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)
{
found++;
}
break;
}
default:
{
if (streamType > 5)
{
return CELL_PAMF_ERROR_INVALID_ARG;
}
}
}
if (found > streamIndex)
{
@ -368,199 +410,328 @@ int cellPamfReaderSetStreamWithTypeAndIndex(vm::ptr<CellPamfReader> pSelf, u8 st
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());
return pamfStreamTypeToEsFilterId(type, ch, pEsFilterId);
if (!pEsFilterId)
{
return CELL_PAMF_ERROR_INVALID_ARG;
}
return pamfStreamTypeToEsFilterId(type, ch, *pEsFilterId);
}
int cellPamfReaderGetStreamIndex(vm::ptr<CellPamfReader> pSelf)
s32 cellPamfReaderGetStreamIndex(vm::ptr<CellPamfReader> pSelf)
{
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;
}
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",
pSelf.addr(), pSelf->stream, pType.addr(), pCh.addr());
// unclear
*pType = pamfGetStreamType(pSelf, pSelf->stream);
*pCh = pamfGetStreamChannel(pSelf, pSelf->stream);
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());
return pamfStreamTypeToEsFilterId(pamfGetStreamType(pSelf, pSelf->stream),
pamfGetStreamChannel(pSelf, pSelf->stream), pEsFilterId);
// always returns CELL_OK
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);
if (!pSelf->pAddr) {
return CELL_PAMF_ERROR_INVALID_PAMF;
}
assert((u32)pSelf->stream < (u32)pSelf->pAddr->stream_count);
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 (pamfGetStreamType(pSelf, pSelf->stream))
switch (type)
{
case CELL_PAMF_STREAM_TYPE_AVC:
{
if (size < sizeof(CellPamfAvcInfo))
{
auto pInfo = vm::ptr<CellPamfAvcInfo>::make(pInfo_addr);
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;
}
pInfo->profileIdc = pAVC->profileIdc;
pInfo->levelIdc = pAVC->levelIdc;
pInfo->frameMbsOnlyFlag = 1; //fake
pInfo->frameRateInfo = (pAVC->unk0 & 0x7) - 1;
pInfo->aspectRatioIdc = 1; //fake
pInfo->horizontalSize = 16 * (u16)pAVC->horizontalSize;
pInfo->verticalSize = 16 * (u16)pAVC->verticalSize;
pInfo->videoSignalInfoFlag = 1; //fake
pInfo->colourPrimaries = 1; //fake
pInfo->transferCharacteristics = 1; //fake
pInfo->matrixCoefficients = 1; //fake
//pInfo->deblockingFilterFlag = 1; //???
cellPamf->Warning("cellPamfReaderGetStreamInfo: CELL_PAMF_STREAM_TYPE_AVC");
}
break;
case CELL_PAMF_STREAM_TYPE_M2V:
{
//TODO
cellPamf->Error("TODO: cellPamfReaderGetStreamInfo: CELL_PAMF_STREAM_TYPE_M2V");
}
break;
case CELL_PAMF_STREAM_TYPE_ATRAC3PLUS:
{
auto pInfo = vm::ptr<CellPamfAtrac3plusInfo>::make(pInfo_addr);
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;
}
pInfo->numberOfChannels = pAudio->channels;
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))
{
cellPamf->Error("cellPamfReaderGetStreamInfo: wrong AC3 data size(%d)", size);
return CELL_PAMF_ERROR_INVALID_ARG;
}
pInfo->numberOfChannels = pAudio->channels;
pInfo->samplingFrequency = CELL_PAMF_FS_48kHz;
}
break;
case CELL_PAMF_STREAM_TYPE_PAMF_LPCM:
{
auto pInfo = vm::ptr<CellPamfLpcmInfo>::make(pInfo_addr);
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;
}
pInfo->numberOfChannels = pAudio->channels;
pInfo->samplingFrequency = CELL_PAMF_FS_48kHz;
if (pAudio->bps == 0x40)
pInfo->bitsPerSample = CELL_PAMF_BIT_LENGTH_16;
else
//TODO: CELL_PAMF_BIT_LENGTH_24
cellPamf->Error("cellPamfReaderGetStreamInfo: unknown bps(0x%x)", (u8)pAudio->bps);
}
break;
case CELL_PAMF_STREAM_TYPE_USER_DATA:
{
cellPamf->Error("cellPamfReaderGetStreamInfo: CELL_PAMF_STREAM_TYPE_USER_DATA");
return CELL_PAMF_ERROR_INVALID_ARG;
}
auto info = vm::ptr<CellPamfAvcInfo>::make(pInfo_addr);
info->profileIdc = header.AVC.profileIdc;
info->levelIdc = header.AVC.levelIdc;
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;
if (header.AVC.aspectRatioIdc == 0xff)
{
info->sarWidth = header.AVC.sarWidth;
info->sarHeight = header.AVC.sarHeight;
}
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;
}
case CELL_PAMF_STREAM_TYPE_M2V:
{
if (size < sizeof(CellPamfM2vInfo))
{
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;
}
case CELL_PAMF_STREAM_TYPE_ATRAC3PLUS:
{
if (size < sizeof(CellPamfAtrac3plusInfo))
{
return CELL_PAMF_ERROR_INVALID_ARG;
}
auto info = vm::ptr<CellPamfAtrac3plusInfo>::make(pInfo_addr);
info->samplingFrequency = header.audio.freq & 0xf;
info->numberOfChannels = header.audio.channels & 0xf;
cellPamf->Notice("cellPamfReaderGetStreamInfo(): CELL_PAMF_STREAM_TYPE_ATRAC3PLUS");
break;
}
case CELL_PAMF_STREAM_TYPE_PAMF_LPCM:
{
if (size < sizeof(CellPamfLpcmInfo))
{
return CELL_PAMF_ERROR_INVALID_ARG;
}
auto info = vm::ptr<CellPamfLpcmInfo>::make(pInfo_addr);
info->samplingFrequency = header.audio.freq & 0xf;
info->numberOfChannels = header.audio.channels & 0xf;
info->bitsPerSample = header.audio.bps >> 6;
cellPamf->Notice("cellPamfReaderGetStreamInfo(): CELL_PAMF_STREAM_TYPE_PAMF_LPCM");
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:
{
cellPamf->Error("cellPamfReaderGetStreamInfo(): invalid type CELL_PAMF_STREAM_TYPE_USER_DATA");
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;
}
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) {
return CELL_PAMF_ERROR_INVALID_PAMF;
}
return pSelf->pAddr->stream_headers[pSelf->stream].ep_num;
// cannot return error code
return 0; //pSelf->pAddr->stream_headers[pSelf->stream].ep_num;
}
int cellPamfReaderGetEpIteratorWithIndex(vm::ptr<CellPamfReader> pSelf, u32 epIndex, vm::ptr<CellPamfEpIterator> pIt)
s32 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());
if (!pSelf->pAddr) {
return CELL_PAMF_ERROR_INVALID_PAMF;
}
//TODO:
// TODO
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());
if (!pSelf->pAddr) {
return CELL_PAMF_ERROR_INVALID_PAMF;
}
//TODO:
// TODO
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());
//TODO:
// always returns CELL_OK
// TODO
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());
//TODO:
return CELL_OK;
// cannot return error code
// TODO
return 0;
}
void cellPamf_init(Module *pxThis)

View File

@ -141,6 +141,8 @@ struct CellCodecTimeStamp
be_t<u32> lower;
};
static const u64 CODEC_TS_INVALID = 0xffffffffffffffffull;
// Entry point information
struct CellPamfEp
{
@ -168,37 +170,41 @@ struct CellCodecEsFilterId
};
// AVC (MPEG4 AVC Video) Specific Information
struct CellPamfAvcInfo {
struct CellPamfAvcInfo
{
u8 profileIdc;
u8 levelIdc;
u8 frameMbsOnlyFlag;
u8 videoSignalInfoFlag;
u8 frameRateInfo;
u8 aspectRatioIdc;
be_t<u16> sarWidth; //reserved
be_t<u16> sarHeight; //reserved
be_t<u16> sarWidth;
be_t<u16> sarHeight;
be_t<u16> horizontalSize;
be_t<u16> verticalSize;
be_t<u16> frameCropLeftOffset; //reserved
be_t<u16> frameCropRightOffset; //reserved
be_t<u16> frameCropTopOffset; //reserved
be_t<u16> frameCropBottomOffset; //!!!!!
u8 videoFormat; //reserved
be_t<u16> frameCropLeftOffset;
be_t<u16> frameCropRightOffset;
be_t<u16> frameCropTopOffset;
be_t<u16> frameCropBottomOffset;
u8 videoFormat;
u8 videoFullRangeFlag;
u8 colourPrimaries;
u8 transferCharacteristics;
u8 matrixCoefficients;
u8 entropyCodingModeFlag; //reserved
u8 entropyCodingModeFlag;
u8 deblockingFilterFlag;
u8 minNumSlicePerPictureIdc; //reserved
u8 nfwIdc; //reserved
u8 maxMeanBitrate; //reserved
u8 minNumSlicePerPictureIdc;
u8 nfwIdc;
u8 maxMeanBitrate;
};
static_assert(sizeof(CellPamfAvcInfo) == 0x20, "Invalid CellPamfAvcInfo size");
// M2V (MPEG2 Video) Specific Information
struct CellPamfM2vInfo {
struct CellPamfM2vInfo
{
u8 profileAndLevelIndication;
bool progressiveSequence;
u8 progressiveSequence;
u8 videoSignalInfoFlag;
u8 frameRateInfo;
u8 aspectRatioIdc;
@ -215,76 +221,122 @@ struct CellPamfM2vInfo {
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
struct CellPamfLpcmInfo {
struct CellPamfLpcmInfo
{
be_t<u32> samplingFrequency;
u8 numberOfChannels;
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
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
struct PamfStreamHeader
{
//TODO: look for correct beginning of stream header
u8 type; //0x1B for video (AVC), 0xDC ATRAC3+, 0x80 LPCM, 0xDD userdata
u8 unknown[3]; //0
//TODO: examine stream_ch encoding
u8 stream_id;
u8 private_stream_id;
u8 unknown1; //?????
u8 unknown2; //?????
//Entry Point Info
be_t<u32> ep_offset; //offset of EP section in header
be_t<u32> ep_num; //count of EPs
//Specific Info
u8 data[32];
u8 type;
u8 unknown[3];
u8 fid_major;
u8 fid_minor;
u8 unknown1;
u8 unknown2;
be_t<u32> ep_offset; // offset of EP section in header
be_t<u32> ep_num; // count of EPs
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
{
u32 magic; //"PAMF"
@ -317,21 +369,27 @@ struct PamfHeader
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> pts_high;
be_t<u32> pts_low;
be_t<u32> rpnOffset;
};
static_assert(sizeof(PamfEpHeader) == 12, "Invalid PamfEpHeader size");
#pragma pack(pop)
// not directly accessed by virtual CPU, fields are unknown
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;
int stream;
s32 stream;
u64 fileSize;
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);

View File

@ -4,12 +4,14 @@
#include "Emu/SysCalls/Modules.h"
#include "stblib/stb_image.h"
#include "Emu/SysCalls/lv2/lv2Fs.h"
#include "Emu/SysCalls/lv2/cellFs.h"
#include "cellPngDec.h"
#include <map>
Module *cellPngDec = nullptr;
#undef PRX_DEBUG
#ifdef PRX_DEBUG
#include "prx_libpngdec.h"
u32 libpngdec;
@ -75,13 +77,13 @@ s64 pngDecOpen(
stream->fd = 0;
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();
break;
case CELL_PNGDEC_FILE:
case se32(CELL_PNGDEC_FILE):
// Get file descriptor
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);
@ -143,7 +145,7 @@ s64 pngReadHeader(
auto buffer_32 = buffer.To<be_t<u32>>();
vm::var<be_t<u64>> pos, nread;
switch (stream->src.srcSelect.ToBE())
switch ((u32)stream->src.srcSelect.ToBE())
{
case se32(CELL_PNGDEC_BUFFER):
memmove(buffer.begin(), stream->src.streamPtr.get_ptr(), buffer.size());
@ -204,17 +206,21 @@ s64 pngDecSetParameter(
current_outParam.outputHeight = current_info.imageHeight;
current_outParam.outputColorSpace = inParam->outputColorSpace;
switch ((u32)current_outParam.outputColorSpace)
switch ((u32)current_outParam.outputColorSpace.ToBE())
{
case CELL_PNGDEC_PALETTE:
case CELL_PNGDEC_GRAYSCALE: current_outParam.outputComponents = 1; break;
case se32(CELL_PNGDEC_PALETTE):
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 CELL_PNGDEC_ARGB: current_outParam.outputComponents = 4; break;
case se32(CELL_PNGDEC_RGBA):
case se32(CELL_PNGDEC_ARGB):
current_outParam.outputComponents = 4; break;
default:
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<be_t<u64>> pos, nread;
switch (stream->src.srcSelect.ToBE())
switch ((u32)stream->src.srcSelect.ToBE())
{
case se32(CELL_PNGDEC_BUFFER):
memmove(png.begin(), stream->src.streamPtr.get_ptr(), png.size());
@ -277,10 +283,10 @@ s64 pngDecodeData(
const int bytesPerLine = (u32)dataCtrlParam->outputBytesPerLine;
uint image_size = width * height;
switch ((u32)current_outParam.outputColorSpace)
switch ((u32)current_outParam.outputColorSpace.ToBE())
{
case CELL_PNGDEC_RGB:
case CELL_PNGDEC_RGBA:
case se32(CELL_PNGDEC_RGB):
case se32(CELL_PNGDEC_RGBA):
{
const char nComponents = current_outParam.outputColorSpace == CELL_PNGDEC_RGBA ? 4 : 3;
image_size *= nComponents;
@ -298,10 +304,10 @@ s64 pngDecodeData(
{
memcpy(data.get_ptr(), image.get(), image_size);
}
}
break;
}
case CELL_PNGDEC_ARGB:
case se32(CELL_PNGDEC_ARGB):
{
const int nComponents = 4;
image_size *= nComponents;
@ -340,12 +346,12 @@ s64 pngDecodeData(
memcpy(data.get_ptr(), img, image_size);
delete[] img;
}
}
break;
}
case CELL_PNGDEC_GRAYSCALE:
case CELL_PNGDEC_PALETTE:
case CELL_PNGDEC_GRAYSCALE_ALPHA:
case se32(CELL_PNGDEC_GRAYSCALE):
case se32(CELL_PNGDEC_PALETTE):
case se32(CELL_PNGDEC_GRAYSCALE_ALPHA):
cellPngDec->Error("pngDecodeData: Unsupported color space (%d)", current_outParam.outputColorSpace.ToLE());
break;

View File

@ -1,8 +1,10 @@
#include "stdafx.h"
#include "Emu/Memory/Memory.h"
#include "Emu/SysCalls/Modules.h"
#include "Emu/FS/vfsFile.h"
#include "cellSail.h"
#include "cellPamf.h"
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());
pSelf->callbacks = pCallbacks;
// TODO: Create a cellSail thread
return CELL_OK;
}
@ -71,7 +74,7 @@ int cellSailDescriptorGetMediaInfo()
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) {
pSelf->autoSelection = autoSelection;
@ -91,9 +94,22 @@ int cellSailDescriptorIsAutoSelection(vm::ptr<CellSailDescriptor> pSelf)
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;
}
@ -616,23 +632,52 @@ int cellSailPlayerAddDescriptor(vm::ptr<CellSailPlayer> pSelf, vm::ptr<CellSailD
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());
// 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();
//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->descriptors = 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());
//cellSailPlayerAddDescriptor(pSelf, ppDesc);
@ -766,16 +811,16 @@ int cellSailPlayerCancel()
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;
}
int cellSailPlayerIsPaused()
int cellSailPlayerIsPaused(vm::ptr<CellSailPlayer> pSelf)
{
UNIMPLEMENTED_FUNC(cellSail);
return CELL_OK;
cellSail->Warning("cellSailPlayerIsPaused(pSelf_addr=0x%x)", pSelf.addr());
return pSelf->paused;
}
int cellSailPlayerSetRepeatMode(vm::ptr<CellSailPlayer> pSelf, s32 repeatMode, vm::ptr<CellSailStartCommand> pCommand)

View File

@ -679,8 +679,8 @@ typedef void(*CellSailPlayerFuncNotified)(u32 pArg, vm::ptr<CellSailEvent> event
struct CellSailMemAllocatorFuncs
{
CellSailMemAllocatorFuncAlloc pAlloc;
CellSailMemAllocatorFuncFree pFree;
vm::ptr<CellSailMemAllocatorFuncAlloc> pAlloc;
vm::ptr<CellSailMemAllocatorFuncFree> pFree;
};
struct CellSailMemAllocator
@ -691,8 +691,8 @@ struct CellSailMemAllocator
struct CellSailFuture
{
u32 mutex_id;
u32 cond_id;
be_t<u32> mutex_id;
be_t<u32> cond_id;
volatile be_t<u32> flags;
be_t<s32> result;
be_t<u64> userParam;
@ -1038,9 +1038,11 @@ struct CellSailDescriptor
bool autoSelection;
bool registered;
be_t<s32> streamType;
be_t<u64> internalData[32];
be_t<u64> internalData[31];
};
static_assert(sizeof(CellSailDescriptor) == 0x100, "Invalid CellSailDescriptor size");
struct CellSailStartCommand
{
be_t<u32> startType;
@ -1102,4 +1104,8 @@ struct CellSailPlayer
be_t<s32> repeatMode;
be_t<s32> descriptors;
vm::ptr<CellSailDescriptor> registeredDescriptors[2];
bool paused = true;
be_t<u64> internalData[26];
};
static_assert(sizeof(CellSailPlayer) == 0x100, "Invalid CellSailPlayer size");

View File

@ -10,6 +10,14 @@
#include "Loader/PSF.h"
#include "cellSaveData.h"
#ifdef _WIN32
#include <windows.h>
#undef CreateFile
#else
#include <sys/types.h>
#include <sys/stat.h>
#endif
extern Module *cellSysutil;
// Auxiliary Classes
@ -39,7 +47,6 @@ public:
}
};
// Auxiliary Functions
u64 getSaveDataSize(const std::string& dirName)
{
@ -69,6 +76,26 @@ void addSaveDataEntry(std::vector<SaveDataEntry>& saveEntries, const std::string
std::string 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;
saveEntry.dirName = psf.GetString("SAVEDATA_DIRECTORY");
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.details = psf.GetString("DETAIL");
saveEntry.sizeKB = (u32)(getSaveDataSize(saveDir) / 1024);
saveEntry.st_atime_ = 0; // TODO
saveEntry.st_mtime_ = 0; // TODO
saveEntry.st_ctime_ = 0; // TODO
saveEntry.st_atime_ = atime;
saveEntry.st_mtime_ = mtime;
saveEntry.st_ctime_ = ctime;
saveEntry.iconBuf = NULL; // TODO: Here should be the PNG buffer
saveEntry.iconBufSize = 0; // TODO: Size of the PNG file
saveEntry.isNew = false;
@ -112,7 +139,7 @@ void setSaveDataList(std::vector<SaveDataEntry>& saveEntries, vm::ptr<CellSaveDa
while (entry != saveEntries.end())
{
bool found = false;
for (u32 j=0; j<fixedListNum; j++)
for (u32 j = 0; j < fixedListNum; j++)
{
if (entry->dirName == (char*)fixedList[j].dirName)
{
@ -196,10 +223,15 @@ void getSaveDataStat(SaveDataEntry entry, vm::ptr<CellSaveDataStatGet> statGet)
CellSaveDataFileStat fileEntry;
vfsFile file(saveDir + "/" + dirEntry->name);
if (dirEntry->name == "ICON0.PNG") fileEntry.fileType = CELL_SAVEDATA_FILETYPE_CONTENT_ICON0;
if (dirEntry->name == "ICON1.PAM") fileEntry.fileType = CELL_SAVEDATA_FILETYPE_CONTENT_ICON1;
if (dirEntry->name == "PIC1.PNG") fileEntry.fileType = CELL_SAVEDATA_FILETYPE_CONTENT_PIC1;
if (dirEntry->name == "SND0.AT3") fileEntry.fileType = CELL_SAVEDATA_FILETYPE_CONTENT_SND0;
if (dirEntry->name == "ICON0.PNG")
fileEntry.fileType = CELL_SAVEDATA_FILETYPE_CONTENT_ICON0;
else if (dirEntry->name == "ICON1.PAM")
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_atime_ = 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))));
for (u32 i=0; i<fileEntries.size(); i++)
memcpy(&statGet->fileList[i], &fileEntries[i], sizeof(CellSaveDataFileStat));
statGet->fileList = vm::ptr<CellSaveDataFileStat>::make((u32)Memory.Alloc(sizeof(CellSaveDataFileStat) * fileEntries.size(), 8));
for (u32 i = 0; i < fileEntries.size(); i++) {
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)
@ -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.
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;
}
@ -637,7 +671,9 @@ int cellSaveDataAutoSave2(u32 version, vm::ptr<const char> dirName, u32 errDialo
result->userdata = userdata;
funcStat(result, statGet, statSet);
Memory.Free(statGet->fileList.addr());
if (statGet->fileList)
Memory.Free(statGet->fileList.addr());
if (result->result < 0) {
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;

View File

@ -3,8 +3,13 @@
#include "Emu/System.h"
#include "Emu/SysCalls/Modules.h"
#include "Emu/SysCalls/CB_FUNC.h"
#include "Emu/Memory/atomic_type.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_memory.h"
#include "Emu/SysCalls/lv2/sys_process.h"
@ -251,13 +256,13 @@ s64 spursInit(
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");
}
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");
}
@ -265,6 +270,8 @@ s64 spursInit(
}
else while (true)
{
if (Emu.IsStopped()) break;
spurs->m.xD64.exchange(0);
if (spurs->m.exception.ToBE() == 0)
{
@ -311,7 +318,7 @@ s64 spursInit(
spurs->m.xD65.exchange(1);
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");
}
@ -319,14 +326,17 @@ s64 spursInit(
spurs->m.xD65.exchange(0);
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");
}
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");
}
@ -393,7 +403,7 @@ s64 spursInit(
}
else if (flags & SAF_EXIT_IF_NO_WORK) // wakeup
{
return spursWakeUp(spurs);
return spursWakeUp(GetCurrentPPUThread(), spurs);
}
return CELL_OK;
@ -953,7 +963,7 @@ s64 cellSpursGetInfo(vm::ptr<CellSpurs> spurs, vm::ptr<CellSpursInfo> info)
#endif
}
s64 spursWakeUp(vm::ptr<CellSpurs> spurs)
s64 spursWakeUp(PPUThread& CPU, vm::ptr<CellSpurs> spurs)
{
#ifdef PRX_DEBUG_XXX
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);
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");
}
@ -983,7 +993,7 @@ s64 spursWakeUp(vm::ptr<CellSpurs> spurs)
{
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");
}
@ -991,11 +1001,11 @@ s64 spursWakeUp(vm::ptr<CellSpurs> spurs)
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());
return spursWakeUp(spurs);
return spursWakeUp(CPU, spurs);
}
s32 spursAddWorkload(
@ -2509,7 +2519,7 @@ s64 _cellSpursTaskAttribute2Initialize(vm::ptr<CellSpursTaskAttribute2> attribut
#else
attribute->revision = revision;
attribute->sizeContext = 0;
attribute->eaContext = NULL;
attribute->eaContext = 0;
for (s32 c = 0; c < 4; c++)
{

View File

@ -1,7 +1,4 @@
#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.
enum
@ -820,4 +817,4 @@ struct SpursKernelMgmtData {
};
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);

View File

@ -2,7 +2,12 @@
#include "Emu/Memory/Memory.h"
#include "Emu/System.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 "cellSpursJq.h"

View File

@ -3,6 +3,9 @@
#include "Emu/System.h"
#include "Emu/Cell/SPUThread.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"
//

View File

@ -1,21 +1,10 @@
#include "stdafx.h"
#if 0
#include "Emu/Memory/Memory.h"
#include "Emu/SysCalls/Modules.h"
void cellSubdisplay_init();
Module cellSubdisplay(0x0034, cellSubdisplay_init);
#include "cellSubdisplay.h"
// 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,
};
Module *cellSubdisplay = nullptr;
int cellSubDisplayInit()
{
@ -29,10 +18,18 @@ int cellSubDisplayEnd()
return CELL_OK;
}
int cellSubDisplayGetRequiredMemory()
int cellSubDisplayGetRequiredMemory(vm::ptr<CellSubDisplayParam> pParam)
{
UNIMPLEMENTED_FUNC(cellSubdisplay);
return CELL_OK;
cellSubdisplay->Warning("cellSubDisplayGetRequiredMemory(pParam_addr=0x%x)", pParam.addr());
if (pParam->version == CELL_SUBDISPLAY_VERSION_0002)
{
return CELL_SUBDISPLAY_0002_MEMORY_CONTAINER_SIZE;
}
else
{
return CELL_SUBDISPLAY_0001_MEMORY_CONTAINER_SIZE;
}
}
int cellSubDisplayStart()
@ -77,19 +74,20 @@ int cellSubDisplayGetPeerList()
return CELL_OK;
}
void cellSubdisplay_init()
void cellSubdisplay_init(Module *pxThis)
{
cellSubdisplay.AddFunc(0xf9a7e8a5, cellSubDisplayInit);
cellSubdisplay.AddFunc(0x551d80a5, cellSubDisplayEnd);
cellSubdisplay.AddFunc(0x6595ce22, cellSubDisplayGetRequiredMemory);
cellSubdisplay.AddFunc(0xa5bccb47, cellSubDisplayStart);
cellSubdisplay.AddFunc(0x6d85ddb3, cellSubDisplayStop);
cellSubdisplay = pxThis;
cellSubdisplay.AddFunc(0x938ac642, cellSubDisplayGetVideoBuffer);
cellSubdisplay.AddFunc(0xaee1e0c2, cellSubDisplayAudioOutBlocking);
cellSubdisplay.AddFunc(0x5468d6b0, cellSubDisplayAudioOutNonBlocking);
cellSubdisplay->AddFunc(0xf9a7e8a5, cellSubDisplayInit);
cellSubdisplay->AddFunc(0x551d80a5, cellSubDisplayEnd);
cellSubdisplay->AddFunc(0x6595ce22, cellSubDisplayGetRequiredMemory);
cellSubdisplay->AddFunc(0xa5bccb47, cellSubDisplayStart);
cellSubdisplay->AddFunc(0x6d85ddb3, cellSubDisplayStop);
cellSubdisplay.AddFunc(0x8a264d71, cellSubDisplayGetPeerNum);
cellSubdisplay.AddFunc(0xe2485f79, cellSubDisplayGetPeerList);
cellSubdisplay->AddFunc(0x938ac642, cellSubDisplayGetVideoBuffer);
cellSubdisplay->AddFunc(0xaee1e0c2, cellSubDisplayAudioOutBlocking);
cellSubdisplay->AddFunc(0x5468d6b0, cellSubDisplayAudioOutNonBlocking);
cellSubdisplay->AddFunc(0x8a264d71, cellSubDisplayGetPeerNum);
cellSubdisplay->AddFunc(0xe2485f79, cellSubDisplayGetPeerList);
}
#endif

View File

@ -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);

View File

@ -3,7 +3,10 @@
#include "Emu/System.h"
#include "Emu/SysCalls/Modules.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/Event.h"
#include "cellSync.h"

View File

@ -286,13 +286,13 @@ int cellVideoOutGetNumberOfDevice(u32 videoOut)
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);
if(!ResolutionIdToNum(resolutionId))
{
return CELL_EINVAL;
}
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 ||
resolutionId == CELL_VIDEO_OUT_RESOLUTION_640x720_3D_FRAME_PACKING))
return 0;
switch(videoOut)
{

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