Merge upstream

This commit is contained in:
S Gopal Rajagopal
2015-01-05 16:44:26 +05:30
169 changed files with 11377 additions and 7129 deletions
+1 -1
View File
@@ -19,7 +19,7 @@ __Windows__
* [Visual C++ Redistributable Packages for Visual Studio 2013](http://www.microsoft.com/en-us/download/details.aspx?id=40784)
__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`
+9 -7
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);
}
};
+4 -4
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;
+3 -3
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())
{
-10
View File
@@ -1,10 +0,0 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/CPU/CPUThread.h"
#include "Utilities/SMutex.h"
bool SM_IsAborted()
{
return Emu.IsStopped();
}
-129
View File
@@ -1,129 +0,0 @@
#pragma once
#include "Emu/Memory/atomic_type.h"
bool SM_IsAborted();
enum SMutexResult
{
SMR_OK = 0, // succeeded (lock, trylock, unlock)
SMR_FAILED, // failed (trylock, unlock)
SMR_DEADLOCK, // mutex reached deadlock (lock, trylock)
SMR_SIGNAL = SMR_DEADLOCK, // unlock can be used for signaling specific thread
SMR_PERMITTED, // not owner of the mutex (unlock)
SMR_ABORT, // emulator has been stopped (lock, trylock, unlock)
SMR_DESTROYED, // mutex has been destroyed (lock, trylock, unlock)
SMR_TIMEOUT, // timed out (lock)
};
template
<
typename T,
const u64 free_value = 0,
const u64 dead_value = 0xffffffffffffffffull
>
class SMutexBase
{
static_assert(sizeof(T) == sizeof(atomic_le_t<T>), "Invalid SMutexBase type");
T owner;
typedef atomic_le_t<T> AT;
public:
static const T GetFreeValue()
{
static const u64 value = free_value;
return (T&)value;
}
static const T GetDeadValue()
{
static const u64 value = dead_value;
return (T&)value;
}
void initialize()
{
owner = GetFreeValue();
}
void finalize()
{
owner = GetDeadValue();
}
__forceinline T GetOwner() const
{
return (T&)owner;
}
SMutexResult trylock(T tid)
{
if (SM_IsAborted())
{
return SMR_ABORT;
}
T old = reinterpret_cast<AT&>(owner).compare_and_swap(GetFreeValue(), tid);
if (old != GetFreeValue())
{
if (old == tid)
{
return SMR_DEADLOCK;
}
if (old == GetDeadValue())
{
return SMR_DESTROYED;
}
return SMR_FAILED;
}
return SMR_OK;
}
SMutexResult unlock(T tid, T to = GetFreeValue())
{
if (SM_IsAborted())
{
return SMR_ABORT;
}
T old = reinterpret_cast<AT&>(owner).compare_and_swap(tid, to);
if (old != tid)
{
if (old == GetFreeValue())
{
return SMR_FAILED;
}
if (old == GetDeadValue())
{
return SMR_DESTROYED;
}
return SMR_PERMITTED;
}
return SMR_OK;
}
SMutexResult lock(T tid, u64 timeout = 0)
{
u64 counter = 0;
while (true)
{
switch (SMutexResult res = trylock(tid))
{
case SMR_FAILED: break;
default: return res;
}
std::this_thread::sleep_for(std::chrono::milliseconds(1));
if (timeout && counter++ > timeout)
{
return SMR_TIMEOUT;
}
}
}
};
typedef SMutexBase<u32> SMutex;
-118
View File
@@ -1,118 +0,0 @@
#pragma once
static const volatile bool sq_no_wait = true;
template<typename T, u32 SQSize = 666>
class SQueue
{
mutable std::mutex m_mutex;
u32 m_pos;
u32 m_count;
T m_data[SQSize];
public:
SQueue()
: m_pos(0)
, m_count(0)
{
}
u32 GetSize() const
{
return SQSize;
}
bool IsFull() const volatile
{
return m_count == SQSize;
}
bool Push(const T& data, const volatile bool* do_exit)
{
while (true)
{
if (m_count >= SQSize)
{
if (Emu.IsStopped() || (do_exit && *do_exit))
{
return false;
}
std::this_thread::sleep_for(std::chrono::milliseconds(1));
continue;
}
{
std::lock_guard<std::mutex> lock(m_mutex);
if (m_count >= SQSize) continue;
m_data[(m_pos + m_count++) % SQSize] = data;
return true;
}
}
}
bool Pop(T& data, const volatile bool* do_exit)
{
while (true)
{
if (!m_count)
{
if (Emu.IsStopped() || (do_exit && *do_exit))
{
return false;
}
std::this_thread::sleep_for(std::chrono::milliseconds(1));
continue;
}
{
std::lock_guard<std::mutex> lock(m_mutex);
if (!m_count) continue;
data = m_data[m_pos];
m_pos = (m_pos + 1) % SQSize;
m_count--;
return true;
}
}
}
void Clear()
{
std::lock_guard<std::mutex> lock(m_mutex);
m_count = 0;
}
bool Peek(T& data, const volatile bool* do_exit, u32 pos = 0)
{
while (true)
{
if (m_count <= pos)
{
if (Emu.IsStopped() || (do_exit && *do_exit))
{
return false;
}
std::this_thread::sleep_for(std::chrono::milliseconds(1));
continue;
}
{
std::lock_guard<std::mutex> lock(m_mutex);
if (m_count > pos)
{
break;
}
}
}
data = m_data[(m_pos + pos) % SQSize];
return true;
}
};
+26 -7
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;
@@ -164,4 +183,4 @@ std::string fmt::tolower(std::string source)
std::transform(source.begin(), source.end(), source.begin(), ::tolower);
return source;
}
}
+37 -29
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);
}
+313 -29
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();
}
};
+1 -1
Submodule asmjit updated: 1318c9aff7...48da90ded7
+1 -1
Submodule ffmpeg updated: 352fdfbbfa...79a2d7a9f7
+4 -4
View File
@@ -43,13 +43,13 @@ bool CheckHeader(rFile& pkg_f, PKGHeader* m_header)
}
if (m_header->pkg_size != pkg_f.Length()) {
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;
+27 -14
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;
}
};
};
+1 -2
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
+6 -2
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;
}
}
+26 -1
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();
+4 -4
View File
@@ -121,7 +121,7 @@ s32 sceKernelStartThread(s32 threadId, u32 argSize, vm::psv::ptr<const void> pAr
{
sceLibKernel.Error("sceKernelStartThread(threadId=%d, argSize=%d, pArgBlock_addr=0x%x)", threadId, argSize, pArgBlock.addr());
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;
+1
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"
+1
View File
@@ -1,4 +1,5 @@
#include "stdafx.h"
#include "Utilities/Log.h"
#include "Emu/System.h"
#include "PSVFuncList.h"
+3
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
+3 -26
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;
}
+1 -18
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();
}
+11 -17
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();
}
+3 -3
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();
+5 -6
View File
@@ -1030,14 +1030,13 @@ private:
Write(fmt::Format("bc [%x:%x:%x:%x:%x], cr%d[%x], 0x%x, %d, %d", bo0, bo1, bo2, bo3, bo4, bi/4, bi%4, bd, aa, lk));
}
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)
+3 -3
View File
@@ -162,8 +162,8 @@ namespace PPU_instr
//This field mask is used to identify the CR fields that are to be updated by the mtcrf instruction.
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);
+15 -9
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);
}
+6 -6
View File
@@ -1995,20 +1995,20 @@ void Compiler::BC(u32 bo, u32 bi, s32 bd, u32 aa, u32 lk) {
CreateBranch(CheckBranchCondition(bo, bi), target_i32, lk ? true : false);
}
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;
}
}
+3 -1
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;
+2
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;
-2
View File
@@ -1,7 +1,5 @@
#pragma once
#include "Emu/SysCalls/Modules/cellSpurs.h"
class SPURSManagerEventFlag
{
public:
+1 -1
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();
+106 -73
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();
}
+6 -4
View File
@@ -1,10 +1,12 @@
#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"
enum SPUchannels
enum SPUchannels
{
SPU_RdEventStat = 0, //Read event status with mask applied
SPU_WrEventMask = 1, //Write event mask
@@ -22,7 +24,7 @@ enum SPUchannels
SPU_WrOutIntrMbox = 30, //Write outbound interrupt mailbox contents (interrupting PPU)
};
enum MFCchannels
enum MFCchannels
{
MFC_WrMSSyncReq = 9, //Write multisource synchronization request
MFC_RdTagMask = 12, //Read tag mask
@@ -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
+8 -6
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;
}
+5 -4
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);
};
+3 -12
View File
@@ -32,21 +32,12 @@ std::string simplify_path(const std::string& path, bool is_dir)
{
std::vector<std::string> path_blocks = simplify_path_blocks(path);
std::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()
+6 -1
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;
+1
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;
+31 -13
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{};
}
}
};
+12 -20
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)
+2 -2
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()
{
+5 -11
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)
+8 -8
View File
@@ -67,12 +67,12 @@ namespace vm
__forceinline _ptr_base<T, lvl - 1, std::conditional<is_be_t<T>::value, typename to_be_t<AT>::type, AT>>& operator *() const
{
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
{
+353 -187
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,22 +613,22 @@ 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();
}
delete m_decompiler_thread;
m_decompiler_thread = nullptr;
}
@@ -473,93 +636,96 @@ 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();
}
delete m_decompiler_thread;
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;
}
}
+10 -32
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
+31 -4
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();
};
+7
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;
+1
View File
@@ -24,5 +24,6 @@ public:
void Use();
void UnUse();
void SetTex(u32 index);
void SetVTex(u32 index);
void Delete();
};
+9 -9
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);
+2 -2
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();
};
+98 -10
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 }, ".");
}
};
+341 -139
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;
@@ -58,7 +58,7 @@ std::string GLVertexDecompilerThread::GetDST(bool isSca)
std::string GLVertexDecompilerThread::GetSRC(const u32 n)
{
static const std::string reg_table[] =
static const std::string reg_table[] =
{
"in_pos", "in_weight", "in_normal",
"in_diff_color", "in_spec_color",
@@ -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);
@@ -632,16 +834,16 @@ void GLVertexProgram::Compile()
glShaderSource(id, 1, &str, &strlen);
glCompileShader(id);
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())
{
+57 -1
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);
+37 -38
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() {}
};
+3 -3
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)
+203
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)];
}
+60 -3
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
+44 -10
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;
+6 -5
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
+1
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";
+2 -2
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
+2 -1
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 },
+1 -1
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();
+5 -3
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);
}
+222 -130
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();
+14 -5
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;
+146 -27
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;
}
+9 -6
View File
@@ -16,16 +16,18 @@ int cellVideoOutGetScreenSize(u32 videoOut, vm::ptr<float> screenSize)
{
cellAvconfExt->Warning("cellVideoOutGetScreenSize(videoOut=%d, screenSize_addr=0x%x)", videoOut, screenSize.addr());
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);
}
+287 -174
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))
{
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);
}
u8 pos = 0;
while (pos++ < size)
{
u8 empty = 0;
u8 v;
while (true)
if (!stream.get(v))
{
stream.get(v);
if (v != 0xFF) break; // skip padding bytes
empty++;
if (empty == size) return;
};
return; // should never occur
}
if ((v & 0xF0) == 0x20 && (size - empty) >= 5) // pts only
if (v == 0xff) // skip padding bytes
{
has_ts = true;
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;
}
case dmuxClose:
{
break;
}
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;
}
+10 -38
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);
+2 -4
View File
@@ -385,8 +385,7 @@ int cellFontGetEffectSlant(vm::ptr<CellFont> font, vm::ptr<be_t<float>> slantPar
int cellFontGetFontIdCode(vm::ptr<CellFont> font, u32 code, vm::ptr<u32> fontId, vm::ptr<u32> fontCode)
{
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;
+11 -8
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;
+6 -6
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;
+6 -6
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;
+74 -39
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);
+16 -21
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();
+27 -3
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);
+24
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];
+454 -283
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 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:
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;
{
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)
{
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());
if (!pEsFilterId)
{
return CELL_PAMF_ERROR_INVALID_ARG;
}
return pamfStreamTypeToEsFilterId(type, ch, pEsFilterId);
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)
+135 -77
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);
+28 -22
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;
+66 -21
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;
@@ -84,16 +87,29 @@ int cellSailDescriptorSetAutoSelection(vm::ptr<CellSailDescriptor> pSelf, bool a
int cellSailDescriptorIsAutoSelection(vm::ptr<CellSailDescriptor> pSelf)
{
cellSail->Warning("cellSailDescriptorIsAutoSelection(pSelf_addr=0x%x)", pSelf.addr());
if (pSelf)
return pSelf->autoSelection;
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)
+12 -6
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");
+50 -14
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;
+22 -12
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++)
{
+1 -4
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);
@@ -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"
@@ -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"
//
+28 -30
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
@@ -0,0 +1,83 @@
#pragma once
// Return Codes
enum
{
CELL_SUBDISPLAY_ERROR_OUT_OF_MEMORY = 0x80029851,
CELL_SUBDISPLAY_ERROR_FATAL = 0x80029852,
CELL_SUBDISPLAY_ERROR_NOT_FOUND = 0x80029853,
CELL_SUBDISPLAY_ERROR_INVALID_VALUE = 0x80029854,
CELL_SUBDISPLAY_ERROR_NOT_INITIALIZED = 0x80029855,
CELL_SUBDISPLAY_ERROR_SET_SAMPLE = 0x80029860,
CELL_SUBDISPLAY_ERROR_AUDIOOUT_IS_BUSY = 0x80029861,
CELL_SUBDISPLAY_ERROR_ZERO_REGISTERED = 0x80029813,
};
// Different constants
enum
{
CELL_SUBDISPLAY_STATUS_JOIN = 1,
CELL_SUBDISPLAY_STATUS_LEAVE = 2,
CELL_SUBDISPLAY_STATUS_FATALERROR = 3,
CELL_SUBDISPLAY_VERSION_0001 = 1,
CELL_SUBDISPLAY_VERSION_0002 = 2,
CELL_SUBDISPLAY_MODE_REMOTEPLAY = 1,
CELL_SUBDISPLAY_VIDEO_FORMAT_A8R8G8B8 = 1,
CELL_SUBDISPLAY_VIDEO_FORMAT_R8G8B8A8 = 2,
CELL_SUBDISPLAY_VIDEO_ASPECT_RATIO_16_9 = 0,
CELL_SUBDISPLAY_VIDEO_ASPECT_RATIO_4_3 = 1,
CELL_SUBDISPLAY_VIDEO_MODE_SETDATA = 0,
CELL_SUBDISPLAY_VIDEO_MODE_CAPTURE = 1,
CELL_SUBDISPLAY_AUDIO_MODE_SETDATA = 0,
CELL_SUBDISPLAY_AUDIO_MODE_CAPTURE = 1,
CELL_SUBDISPLAY_0001_MEMORY_CONTAINER_SIZE = 8 * 1024 * 1024,
CELL_SUBDISPLAY_0002_MEMORY_CONTAINER_SIZE = 10 * 1024 * 1024,
CELL_SUBDISPLAY_NICKNAME_LEN = 256,
CELL_SUBDISPLAY_PSPID_LEN = 16,
};
struct CellSubDisplayVideoParam
{
be_t<s32> format;
be_t<s32> width;
be_t<s32> height;
be_t<s32> pitch;
be_t<s32> aspectRatio;
be_t<s32> videoMode;
};
struct CellSubDisplayAudioParam
{
be_t<s32> ch;
be_t<s32> audioMode;
};
struct CellSubDisplayParam
{
be_t<s32> version;
be_t<s32> mode;
be_t<s32> nGroup;
be_t<s32> nPeer;
vm::ptr<CellSubDisplayVideoParam> videoParam;
vm::ptr<CellSubDisplayAudioParam> audioParam;
};
struct CellSubDisplayPSPId
{
char data[CELL_SUBDISPLAY_PSPID_LEN];
};
struct CellSubDisplayNickname
{
char data[CELL_SUBDISPLAY_NICKNAME_LEN];
};
struct CellSubDisplayPeerInfo
{
be_t<u64> sessionId;
be_t<u32> portNo;
CellSubDisplayPSPId pspId;
CellSubDisplayNickname pspNickname;
};
typedef void(*CellSubDisplayHandler)(s32 cbMsg, u64 cbParam, u32 *userdata);
+3
View File
@@ -3,7 +3,10 @@
#include "Emu/System.h"
#include "Emu/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"
+5 -5
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