mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-03-12 04:14:35 +00:00
Merge upstream
This commit is contained in:
commit
2d94db4945
@ -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`
|
||||
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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())
|
||||
{
|
||||
|
@ -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();
|
||||
}
|
@ -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;
|
@ -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;
|
||||
}
|
||||
};
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#include "Emu/Memory/atomic_type.h"
|
||||
|
||||
static std::thread::id main_thread;
|
||||
|
||||
@ -71,33 +72,6 @@ public:
|
||||
bool joinable() const;
|
||||
};
|
||||
|
||||
class s_mutex_t
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
class s_shared_mutex_t
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
class s_cond_var_t
|
||||
{
|
||||
|
||||
//public:
|
||||
// s_cond_var_t();
|
||||
// ~s_cond_var_t();
|
||||
//
|
||||
// s_cond_var_t(s_cond_var_t& right) = delete;
|
||||
// s_cond_var_t& operator = (s_cond_var_t& right) = delete;
|
||||
//
|
||||
// void wait();
|
||||
// void wait_for();
|
||||
//
|
||||
// void notify();
|
||||
// void notify_all();
|
||||
};
|
||||
|
||||
class slw_mutex_t
|
||||
{
|
||||
|
||||
@ -160,10 +134,10 @@ public:
|
||||
// register waiter
|
||||
waiter_reg_t waiter(*this, signal_id);
|
||||
|
||||
// check condition or if emulator is stopped
|
||||
// check the condition or if the emulator is stopped
|
||||
while (!waiter_func() && !is_stopped(signal_id))
|
||||
{
|
||||
// initialize waiter (only first time)
|
||||
// initialize waiter (only once)
|
||||
waiter.init();
|
||||
// wait for 1 ms or until signal arrived
|
||||
waiter.thread->WaitForAnySignal(1);
|
||||
@ -173,3 +147,313 @@ public:
|
||||
// signal all threads waiting on waiter_op() with the same signal_id (signaling only hints those threads that corresponding conditions are *probably* met)
|
||||
void notify(u64 signal_id);
|
||||
};
|
||||
|
||||
bool squeue_test_exit(const volatile bool* do_exit);
|
||||
|
||||
template<typename T, u32 sq_size = 256>
|
||||
class squeue_t
|
||||
{
|
||||
struct squeue_sync_var_t
|
||||
{
|
||||
struct
|
||||
{
|
||||
u32 position : 31;
|
||||
u32 pop_lock : 1;
|
||||
};
|
||||
struct
|
||||
{
|
||||
u32 count : 31;
|
||||
u32 push_lock : 1;
|
||||
};
|
||||
};
|
||||
|
||||
atomic_le_t<squeue_sync_var_t> m_sync;
|
||||
|
||||
mutable std::mutex m_rcv_mutex;
|
||||
mutable std::mutex m_wcv_mutex;
|
||||
mutable std::condition_variable m_rcv;
|
||||
mutable std::condition_variable m_wcv;
|
||||
|
||||
T m_data[sq_size];
|
||||
|
||||
enum squeue_sync_var_result : u32
|
||||
{
|
||||
SQSVR_OK = 0,
|
||||
SQSVR_LOCKED = 1,
|
||||
SQSVR_FAILED = 2,
|
||||
};
|
||||
|
||||
public:
|
||||
squeue_t()
|
||||
{
|
||||
m_sync.write_relaxed({});
|
||||
}
|
||||
|
||||
u32 get_max_size() const
|
||||
{
|
||||
return sq_size;
|
||||
}
|
||||
|
||||
bool is_full() const volatile
|
||||
{
|
||||
return m_sync.read_relaxed().count == sq_size;
|
||||
}
|
||||
|
||||
bool push(const T& data, const volatile bool* do_exit = nullptr)
|
||||
{
|
||||
u32 pos = 0;
|
||||
|
||||
while (u32 res = m_sync.atomic_op_sync(SQSVR_OK, [&pos](squeue_sync_var_t& sync) -> u32
|
||||
{
|
||||
assert(sync.count <= sq_size);
|
||||
assert(sync.position < sq_size);
|
||||
|
||||
if (sync.push_lock)
|
||||
{
|
||||
return SQSVR_LOCKED;
|
||||
}
|
||||
if (sync.count == sq_size)
|
||||
{
|
||||
return SQSVR_FAILED;
|
||||
}
|
||||
|
||||
sync.push_lock = 1;
|
||||
pos = sync.position + sync.count;
|
||||
return SQSVR_OK;
|
||||
}))
|
||||
{
|
||||
if (res == SQSVR_FAILED && squeue_test_exit(do_exit))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unique_lock<std::mutex> wcv_lock(m_wcv_mutex);
|
||||
m_wcv.wait_for(wcv_lock, std::chrono::milliseconds(1));
|
||||
}
|
||||
|
||||
m_data[pos >= sq_size ? pos - sq_size : pos] = data;
|
||||
|
||||
m_sync.atomic_op([](squeue_sync_var_t& sync)
|
||||
{
|
||||
assert(sync.count <= sq_size);
|
||||
assert(sync.position < sq_size);
|
||||
assert(sync.push_lock);
|
||||
sync.push_lock = 0;
|
||||
sync.count++;
|
||||
});
|
||||
|
||||
m_rcv.notify_one();
|
||||
m_wcv.notify_one();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool try_push(const T& data)
|
||||
{
|
||||
static const volatile bool no_wait = true;
|
||||
|
||||
return push(data, &no_wait);
|
||||
}
|
||||
|
||||
bool pop(T& data, const volatile bool* do_exit = nullptr)
|
||||
{
|
||||
u32 pos = 0;
|
||||
|
||||
while (u32 res = m_sync.atomic_op_sync(SQSVR_OK, [&pos](squeue_sync_var_t& sync) -> u32
|
||||
{
|
||||
assert(sync.count <= sq_size);
|
||||
assert(sync.position < sq_size);
|
||||
|
||||
if (!sync.count)
|
||||
{
|
||||
return SQSVR_FAILED;
|
||||
}
|
||||
if (sync.pop_lock)
|
||||
{
|
||||
return SQSVR_LOCKED;
|
||||
}
|
||||
|
||||
sync.pop_lock = 1;
|
||||
pos = sync.position;
|
||||
return SQSVR_OK;
|
||||
}))
|
||||
{
|
||||
if (res == SQSVR_FAILED && squeue_test_exit(do_exit))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unique_lock<std::mutex> rcv_lock(m_rcv_mutex);
|
||||
m_rcv.wait_for(rcv_lock, std::chrono::milliseconds(1));
|
||||
}
|
||||
|
||||
data = m_data[pos];
|
||||
|
||||
m_sync.atomic_op([](squeue_sync_var_t& sync)
|
||||
{
|
||||
assert(sync.count <= sq_size);
|
||||
assert(sync.position < sq_size);
|
||||
assert(sync.pop_lock);
|
||||
sync.pop_lock = 0;
|
||||
sync.position++;
|
||||
sync.count--;
|
||||
if (sync.position == sq_size)
|
||||
{
|
||||
sync.position = 0;
|
||||
}
|
||||
});
|
||||
|
||||
m_rcv.notify_one();
|
||||
m_wcv.notify_one();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool try_pop(T& data)
|
||||
{
|
||||
static const volatile bool no_wait = true;
|
||||
|
||||
return pop(data, &no_wait);
|
||||
}
|
||||
|
||||
bool peek(T& data, u32 start_pos = 0, const volatile bool* do_exit = nullptr)
|
||||
{
|
||||
assert(start_pos < sq_size);
|
||||
u32 pos = 0;
|
||||
|
||||
while (u32 res = m_sync.atomic_op_sync(SQSVR_OK, [&pos, start_pos](squeue_sync_var_t& sync) -> u32
|
||||
{
|
||||
assert(sync.count <= sq_size);
|
||||
assert(sync.position < sq_size);
|
||||
|
||||
if (sync.count <= start_pos)
|
||||
{
|
||||
return SQSVR_FAILED;
|
||||
}
|
||||
if (sync.pop_lock)
|
||||
{
|
||||
return SQSVR_LOCKED;
|
||||
}
|
||||
|
||||
sync.pop_lock = 1;
|
||||
pos = sync.position + start_pos;
|
||||
return SQSVR_OK;
|
||||
}))
|
||||
{
|
||||
if (res == SQSVR_FAILED && squeue_test_exit(do_exit))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unique_lock<std::mutex> rcv_lock(m_rcv_mutex);
|
||||
m_rcv.wait_for(rcv_lock, std::chrono::milliseconds(1));
|
||||
}
|
||||
|
||||
data = m_data[pos >= sq_size ? pos - sq_size : pos];
|
||||
|
||||
m_sync.atomic_op([](squeue_sync_var_t& sync)
|
||||
{
|
||||
assert(sync.count <= sq_size);
|
||||
assert(sync.position < sq_size);
|
||||
assert(sync.pop_lock);
|
||||
sync.pop_lock = 0;
|
||||
});
|
||||
|
||||
m_rcv.notify_one();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool try_peek(T& data, u32 start_pos = 0)
|
||||
{
|
||||
static const volatile bool no_wait = true;
|
||||
|
||||
return peek(data, start_pos, &no_wait);
|
||||
}
|
||||
|
||||
class squeue_data_t
|
||||
{
|
||||
T* const m_data;
|
||||
const u32 m_pos;
|
||||
const u32 m_count;
|
||||
|
||||
squeue_data_t(T* data, u32 pos, u32 count)
|
||||
: m_data(data)
|
||||
, m_pos(pos)
|
||||
, m_count(count)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
T& operator [] (u32 index)
|
||||
{
|
||||
assert(index < m_count);
|
||||
index += m_pos;
|
||||
index = index < sq_size ? index : index - sq_size;
|
||||
return m_data[index];
|
||||
}
|
||||
};
|
||||
|
||||
void process(void(*proc)(squeue_data_t data))
|
||||
{
|
||||
u32 pos, count;
|
||||
|
||||
while (m_sync.atomic_op_sync(SQSVR_OK, [&pos, &count](squeue_sync_var_t& sync) -> u32
|
||||
{
|
||||
assert(sync.count <= sq_size);
|
||||
assert(sync.position < sq_size);
|
||||
|
||||
if (sync.pop_lock || sync.push_lock)
|
||||
{
|
||||
return SQSVR_LOCKED;
|
||||
}
|
||||
|
||||
pos = sync.position;
|
||||
count = sync.count;
|
||||
sync.pop_lock = 1;
|
||||
sync.push_lock = 1;
|
||||
return SQSVR_OK;
|
||||
}))
|
||||
{
|
||||
std::unique_lock<std::mutex> rcv_lock(m_rcv_mutex);
|
||||
m_rcv.wait_for(rcv_lock, std::chrono::milliseconds(1));
|
||||
}
|
||||
|
||||
proc(squeue_data_t(m_data, pos, count));
|
||||
|
||||
m_sync.atomic_op([](squeue_sync_var_t& sync)
|
||||
{
|
||||
assert(sync.count <= sq_size);
|
||||
assert(sync.position < sq_size);
|
||||
assert(sync.pop_lock && sync.push_lock);
|
||||
sync.pop_lock = 0;
|
||||
sync.push_lock = 0;
|
||||
});
|
||||
|
||||
m_wcv.notify_one();
|
||||
m_rcv.notify_one();
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
while (m_sync.atomic_op_sync(SQSVR_OK, [](squeue_sync_var_t& sync) -> u32
|
||||
{
|
||||
assert(sync.count <= sq_size);
|
||||
assert(sync.position < sq_size);
|
||||
|
||||
if (sync.pop_lock || sync.push_lock)
|
||||
{
|
||||
return SQSVR_LOCKED;
|
||||
}
|
||||
|
||||
sync.pop_lock = 1;
|
||||
sync.push_lock = 1;
|
||||
return SQSVR_OK;
|
||||
}))
|
||||
{
|
||||
std::unique_lock<std::mutex> rcv_lock(m_rcv_mutex);
|
||||
m_rcv.wait_for(rcv_lock, std::chrono::milliseconds(1));
|
||||
}
|
||||
|
||||
m_sync.exchange({});
|
||||
m_wcv.notify_one();
|
||||
m_rcv.notify_one();
|
||||
}
|
||||
};
|
||||
|
2
asmjit
2
asmjit
@ -1 +1 @@
|
||||
Subproject commit 1318c9aff7137b30aec7dee2ababb2b313ae0f06
|
||||
Subproject commit 48da90ded775fa2ba0fd3f15522890ad631ad6de
|
2
ffmpeg
2
ffmpeg
@ -1 +1 @@
|
||||
Subproject commit 352fdfbbfa6d7b26142f00b43d7e1802a03c68a8
|
||||
Subproject commit 79a2d7a9f780ad27d1622010cb1cb8396c3701e9
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
};
|
@ -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
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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,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,4 +1,5 @@
|
||||
#include "stdafx.h"
|
||||
#include "Utilities/Log.h"
|
||||
#include "Emu/System.h"
|
||||
#include "PSVFuncList.h"
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -1,7 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "Emu/SysCalls/Modules/cellSpurs.h"
|
||||
|
||||
class SPURSManagerEventFlag
|
||||
{
|
||||
public:
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
#pragma once
|
||||
#include "Emu/Memory/atomic_type.h"
|
||||
#include "PPCThread.h"
|
||||
#include "Emu/SysCalls/lv2/sleep_queue_type.h"
|
||||
#include "Emu/SysCalls/lv2/sys_event.h"
|
||||
#include "Emu/Event.h"
|
||||
#include "MFC.h"
|
||||
|
||||
@ -281,9 +283,9 @@ public:
|
||||
u64 R_ADDR; // reservation address
|
||||
u64 R_DATA[16]; // lock line data (BE)
|
||||
|
||||
EventPort SPUPs[64]; // SPU Thread Event Ports
|
||||
std::shared_ptr<EventPort> SPUPs[64]; // SPU Thread Event Ports
|
||||
EventManager SPUQs; // SPU Queue Mapping
|
||||
SpuGroupInfo* group; // associated SPU Thread Group (null for raw spu)
|
||||
std::shared_ptr<SpuGroupInfo> group; // associated SPU Thread Group (null for raw spu)
|
||||
|
||||
u64 m_dec_start; // timestamp of writing decrementer value
|
||||
u32 m_dec_value; // written decrementer value
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
};
|
||||
|
@ -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()
|
||||
|
@ -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;
|
||||
|
@ -4,6 +4,7 @@ struct GameInfo
|
||||
{
|
||||
std::string root;
|
||||
|
||||
std::string icon_path;
|
||||
std::string name;
|
||||
std::string serial;
|
||||
std::string app_ver;
|
||||
|
@ -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{};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -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)
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -6,9 +6,9 @@
|
||||
|
||||
void GLFragmentDecompilerThread::SetDst(std::string code, bool append_mask)
|
||||
{
|
||||
if(!src0.exec_if_eq && !src0.exec_if_gr && !src0.exec_if_lt) return;
|
||||
if (!src0.exec_if_eq && !src0.exec_if_gr && !src0.exec_if_lt) return;
|
||||
|
||||
switch(src1.scale)
|
||||
switch (src1.scale)
|
||||
{
|
||||
case 0: break;
|
||||
case 1: code = "(" + code + " * 2.0)"; break;
|
||||
@ -21,27 +21,39 @@ void GLFragmentDecompilerThread::SetDst(std::string code, bool append_mask)
|
||||
default:
|
||||
LOG_ERROR(RSX, "Bad scale: %d", fmt::by_value(src1.scale));
|
||||
Emu.Pause();
|
||||
break;
|
||||
break;
|
||||
}
|
||||
|
||||
if(dst.saturate)
|
||||
if (dst.saturate)
|
||||
{
|
||||
code = "clamp(" + code + ", 0.0, 1.0)";
|
||||
}
|
||||
|
||||
std::string dest;
|
||||
code += (append_mask ? "$m" : "");
|
||||
|
||||
if (dst.no_dest)
|
||||
{
|
||||
if (dst.set_cond)
|
||||
{
|
||||
AddCode("$ifcond " + m_parr.AddParam(PARAM_NONE, "vec4", "cc" + std::to_string(src0.cond_mod_reg_index)) + "$m = " + code + ";");
|
||||
}
|
||||
else
|
||||
{
|
||||
AddCode("$ifcond " + code + ";");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
std::string dest = AddReg(dst.dest_reg, dst.fp16) + "$m";
|
||||
|
||||
AddCodeCond(Format(dest), code);
|
||||
//AddCode("$ifcond " + dest + code + (append_mask ? "$m;" : ";"));
|
||||
|
||||
if (dst.set_cond)
|
||||
{
|
||||
dest += m_parr.AddParam(PARAM_NONE, "vec4", "cc" + std::to_string(src0.cond_mod_reg_index)) + "$m = ";
|
||||
AddCode(m_parr.AddParam(PARAM_NONE, "vec4", "cc" + std::to_string(src0.cond_mod_reg_index)) + "$m = " + dest + ";");
|
||||
}
|
||||
|
||||
if (!dst.no_dest)
|
||||
{
|
||||
dest += AddReg(dst.dest_reg, dst.fp16) + "$m = ";
|
||||
}
|
||||
|
||||
AddCode("$ifcond " + dest + code + (append_mask ? "$m;" : ";"));
|
||||
}
|
||||
|
||||
void GLFragmentDecompilerThread::AddCode(const std::string& code)
|
||||
@ -58,17 +70,17 @@ std::string GLFragmentDecompilerThread::GetMask()
|
||||
'x', 'y', 'z', 'w',
|
||||
};
|
||||
|
||||
if(dst.mask_x) ret += dst_mask[0];
|
||||
if(dst.mask_y) ret += dst_mask[1];
|
||||
if(dst.mask_z) ret += dst_mask[2];
|
||||
if(dst.mask_w) ret += dst_mask[3];
|
||||
if (dst.mask_x) ret += dst_mask[0];
|
||||
if (dst.mask_y) ret += dst_mask[1];
|
||||
if (dst.mask_z) ret += dst_mask[2];
|
||||
if (dst.mask_w) ret += dst_mask[3];
|
||||
|
||||
return ret.empty() || strncmp(ret.c_str(), dst_mask, 4) == 0 ? "" : ("." + ret);
|
||||
}
|
||||
|
||||
std::string GLFragmentDecompilerThread::AddReg(u32 index, int fp16)
|
||||
{
|
||||
return m_parr.AddParam(PARAM_NONE, "vec4", std::string(fp16 ? "h" : "r") + std::to_string(index), "vec4(0.0, 0.0, 0.0, 0.0)");
|
||||
return m_parr.AddParam(PARAM_NONE, "vec4", std::string(fp16 ? "h" : "r") + std::to_string(index), "vec4(0.0)");
|
||||
}
|
||||
|
||||
bool GLFragmentDecompilerThread::HasReg(u32 index, int fp16)
|
||||
@ -79,13 +91,13 @@ bool GLFragmentDecompilerThread::HasReg(u32 index, int fp16)
|
||||
|
||||
std::string GLFragmentDecompilerThread::AddCond()
|
||||
{
|
||||
return m_parr.AddParam(PARAM_NONE , "vec4", "cc" + std::to_string(src0.cond_reg_index));
|
||||
return m_parr.AddParam(PARAM_NONE, "vec4", "cc" + std::to_string(src0.cond_reg_index));
|
||||
}
|
||||
|
||||
std::string GLFragmentDecompilerThread::AddConst()
|
||||
{
|
||||
std::string name = std::string("fc") + std::to_string(m_size + 4 * 4);
|
||||
if(m_parr.HasParam(PARAM_UNIFORM, "vec4", name))
|
||||
if (m_parr.HasParam(PARAM_UNIFORM, "vec4", name))
|
||||
{
|
||||
return name;
|
||||
}
|
||||
@ -118,11 +130,11 @@ std::string GLFragmentDecompilerThread::Format(const std::string& code)
|
||||
{ "$t", std::bind(std::mem_fn(&GLFragmentDecompilerThread::AddTex), this) },
|
||||
{ "$m", std::bind(std::mem_fn(&GLFragmentDecompilerThread::GetMask), this) },
|
||||
{ "$ifcond ", [this]() -> std::string
|
||||
{
|
||||
const std::string& cond = GetCond();
|
||||
if (cond == "true") return "";
|
||||
return "if(" + cond + ") ";
|
||||
}
|
||||
{
|
||||
const std::string& cond = GetCond();
|
||||
if (cond == "true") return "";
|
||||
return "if(" + cond + ") ";
|
||||
}
|
||||
},
|
||||
{ "$cond", std::bind(std::mem_fn(&GLFragmentDecompilerThread::GetCond), this) },
|
||||
{ "$c", std::bind(std::mem_fn(&GLFragmentDecompilerThread::AddConst), this) }
|
||||
@ -179,15 +191,83 @@ std::string GLFragmentDecompilerThread::GetCond()
|
||||
return "any(" + cond + "(" + AddCond() + swizzle + ", vec4(0.0)))";
|
||||
}
|
||||
|
||||
void GLFragmentDecompilerThread::AddCodeCond(const std::string& dst, const std::string& src)
|
||||
{
|
||||
if (src0.exec_if_gr && src0.exec_if_lt && src0.exec_if_eq)
|
||||
{
|
||||
AddCode(dst + " = " + src + ";");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!src0.exec_if_gr && !src0.exec_if_lt && !src0.exec_if_eq)
|
||||
{
|
||||
AddCode("//" + dst + " = " + src + ";");
|
||||
return;
|
||||
}
|
||||
|
||||
static const char f[4] = { 'x', 'y', 'z', 'w' };
|
||||
|
||||
std::string swizzle, cond;
|
||||
swizzle += f[src0.cond_swizzle_x];
|
||||
swizzle += f[src0.cond_swizzle_y];
|
||||
swizzle += f[src0.cond_swizzle_z];
|
||||
swizzle += f[src0.cond_swizzle_w];
|
||||
swizzle = swizzle == "xyzw" ? "" : "." + swizzle;
|
||||
|
||||
if (src0.exec_if_gr && src0.exec_if_eq)
|
||||
{
|
||||
cond = "greaterThanEqual";
|
||||
}
|
||||
else if (src0.exec_if_lt && src0.exec_if_eq)
|
||||
{
|
||||
cond = "lessThanEqual";
|
||||
}
|
||||
else if (src0.exec_if_gr && src0.exec_if_lt)
|
||||
{
|
||||
cond = "notEqual";
|
||||
}
|
||||
else if (src0.exec_if_gr)
|
||||
{
|
||||
cond = "greaterThan";
|
||||
}
|
||||
else if (src0.exec_if_lt)
|
||||
{
|
||||
cond = "lessThan";
|
||||
}
|
||||
else //if(src0.exec_if_eq)
|
||||
{
|
||||
cond = "equal";
|
||||
}
|
||||
|
||||
cond = cond + "(" + AddCond() + swizzle + ", vec4(0.0))";
|
||||
|
||||
ShaderVar dst_var(dst);
|
||||
dst_var.symplify();
|
||||
|
||||
//const char *c_mask = f;
|
||||
|
||||
if (dst_var.swizzles[0].length() == 1)
|
||||
{
|
||||
AddCode("if (" + cond + ".x) " + dst + " = vec4(" + src + ").x;");
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < dst_var.swizzles[0].length(); ++i)
|
||||
{
|
||||
AddCode("if (" + cond + "." + f[i] + ") " + dst + "." + f[i] + " = " + src + "." + f[i] + ";");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T> std::string GLFragmentDecompilerThread::GetSRC(T src)
|
||||
{
|
||||
std::string ret;
|
||||
|
||||
switch(src.reg_type)
|
||||
switch (src.reg_type)
|
||||
{
|
||||
case 0: //tmp
|
||||
ret += AddReg(src.tmp_reg_index, src.fp16);
|
||||
break;
|
||||
break;
|
||||
|
||||
case 1: //input
|
||||
{
|
||||
@ -200,11 +280,11 @@ template<typename T> std::string GLFragmentDecompilerThread::GetSRC(T src)
|
||||
"ssa"
|
||||
};
|
||||
|
||||
switch(dst.src_attr_reg_num)
|
||||
switch (dst.src_attr_reg_num)
|
||||
{
|
||||
case 0x00: ret += reg_table[0]; break;
|
||||
default:
|
||||
if(dst.src_attr_reg_num < sizeof(reg_table)/sizeof(reg_table[0]))
|
||||
if (dst.src_attr_reg_num < sizeof(reg_table) / sizeof(reg_table[0]))
|
||||
{
|
||||
ret += m_parr.AddParam(PARAM_IN, "vec4", reg_table[dst.src_attr_reg_num]);
|
||||
}
|
||||
@ -214,22 +294,22 @@ template<typename T> std::string GLFragmentDecompilerThread::GetSRC(T src)
|
||||
ret += m_parr.AddParam(PARAM_IN, "vec4", "unk");
|
||||
Emu.Pause();
|
||||
}
|
||||
break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: //const
|
||||
ret += AddConst();
|
||||
break;
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_ERROR(RSX, "Bad src type %d", fmt::by_value(src.reg_type));
|
||||
Emu.Pause();
|
||||
break;
|
||||
break;
|
||||
}
|
||||
|
||||
static const char f[4] = {'x', 'y', 'z', 'w'};
|
||||
static const char f[4] = { 'x', 'y', 'z', 'w' };
|
||||
|
||||
std::string swizzle = "";
|
||||
swizzle += f[src.swizzle_x];
|
||||
@ -237,10 +317,10 @@ template<typename T> std::string GLFragmentDecompilerThread::GetSRC(T src)
|
||||
swizzle += f[src.swizzle_z];
|
||||
swizzle += f[src.swizzle_w];
|
||||
|
||||
if(strncmp(swizzle.c_str(), f, 4) != 0) ret += "." + swizzle;
|
||||
if (strncmp(swizzle.c_str(), f, 4) != 0) ret += "." + swizzle;
|
||||
|
||||
if(src.abs) ret = "abs(" + ret + ")";
|
||||
if(src.neg) ret = "-" + ret;
|
||||
if (src.abs) ret = "abs(" + ret + ")";
|
||||
if (src.neg) ret = "-" + ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -251,10 +331,9 @@ std::string GLFragmentDecompilerThread::BuildCode()
|
||||
const std::pair<std::string, std::string> table[] =
|
||||
{
|
||||
{ "ocol0", m_ctrl & 0x40 ? "r0" : "h0" },
|
||||
{ "ocol1", m_ctrl & 0x40 ? "r2" : "h2" },
|
||||
{ "ocol2", m_ctrl & 0x40 ? "r3" : "h4" },
|
||||
{ "ocol3", m_ctrl & 0x40 ? "r4" : "h6" },
|
||||
{ "ocol4", m_ctrl & 0x40 ? "r5" : "h8" },
|
||||
{ "ocol1", m_ctrl & 0x40 ? "r2" : "h4" },
|
||||
{ "ocol2", m_ctrl & 0x40 ? "r3" : "h6" },
|
||||
{ "ocol3", m_ctrl & 0x40 ? "r4" : "h8" },
|
||||
};
|
||||
|
||||
for (int i = 0; i < sizeof(table) / sizeof(*table); ++i)
|
||||
@ -263,7 +342,7 @@ std::string GLFragmentDecompilerThread::BuildCode()
|
||||
AddCode(m_parr.AddParam(PARAM_OUT, "vec4", table[i].first, i) + " = " + table[i].second + ";");
|
||||
}
|
||||
|
||||
if (m_ctrl & 0xe) main += "\tgl_FragDepth = r1.z;\n";
|
||||
if (m_ctrl & 0xe) main += m_ctrl & 0x40 ? "\tgl_FragDepth = r1.z;\n" : "\tgl_FragDepth = h2.z;\n";
|
||||
|
||||
std::string p;
|
||||
|
||||
@ -285,7 +364,16 @@ void GLFragmentDecompilerThread::Task()
|
||||
m_loop_count = 0;
|
||||
m_code_level = 1;
|
||||
|
||||
while(true)
|
||||
enum
|
||||
{
|
||||
FORCE_NONE,
|
||||
FORCE_SCT,
|
||||
FORCE_SCB,
|
||||
};
|
||||
|
||||
int forced_unit = FORCE_NONE;
|
||||
|
||||
while (true)
|
||||
{
|
||||
for (auto finded = std::find(m_end_offsets.begin(), m_end_offsets.end(), m_size);
|
||||
finded != m_end_offsets.end();
|
||||
@ -318,126 +406,201 @@ void GLFragmentDecompilerThread::Task()
|
||||
|
||||
const u32 opcode = dst.opcode | (src1.opcode_is_branch << 6);
|
||||
|
||||
switch(opcode)
|
||||
auto SCT = [&]()
|
||||
{
|
||||
switch (opcode)
|
||||
{
|
||||
case RSX_FP_OPCODE_ADD: SetDst("($0 + $1)"); break;
|
||||
case RSX_FP_OPCODE_DIV: SetDst("($0 / $1)"); break;
|
||||
case RSX_FP_OPCODE_DIVSQ: SetDst("($0 / sqrt($1))"); break;
|
||||
case RSX_FP_OPCODE_DP2: SetDst("vec4(dot($0.xy, $1.xy))"); break;
|
||||
case RSX_FP_OPCODE_DP3: SetDst("vec4(dot($0.xyz, $1.xyz))"); break;
|
||||
case RSX_FP_OPCODE_DP4: SetDst("vec4(dot($0, $1))"); break;
|
||||
case RSX_FP_OPCODE_DP2A: SetDst("vec4($0.x * $1.x + $0.y * $1.y + $2.x)"); break;
|
||||
case RSX_FP_OPCODE_MAD: SetDst("($0 * $1 + $2)"); break;
|
||||
case RSX_FP_OPCODE_MAX: SetDst("max($0, $1)"); break;
|
||||
case RSX_FP_OPCODE_MIN: SetDst("min($0, $1)"); break;
|
||||
case RSX_FP_OPCODE_MOV: SetDst("$0"); break;
|
||||
case RSX_FP_OPCODE_MUL: SetDst("($0 * $1)"); break;
|
||||
case RSX_FP_OPCODE_RCP: SetDst("1 / $0"); break;
|
||||
case RSX_FP_OPCODE_RSQ: SetDst("inversesqrt(abs($0))"); break;
|
||||
case RSX_FP_OPCODE_SEQ: SetDst("vec4(equal($0, $1))"); break;
|
||||
case RSX_FP_OPCODE_SFL: SetDst("vec4(0.0)"); break;
|
||||
case RSX_FP_OPCODE_SGE: SetDst("vec4(greaterThanEqual($0, $1))"); break;
|
||||
case RSX_FP_OPCODE_SGT: SetDst("vec4(greaterThan($0, $1))"); break;
|
||||
case RSX_FP_OPCODE_SLE: SetDst("vec4(lessThanEqual($0, $1))"); break;
|
||||
case RSX_FP_OPCODE_SLT: SetDst("vec4(lessThan($0, $1))"); break;
|
||||
case RSX_FP_OPCODE_SNE: SetDst("vec4(notEqual($0, $1))"); break;
|
||||
case RSX_FP_OPCODE_STR: SetDst("vec4(1.0)"); break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
auto SCB = [&]()
|
||||
{
|
||||
switch (opcode)
|
||||
{
|
||||
case RSX_FP_OPCODE_ADD: SetDst("($0 + $1)"); break;
|
||||
case RSX_FP_OPCODE_COS: SetDst("cos($0)"); break;
|
||||
case RSX_FP_OPCODE_DP2: SetDst("vec4(dot($0.xy, $1.xy))"); break;
|
||||
case RSX_FP_OPCODE_DP3: SetDst("vec4(dot($0.xyz, $1.xyz))"); break;
|
||||
case RSX_FP_OPCODE_DP4: SetDst("vec4(dot($0, $1))"); break;
|
||||
case RSX_FP_OPCODE_DP2A: SetDst("vec4($0.x * $1.x + $0.y * $1.y + $2.x)"); break;
|
||||
case RSX_FP_OPCODE_DST: SetDst("vec4(distance($0, $1))"); break;
|
||||
case RSX_FP_OPCODE_REFL: LOG_ERROR(RSX, "Unimplemented SCB instruction: REFL"); break; // TODO: Is this in the right category?
|
||||
case RSX_FP_OPCODE_EX2: SetDst("exp2($0)"); break;
|
||||
case RSX_FP_OPCODE_FLR: SetDst("floor($0)"); break;
|
||||
case RSX_FP_OPCODE_FRC: SetDst("fract($0)"); break;
|
||||
case RSX_FP_OPCODE_LIT: SetDst("vec4(1.0, $0.x, ($0.x > 0.0 ? exp($0.w * log2($0.y)) : 0.0), 1.0)"); break;
|
||||
case RSX_FP_OPCODE_LIF: SetDst("vec4(1.0, $0.y, ($0.y > 0 ? pow(2.0, $0.w) : 0.0), 1.0)"); break;
|
||||
case RSX_FP_OPCODE_LRP: LOG_ERROR(RSX, "Unimplemented SCB instruction: LRP"); break; // TODO: Is this in the right category?
|
||||
case RSX_FP_OPCODE_LG2: SetDst("log2($0)"); break;
|
||||
case RSX_FP_OPCODE_MAD: SetDst("($0 * $1 + $2)"); break;
|
||||
case RSX_FP_OPCODE_MAX: SetDst("max($0, $1)"); break;
|
||||
case RSX_FP_OPCODE_MIN: SetDst("min($0, $1)"); break;
|
||||
case RSX_FP_OPCODE_MOV: SetDst("$0"); break;
|
||||
case RSX_FP_OPCODE_MUL: SetDst("($0 * $1)"); break;
|
||||
case RSX_FP_OPCODE_PK2: SetDst("packSnorm2x16($0)"); break; // TODO: More testing (Sonic The Hedgehog (NPUB-30442/NPEB-00478))
|
||||
case RSX_FP_OPCODE_PK4: SetDst("packSnorm4x8($0)"); break; // TODO: More testing (Sonic The Hedgehog (NPUB-30442/NPEB-00478))
|
||||
case RSX_FP_OPCODE_PK16: LOG_ERROR(RSX, "Unimplemented SCB instruction: PK16"); break;
|
||||
case RSX_FP_OPCODE_PKB: LOG_ERROR(RSX, "Unimplemented SCB instruction: PKB"); break;
|
||||
case RSX_FP_OPCODE_PKG: LOG_ERROR(RSX, "Unimplemented SCB instruction: PKG"); break;
|
||||
case RSX_FP_OPCODE_SEQ: SetDst("vec4(equal($0, $1))"); break;
|
||||
case RSX_FP_OPCODE_SFL: SetDst("vec4(0.0)"); break;
|
||||
case RSX_FP_OPCODE_SGE: SetDst("vec4(greaterThanEqual($0, $1))"); break;
|
||||
case RSX_FP_OPCODE_SGT: SetDst("vec4(greaterThan($0, $1))"); break;
|
||||
case RSX_FP_OPCODE_SIN: SetDst("sin($0)"); break;
|
||||
case RSX_FP_OPCODE_SLE: SetDst("vec4(lessThanEqual($0, $1))"); break;
|
||||
case RSX_FP_OPCODE_SLT: SetDst("vec4(lessThan($0, $1))"); break;
|
||||
case RSX_FP_OPCODE_SNE: SetDst("vec4(notEqual($0, $1))"); break;
|
||||
case RSX_FP_OPCODE_STR: SetDst("vec4(1.0)"); break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
auto TEX_SRB = [&]()
|
||||
{
|
||||
switch (opcode)
|
||||
{
|
||||
case RSX_FP_OPCODE_DDX: SetDst("dFdx($0)"); break;
|
||||
case RSX_FP_OPCODE_DDY: SetDst("dFdy($0)"); break;
|
||||
case RSX_FP_OPCODE_NRM: SetDst("normalize($0)"); break;
|
||||
case RSX_FP_OPCODE_BEM: LOG_ERROR(RSX, "Unimplemented TEX_SRB instruction: BEM"); break;
|
||||
case RSX_FP_OPCODE_TEX: SetDst("texture($t, $0.xy)"); break;
|
||||
case RSX_FP_OPCODE_TEXBEM: LOG_ERROR(RSX, "Unimplemented TEX_SRB instruction: TEXBEM"); break;
|
||||
case RSX_FP_OPCODE_TXP: SetDst("textureProj($t, $0.xy, $1)"); break; //TODO: More testing (Sonic The Hedgehog (NPUB-30442/NPEB-00478) and The Simpsons Arcade Game (NPUB30563))
|
||||
case RSX_FP_OPCODE_TXPBEM: LOG_ERROR(RSX, "Unimplemented TEX_SRB instruction: TXPBEM"); break;
|
||||
case RSX_FP_OPCODE_TXD: LOG_ERROR(RSX, "Unimplemented TEX_SRB instruction: TXD"); break;
|
||||
case RSX_FP_OPCODE_TXB: SetDst("texture($t, $0.xy, $1.x)"); break;
|
||||
case RSX_FP_OPCODE_TXL: SetDst("textureLod($t, $0.xy, $1.x)"); break;
|
||||
case RSX_FP_OPCODE_UP2: SetDst("unpackSnorm2x16($0)"); break; // TODO: More testing (Sonic The Hedgehog (NPUB-30442/NPEB-00478))
|
||||
case RSX_FP_OPCODE_UP4: SetDst("unpackSnorm4x8($0)"); break; // TODO: More testing (Sonic The Hedgehog (NPUB-30442/NPEB-00478))
|
||||
case RSX_FP_OPCODE_UP16: LOG_ERROR(RSX, "Unimplemented TEX_SRB instruction: UP16"); break;
|
||||
case RSX_FP_OPCODE_UPB: LOG_ERROR(RSX, "Unimplemented TEX_SRB instruction: UPB"); break;
|
||||
case RSX_FP_OPCODE_UPG: LOG_ERROR(RSX, "Unimplemented TEX_SRB instruction: UPG"); break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
auto SIP = [&]()
|
||||
{
|
||||
switch (opcode)
|
||||
{
|
||||
case RSX_FP_OPCODE_BRK: SetDst("break"); break;
|
||||
case RSX_FP_OPCODE_CAL: LOG_ERROR(RSX, "Unimplemented SIP instruction: CAL"); break;
|
||||
case RSX_FP_OPCODE_FENCT: forced_unit = FORCE_SCT; break;
|
||||
case RSX_FP_OPCODE_FENCB: forced_unit = FORCE_SCB; break;
|
||||
case RSX_FP_OPCODE_IFE:
|
||||
AddCode("if($cond)");
|
||||
m_else_offsets.push_back(src1.else_offset << 2);
|
||||
m_end_offsets.push_back(src2.end_offset << 2);
|
||||
AddCode("{");
|
||||
m_code_level++;
|
||||
break;
|
||||
case RSX_FP_OPCODE_LOOP:
|
||||
if (!src0.exec_if_eq && !src0.exec_if_gr && !src0.exec_if_lt)
|
||||
{
|
||||
AddCode(fmt::Format("$ifcond for(int i%u = %u; i%u < %u; i%u += %u) {} //-> %u //LOOP",
|
||||
m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment, src2.end_offset));
|
||||
}
|
||||
else
|
||||
{
|
||||
AddCode(fmt::Format("$ifcond for(int i%u = %u; i%u < %u; i%u += %u) //LOOP",
|
||||
m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment));
|
||||
m_loop_count++;
|
||||
m_end_offsets.push_back(src2.end_offset << 2);
|
||||
AddCode("{");
|
||||
m_code_level++;
|
||||
}
|
||||
break;
|
||||
case RSX_FP_OPCODE_REP:
|
||||
if (!src0.exec_if_eq && !src0.exec_if_gr && !src0.exec_if_lt)
|
||||
{
|
||||
AddCode(fmt::Format("$ifcond for(int i%u = %u; i%u < %u; i%u += %u) {} //-> %u //REP",
|
||||
m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment, src2.end_offset));
|
||||
}
|
||||
else
|
||||
{
|
||||
AddCode(fmt::Format("if($cond) for(int i%u = %u; i%u < %u; i%u += %u) //REP",
|
||||
m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment));
|
||||
m_loop_count++;
|
||||
m_end_offsets.push_back(src2.end_offset << 2);
|
||||
AddCode("{");
|
||||
m_code_level++;
|
||||
}
|
||||
break;
|
||||
case RSX_FP_OPCODE_RET: SetDst("return"); break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
switch (opcode)
|
||||
{
|
||||
case RSX_FP_OPCODE_NOP: break;
|
||||
case RSX_FP_OPCODE_MOV: SetDst("$0"); break;
|
||||
case RSX_FP_OPCODE_MUL: SetDst("($0 * $1)"); break;
|
||||
case RSX_FP_OPCODE_ADD: SetDst("($0 + $1)"); break;
|
||||
case RSX_FP_OPCODE_MAD: SetDst("($0 * $1 + $2)"); break;
|
||||
case RSX_FP_OPCODE_DP3: SetDst("vec4(dot($0.xyz, $1.xyz))"); break;
|
||||
case RSX_FP_OPCODE_DP4: SetDst("vec4(dot($0, $1))"); break;
|
||||
case RSX_FP_OPCODE_DST: SetDst("vec4(distance($0, $1))"); break;
|
||||
case RSX_FP_OPCODE_MIN: SetDst("min($0, $1)"); break;
|
||||
case RSX_FP_OPCODE_MAX: SetDst("max($0, $1)"); break;
|
||||
case RSX_FP_OPCODE_SLT: SetDst("vec4(lessThan($0, $1))"); break;
|
||||
case RSX_FP_OPCODE_SGE: SetDst("vec4(greaterThanEqual($0, $1))"); break;
|
||||
case RSX_FP_OPCODE_SLE: SetDst("vec4(lessThanEqual($0, $1))"); break;
|
||||
case RSX_FP_OPCODE_SGT: SetDst("vec4(greaterThan($0, $1))"); break;
|
||||
case RSX_FP_OPCODE_SNE: SetDst("vec4(notEqual($0, $1))"); break;
|
||||
case RSX_FP_OPCODE_SEQ: SetDst("vec4(equal($0, $1))"); break;
|
||||
|
||||
case RSX_FP_OPCODE_FRC: SetDst("fract($0)"); break;
|
||||
case RSX_FP_OPCODE_FLR: SetDst("floor($0)"); break;
|
||||
case RSX_FP_OPCODE_KIL: SetDst("discard", false); break;
|
||||
//case RSX_FP_OPCODE_PK4: break;
|
||||
//case RSX_FP_OPCODE_UP4: break;
|
||||
case RSX_FP_OPCODE_DDX: SetDst("dFdx($0)"); break;
|
||||
case RSX_FP_OPCODE_DDY: SetDst("dFdy($0)"); break;
|
||||
case RSX_FP_OPCODE_TEX: SetDst("texture($t, $0.xy)"); break;
|
||||
//case RSX_FP_OPCODE_TXP: break;
|
||||
//case RSX_FP_OPCODE_TXD: break;
|
||||
case RSX_FP_OPCODE_RCP: SetDst("(1 / $0)"); break;
|
||||
case RSX_FP_OPCODE_RSQ: SetDst("inversesqrt(abs($0))"); break;
|
||||
case RSX_FP_OPCODE_EX2: SetDst("exp2($0)"); break;
|
||||
case RSX_FP_OPCODE_LG2: SetDst("log2($0)"); break;
|
||||
case RSX_FP_OPCODE_LIT: SetDst("vec4(1.0, $0.x, ($0.x > 0 ? exp2($0.w * log2($0.y)) : 0.0), 1.0)"); break;
|
||||
case RSX_FP_OPCODE_LRP: SetDst("($0 * ($1 - $2) + $2)"); break;
|
||||
|
||||
case RSX_FP_OPCODE_STR: SetDst("vec4(equal($0, vec4(1.0)))"); break;
|
||||
case RSX_FP_OPCODE_SFL: SetDst("vec4(equal($0, vec4(0.0)))"); break;
|
||||
case RSX_FP_OPCODE_COS: SetDst("cos($0)"); break;
|
||||
case RSX_FP_OPCODE_SIN: SetDst("sin($0)"); break;
|
||||
//case RSX_FP_OPCODE_PK2: break;
|
||||
//case RSX_FP_OPCODE_UP2: break;
|
||||
case RSX_FP_OPCODE_POW: SetDst("pow($0, $1)"); break;
|
||||
//case RSX_FP_OPCODE_PKB: break;
|
||||
//case RSX_FP_OPCODE_UPB: break;
|
||||
//case RSX_FP_OPCODE_PK16: break;
|
||||
//case RSX_FP_OPCODE_UP16: break;
|
||||
//case RSX_FP_OPCODE_BEM: break;
|
||||
//case RSX_FP_OPCODE_PKG: break;
|
||||
//case RSX_FP_OPCODE_UPG: break;
|
||||
case RSX_FP_OPCODE_DP2A: SetDst("($0.x * $1.x + $0.y * $1.y + $2.x)"); break;
|
||||
//case RSX_FP_OPCODE_TXL: break;
|
||||
|
||||
//case RSX_FP_OPCODE_TXB: break;
|
||||
//case RSX_FP_OPCODE_TEXBEM: break;
|
||||
//case RSX_FP_OPCODE_TXPBEM: break;
|
||||
//case RSX_FP_OPCODE_BEMLUM: break;
|
||||
case RSX_FP_OPCODE_REFL: SetDst("($0 - 2.0 * $1 * dot($0, $1))"); break;
|
||||
//case RSX_FP_OPCODE_TIMESWTEX: break;
|
||||
case RSX_FP_OPCODE_DP2: SetDst("vec4(dot($0.xy, $1.xy))"); break;
|
||||
case RSX_FP_OPCODE_NRM: SetDst("normalize($0.xyz)"); break;
|
||||
case RSX_FP_OPCODE_DIV: SetDst("($0 / $1)"); break;
|
||||
case RSX_FP_OPCODE_DIVSQ: SetDst("($0 / sqrt($1))"); break;
|
||||
case RSX_FP_OPCODE_LIF: SetDst("vec4(1.0, $0.y, ($0.y > 0 ? pow(2.0, $0.w) : 0.0), 1.0)"); break;
|
||||
case RSX_FP_OPCODE_FENCT: break;
|
||||
case RSX_FP_OPCODE_FENCB: break;
|
||||
|
||||
case RSX_FP_OPCODE_BRK: SetDst("break"); break;
|
||||
//case RSX_FP_OPCODE_CAL: break;
|
||||
case RSX_FP_OPCODE_IFE:
|
||||
AddCode("if($cond)");
|
||||
m_else_offsets.push_back(src1.else_offset << 2);
|
||||
m_end_offsets.push_back(src2.end_offset << 2);
|
||||
AddCode("{");
|
||||
m_code_level++;
|
||||
break;
|
||||
|
||||
case RSX_FP_OPCODE_LOOP:
|
||||
if(!src0.exec_if_eq && !src0.exec_if_gr && !src0.exec_if_lt)
|
||||
{
|
||||
AddCode(fmt::Format("$ifcond for(int i%u = %u; i%u < %u; i%u += %u) {} //-> %u //LOOP",
|
||||
m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment, src2.end_offset));
|
||||
}
|
||||
else
|
||||
{
|
||||
AddCode(fmt::Format("$ifcond for(int i%u = %u; i%u < %u; i%u += %u) //LOOP",
|
||||
m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment));
|
||||
m_loop_count++;
|
||||
m_end_offsets.push_back(src2.end_offset << 2);
|
||||
AddCode("{");
|
||||
m_code_level++;
|
||||
}
|
||||
break;
|
||||
case RSX_FP_OPCODE_REP:
|
||||
if(!src0.exec_if_eq && !src0.exec_if_gr && !src0.exec_if_lt)
|
||||
{
|
||||
AddCode(fmt::Format("$ifcond for(int i%u = %u; i%u < %u; i%u += %u) {} //-> %u //REP",
|
||||
m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment, src2.end_offset));
|
||||
}
|
||||
else
|
||||
{
|
||||
AddCode(fmt::Format("if($cond) for(int i%u = %u; i%u < %u; i%u += %u) //REP",
|
||||
m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment));
|
||||
m_loop_count++;
|
||||
m_end_offsets.push_back(src2.end_offset << 2);
|
||||
AddCode("{");
|
||||
m_code_level++;
|
||||
}
|
||||
break;
|
||||
//case RSX_FP_OPCODE_RET: SetDst("return"); break;
|
||||
|
||||
default:
|
||||
LOG_ERROR(RSX, "Unknown fp opcode 0x%x (inst %d)", opcode, m_size / (4 * 4));
|
||||
//Emu.Pause();
|
||||
break;
|
||||
if (forced_unit == FORCE_NONE)
|
||||
{
|
||||
if (SIP()) break;
|
||||
if (SCT()) break;
|
||||
if (TEX_SRB()) break;
|
||||
if (SCB()) break;
|
||||
}
|
||||
else if (forced_unit == FORCE_SCT)
|
||||
{
|
||||
forced_unit = FORCE_NONE;
|
||||
if (SCT()) break;
|
||||
}
|
||||
else if (forced_unit == FORCE_SCB)
|
||||
{
|
||||
forced_unit = FORCE_NONE;
|
||||
if (SCB()) break;
|
||||
}
|
||||
|
||||
LOG_ERROR(RSX, "Unknown/illegal instruction: 0x%x (forced unit %d)", opcode, forced_unit);
|
||||
break;
|
||||
}
|
||||
|
||||
m_size += m_offset;
|
||||
|
||||
if(dst.end) break;
|
||||
if (dst.end) break;
|
||||
|
||||
assert(m_offset % sizeof(u32) == 0);
|
||||
data += m_offset / sizeof(u32);
|
||||
@ -450,18 +613,18 @@ void GLFragmentDecompilerThread::Task()
|
||||
m_parr.params.clear();
|
||||
}
|
||||
|
||||
GLShaderProgram::GLShaderProgram()
|
||||
GLFragmentProgram::GLFragmentProgram()
|
||||
: m_decompiler_thread(nullptr)
|
||||
, m_id(0)
|
||||
, id(0)
|
||||
{
|
||||
}
|
||||
|
||||
GLShaderProgram::~GLShaderProgram()
|
||||
GLFragmentProgram::~GLFragmentProgram()
|
||||
{
|
||||
if(m_decompiler_thread)
|
||||
if (m_decompiler_thread)
|
||||
{
|
||||
Wait();
|
||||
if(m_decompiler_thread->IsAlive())
|
||||
if (m_decompiler_thread->IsAlive())
|
||||
{
|
||||
m_decompiler_thread->Stop();
|
||||
}
|
||||
@ -473,26 +636,26 @@ GLShaderProgram::~GLShaderProgram()
|
||||
Delete();
|
||||
}
|
||||
|
||||
void GLShaderProgram::Wait()
|
||||
void GLFragmentProgram::Wait()
|
||||
{
|
||||
if(m_decompiler_thread && m_decompiler_thread->IsAlive())
|
||||
if (m_decompiler_thread && m_decompiler_thread->IsAlive())
|
||||
{
|
||||
m_decompiler_thread->Join();
|
||||
}
|
||||
}
|
||||
|
||||
void GLShaderProgram::Decompile(RSXShaderProgram& prog)
|
||||
void GLFragmentProgram::Decompile(RSXFragmentProgram& prog)
|
||||
{
|
||||
GLFragmentDecompilerThread decompiler(m_shader, m_parr, prog.addr, prog.size, prog.ctrl);
|
||||
GLFragmentDecompilerThread decompiler(shader, parr, prog.addr, prog.size, prog.ctrl);
|
||||
decompiler.Task();
|
||||
}
|
||||
|
||||
void GLShaderProgram::DecompileAsync(RSXShaderProgram& prog)
|
||||
void GLFragmentProgram::DecompileAsync(RSXFragmentProgram& prog)
|
||||
{
|
||||
if(m_decompiler_thread)
|
||||
if (m_decompiler_thread)
|
||||
{
|
||||
Wait();
|
||||
if(m_decompiler_thread->IsAlive())
|
||||
if (m_decompiler_thread->IsAlive())
|
||||
{
|
||||
m_decompiler_thread->Stop();
|
||||
}
|
||||
@ -501,65 +664,68 @@ void GLShaderProgram::DecompileAsync(RSXShaderProgram& prog)
|
||||
m_decompiler_thread = nullptr;
|
||||
}
|
||||
|
||||
m_decompiler_thread = new GLFragmentDecompilerThread(m_shader, m_parr, prog.addr, prog.size, prog.ctrl);
|
||||
m_decompiler_thread = new GLFragmentDecompilerThread(shader, parr, prog.addr, prog.size, prog.ctrl);
|
||||
m_decompiler_thread->Start();
|
||||
}
|
||||
|
||||
void GLShaderProgram::Compile()
|
||||
void GLFragmentProgram::Compile()
|
||||
{
|
||||
if (m_id) glDeleteShader(m_id);
|
||||
if (id)
|
||||
{
|
||||
glDeleteShader(id);
|
||||
}
|
||||
|
||||
m_id = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
id = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
|
||||
const char* str = m_shader.c_str();
|
||||
const int strlen = m_shader.length();
|
||||
const char* str = shader.c_str();
|
||||
const int strlen = shader.length();
|
||||
|
||||
glShaderSource(m_id, 1, &str, &strlen);
|
||||
glCompileShader(m_id);
|
||||
glShaderSource(id, 1, &str, &strlen);
|
||||
glCompileShader(id);
|
||||
|
||||
GLint compileStatus = GL_FALSE;
|
||||
glGetShaderiv(m_id, GL_COMPILE_STATUS, &compileStatus); // Determine the result of the glCompileShader call
|
||||
glGetShaderiv(id, GL_COMPILE_STATUS, &compileStatus); // Determine the result of the glCompileShader call
|
||||
if (compileStatus != GL_TRUE) // If the shader failed to compile...
|
||||
{
|
||||
GLint infoLength;
|
||||
glGetShaderiv(m_id, GL_INFO_LOG_LENGTH, &infoLength); // Retrieve the length in bytes (including trailing NULL) of the shader info log
|
||||
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &infoLength); // Retrieve the length in bytes (including trailing NULL) of the shader info log
|
||||
|
||||
if (infoLength > 0)
|
||||
{
|
||||
GLsizei len;
|
||||
char* buf = new char[infoLength]; // Buffer to store infoLog
|
||||
|
||||
glGetShaderInfoLog(m_id, infoLength, &len, buf); // Retrieve the shader info log into our buffer
|
||||
glGetShaderInfoLog(id, infoLength, &len, buf); // Retrieve the shader info log into our buffer
|
||||
LOG_ERROR(RSX, "Failed to compile shader: %s", buf); // Write log to the console
|
||||
|
||||
delete[] buf;
|
||||
}
|
||||
|
||||
LOG_NOTICE(RSX, m_shader.c_str()); // Log the text of the shader that failed to compile
|
||||
LOG_NOTICE(RSX, shader.c_str()); // Log the text of the shader that failed to compile
|
||||
Emu.Pause(); // Pause the emulator, we can't really continue from here
|
||||
}
|
||||
}
|
||||
|
||||
void GLShaderProgram::Delete()
|
||||
void GLFragmentProgram::Delete()
|
||||
{
|
||||
for (auto& param : m_parr.params) {
|
||||
for (auto& param : parr.params) {
|
||||
param.items.clear();
|
||||
param.type.clear();
|
||||
}
|
||||
|
||||
m_parr.params.clear();
|
||||
m_shader.clear();
|
||||
parr.params.clear();
|
||||
shader.clear();
|
||||
|
||||
if (m_id)
|
||||
if (id)
|
||||
{
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
LOG_WARNING(RSX, "GLShaderProgram::Delete(): glDeleteShader(%d) avoided", m_id);
|
||||
LOG_WARNING(RSX, "GLFragmentProgram::Delete(): glDeleteShader(%d) avoided", id);
|
||||
}
|
||||
else
|
||||
{
|
||||
glDeleteShader(m_id);
|
||||
glDeleteShader(id);
|
||||
}
|
||||
m_id = 0;
|
||||
id = 0;
|
||||
}
|
||||
}
|
||||
|
@ -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
@ -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();
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -24,5 +24,6 @@ public:
|
||||
void Use();
|
||||
void UnUse();
|
||||
void SetTex(u32 index);
|
||||
void SetVTex(u32 index);
|
||||
void Delete();
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
};
|
||||
|
@ -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 ¶ms[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 }, ".");
|
||||
}
|
||||
};
|
@ -8,19 +8,19 @@ std::string GLVertexDecompilerThread::GetMask(bool is_sca)
|
||||
{
|
||||
std::string ret;
|
||||
|
||||
if(is_sca)
|
||||
if (is_sca)
|
||||
{
|
||||
if(d3.sca_writemask_x) ret += "x";
|
||||
if(d3.sca_writemask_y) ret += "y";
|
||||
if(d3.sca_writemask_z) ret += "z";
|
||||
if(d3.sca_writemask_w) ret += "w";
|
||||
if (d3.sca_writemask_x) ret += "x";
|
||||
if (d3.sca_writemask_y) ret += "y";
|
||||
if (d3.sca_writemask_z) ret += "z";
|
||||
if (d3.sca_writemask_w) ret += "w";
|
||||
}
|
||||
else
|
||||
{
|
||||
if(d3.vec_writemask_x) ret += "x";
|
||||
if(d3.vec_writemask_y) ret += "y";
|
||||
if(d3.vec_writemask_z) ret += "z";
|
||||
if(d3.vec_writemask_w) ret += "w";
|
||||
if (d3.vec_writemask_x) ret += "x";
|
||||
if (d3.vec_writemask_y) ret += "y";
|
||||
if (d3.vec_writemask_z) ret += "z";
|
||||
if (d3.vec_writemask_w) ret += "w";
|
||||
}
|
||||
|
||||
return ret.empty() || ret == "xyzw" ? "" : ("." + ret);
|
||||
@ -40,17 +40,17 @@ std::string GLVertexDecompilerThread::GetDST(bool isSca)
|
||||
{
|
||||
std::string ret;
|
||||
|
||||
switch(isSca ? 0x1f : d3.dst)
|
||||
switch (isSca ? 0x1f : d3.dst)
|
||||
{
|
||||
case 0x1f:
|
||||
ret += m_parr.AddParam(PARAM_NONE, "vec4", std::string("tmp") + std::to_string(isSca ? d3.sca_dst_tmp : d0.dst_tmp));
|
||||
break;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (d3.dst > 15)
|
||||
LOG_ERROR(RSX, "dst index out of range: %u", d3.dst);
|
||||
ret += m_parr.AddParam(PARAM_NONE, "vec4", std::string("dst_reg") + std::to_string(d3.dst), d3.dst == 0 ? "vec4(0.0f, 0.0f, 0.0f, 1.0f)" : "vec4(0.0)");
|
||||
break;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
@ -70,13 +70,13 @@ std::string GLVertexDecompilerThread::GetSRC(const u32 n)
|
||||
|
||||
std::string ret;
|
||||
|
||||
switch(src[n].reg_type)
|
||||
switch (src[n].reg_type)
|
||||
{
|
||||
case 1: //temp
|
||||
ret += m_parr.AddParam(PARAM_NONE, "vec4", "tmp" + std::to_string(src[n].tmp_src));
|
||||
break;
|
||||
break;
|
||||
case 2: //input
|
||||
if (d1.input_src < (sizeof(reg_table)/sizeof(reg_table[0])))
|
||||
if (d1.input_src < (sizeof(reg_table) / sizeof(reg_table[0])))
|
||||
{
|
||||
ret += m_parr.AddParam(PARAM_IN, "vec4", reg_table[d1.input_src], d1.input_src);
|
||||
}
|
||||
@ -85,16 +85,16 @@ std::string GLVertexDecompilerThread::GetSRC(const u32 n)
|
||||
LOG_ERROR(RSX, "Bad input src num: %d", fmt::by_value(d1.input_src));
|
||||
ret += m_parr.AddParam(PARAM_IN, "vec4", "in_unk", d1.input_src);
|
||||
}
|
||||
break;
|
||||
break;
|
||||
case 3: //const
|
||||
m_parr.AddParam(PARAM_UNIFORM, "vec4", std::string("vc[468]"));
|
||||
ret += std::string("vc[") + std::to_string(d1.const_src) + (d3.index_const ? " + " + AddAddrReg() : "") + "]";
|
||||
break;
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_ERROR(RSX, "Bad src%u reg type: %d", n, fmt::by_value(src[n].reg_type));
|
||||
Emu.Pause();
|
||||
break;
|
||||
break;
|
||||
}
|
||||
|
||||
static const std::string f = "xyzw";
|
||||
@ -106,26 +106,26 @@ std::string GLVertexDecompilerThread::GetSRC(const u32 n)
|
||||
swizzle += f[src[n].swz_z];
|
||||
swizzle += f[src[n].swz_w];
|
||||
|
||||
if(swizzle != f) ret += '.' + swizzle;
|
||||
if (swizzle != f) ret += '.' + swizzle;
|
||||
|
||||
bool abs;
|
||||
|
||||
switch(n)
|
||||
switch (n)
|
||||
{
|
||||
case 0: abs = d0.src0_abs; break;
|
||||
case 1: abs = d0.src1_abs; break;
|
||||
case 2: abs = d0.src2_abs; break;
|
||||
}
|
||||
|
||||
if(abs) ret = "abs(" + ret + ")";
|
||||
if(src[n].neg) ret = "-" + ret;
|
||||
if (abs) ret = "abs(" + ret + ")";
|
||||
if (src[n].neg) ret = "-" + ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void GLVertexDecompilerThread::SetDST(bool is_sca, std::string value)
|
||||
{
|
||||
if(d0.cond == 0) return;
|
||||
if (d0.cond == 0) return;
|
||||
|
||||
enum
|
||||
{
|
||||
@ -138,12 +138,12 @@ void GLVertexDecompilerThread::SetDST(bool is_sca, std::string value)
|
||||
|
||||
value += mask;
|
||||
|
||||
if(is_sca && d0.vec_result)
|
||||
if (is_sca && d0.vec_result)
|
||||
{
|
||||
value = "vec4(" + value + ")" + mask;
|
||||
//value = "vec4(" + value + ")";
|
||||
}
|
||||
|
||||
if(d0.staturate)
|
||||
if (d0.staturate)
|
||||
{
|
||||
value = "clamp(" + value + ", 0.0, 1.0)";
|
||||
}
|
||||
@ -152,22 +152,20 @@ void GLVertexDecompilerThread::SetDST(bool is_sca, std::string value)
|
||||
|
||||
if (d0.cond_update_enable_0 && d0.cond_update_enable_1)
|
||||
{
|
||||
dest += m_parr.AddParam(PARAM_NONE, "vec4", "cc" + std::to_string(d0.cond_reg_sel_1), "vec4(0.0)") + mask + " = ";
|
||||
dest = m_parr.AddParam(PARAM_NONE, "vec4", "cc" + std::to_string(d0.cond_reg_sel_1), "vec4(0.0)") + mask;
|
||||
}
|
||||
|
||||
if (d3.dst != 0x1f || (is_sca ? d3.sca_dst_tmp != 0x3f : d0.dst_tmp != 0x3f))
|
||||
else if (d3.dst != 0x1f || (is_sca ? d3.sca_dst_tmp != 0x3f : d0.dst_tmp != 0x3f))
|
||||
{
|
||||
dest += GetDST(is_sca) + mask + " = ";
|
||||
dest = GetDST(is_sca) + mask;
|
||||
}
|
||||
|
||||
std::string code;
|
||||
//std::string code;
|
||||
//if (d0.cond_test_enable)
|
||||
// code += "$ifcond ";
|
||||
//code += dest + value;
|
||||
//AddCode(code + ";");
|
||||
|
||||
if (d0.cond_test_enable)
|
||||
code += "$ifcond ";
|
||||
|
||||
code += dest + value;
|
||||
|
||||
AddCode(code + ";");
|
||||
AddCodeCond(Format(dest), value);
|
||||
}
|
||||
|
||||
std::string GLVertexDecompilerThread::GetFunc()
|
||||
@ -188,6 +186,11 @@ std::string GLVertexDecompilerThread::GetFunc()
|
||||
return name + "()";
|
||||
}
|
||||
|
||||
std::string GLVertexDecompilerThread::GetTex()
|
||||
{
|
||||
return m_parr.AddParam(PARAM_UNIFORM, "sampler2D", std::string("vtex") + std::to_string(/*?.tex_num*/0));
|
||||
}
|
||||
|
||||
std::string GLVertexDecompilerThread::Format(const std::string& code)
|
||||
{
|
||||
const std::pair<std::string, std::function<std::string()>> repl_list[] =
|
||||
@ -200,14 +203,16 @@ std::string GLVertexDecompilerThread::Format(const std::string& code)
|
||||
{ "$am", std::bind(std::mem_fn(&GLVertexDecompilerThread::AddAddrMask), this) },
|
||||
{ "$a", std::bind(std::mem_fn(&GLVertexDecompilerThread::AddAddrReg), this) },
|
||||
|
||||
{ "$fa", [this]()->std::string {return std::to_string(GetAddr()); } },
|
||||
{ "$t", std::bind(std::mem_fn(&GLVertexDecompilerThread::GetTex), this) },
|
||||
|
||||
{ "$fa", [this]()->std::string { return std::to_string(GetAddr()); } },
|
||||
{ "$f()", std::bind(std::mem_fn(&GLVertexDecompilerThread::GetFunc), this) },
|
||||
{ "$ifcond ", [this]() -> std::string
|
||||
{
|
||||
const std::string& cond = GetCond();
|
||||
if (cond == "true") return "";
|
||||
return "if(" + cond + ") ";
|
||||
}
|
||||
{
|
||||
const std::string& cond = GetCond();
|
||||
if (cond == "true") return "";
|
||||
return "if(" + cond + ") ";
|
||||
}
|
||||
},
|
||||
{ "$cond", std::bind(std::mem_fn(&GLVertexDecompilerThread::GetCond), this) }
|
||||
};
|
||||
@ -252,6 +257,70 @@ std::string GLVertexDecompilerThread::GetCond()
|
||||
return fmt::Format("any(%s(cc%d%s, vec4(0.0)%s))", cond_string_table[d0.cond], d0.cond_reg_sel_1, swizzle.c_str(), swizzle.c_str());
|
||||
}
|
||||
|
||||
void GLVertexDecompilerThread::AddCodeCond(const std::string& dst, const std::string& src)
|
||||
{
|
||||
enum
|
||||
{
|
||||
lt = 0x1,
|
||||
eq = 0x2,
|
||||
gt = 0x4,
|
||||
};
|
||||
|
||||
|
||||
if (!d0.cond_test_enable || d0.cond == (lt | gt | eq))
|
||||
{
|
||||
AddCode(dst + " = " + src + ";");
|
||||
return;
|
||||
}
|
||||
|
||||
if (d0.cond == 0)
|
||||
{
|
||||
AddCode("//" + dst + " = " + src + ";");
|
||||
return;
|
||||
}
|
||||
|
||||
static const char* cond_string_table[(lt | gt | eq) + 1] =
|
||||
{
|
||||
"error",
|
||||
"lessThan",
|
||||
"equal",
|
||||
"lessThanEqual",
|
||||
"greaterThan",
|
||||
"notEqual",
|
||||
"greaterThanEqual",
|
||||
"error"
|
||||
};
|
||||
|
||||
static const char f[4] = { 'x', 'y', 'z', 'w' };
|
||||
|
||||
std::string swizzle;
|
||||
swizzle += f[d0.mask_x];
|
||||
swizzle += f[d0.mask_y];
|
||||
swizzle += f[d0.mask_z];
|
||||
swizzle += f[d0.mask_w];
|
||||
|
||||
swizzle = swizzle == "xyzw" ? "" : "." + swizzle;
|
||||
|
||||
std::string cond = fmt::Format("%s(cc%d%s, vec4(0.0))", cond_string_table[d0.cond], d0.cond_reg_sel_1, swizzle.c_str());
|
||||
|
||||
ShaderVar dst_var(dst);
|
||||
dst_var.symplify();
|
||||
|
||||
//const char *c_mask = f;
|
||||
|
||||
if (dst_var.swizzles[0].length() == 1)
|
||||
{
|
||||
AddCode("if (" + cond + ".x) " + dst + " = vec4(" + src + ").x;");
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < dst_var.swizzles[0].length(); ++i)
|
||||
{
|
||||
AddCode("if (" + cond + "." + f[i] + ") " + dst + "." + f[i] + " = " + src + "." + f[i] + ";");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string GLVertexDecompilerThread::AddAddrMask()
|
||||
{
|
||||
@ -290,21 +359,21 @@ std::string GLVertexDecompilerThread::BuildFuncBody(const FuncInfo& func)
|
||||
{
|
||||
std::string result;
|
||||
|
||||
for(uint i=func.offset; i<m_body.size(); ++i)
|
||||
for (uint i = func.offset; i<m_body.size(); ++i)
|
||||
{
|
||||
if(i != func.offset)
|
||||
if (i != func.offset)
|
||||
{
|
||||
uint call_func = -1;
|
||||
for(uint j=0; j<m_funcs.size(); ++j)
|
||||
for (uint j = 0; j<m_funcs.size(); ++j)
|
||||
{
|
||||
if(m_funcs[j].offset == i)
|
||||
if (m_funcs[j].offset == i)
|
||||
{
|
||||
call_func = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(call_func != -1)
|
||||
if (call_func != -1)
|
||||
{
|
||||
result += '\t' + m_funcs[call_func].name + "();\n";
|
||||
break;
|
||||
@ -352,7 +421,7 @@ std::string GLVertexDecompilerThread::BuildCode()
|
||||
{ "tc6", true, "dst_reg13", "", false },
|
||||
{ "tc7", true, "dst_reg14", "", false },
|
||||
{ "tc8", true, "dst_reg15", "", false },
|
||||
{ "tc9", true, "dst_reg6", "", false } // In this line, dst_reg6 is correct since dst_reg goes from 0 to 15.
|
||||
{ "tc9", true, "dst_reg6", "", false } // In this line, dst_reg6 is correct since dst_reg goes from 0 to 15.
|
||||
};
|
||||
|
||||
std::string f;
|
||||
@ -385,7 +454,7 @@ std::string GLVertexDecompilerThread::BuildCode()
|
||||
|
||||
std::string fp;
|
||||
|
||||
for (int i = m_funcs.size() - 1; i>0; --i)
|
||||
for (int i = m_funcs.size() - 1; i > 0; --i)
|
||||
{
|
||||
fp += fmt::Format("void %s();\n", m_funcs[i].name.c_str());
|
||||
}
|
||||
@ -423,7 +492,7 @@ std::string GLVertexDecompilerThread::BuildCode()
|
||||
|
||||
f += fmt::Format("\nvoid %s()\n{\n%s}\n", m_funcs[1].name.c_str(), main_body.c_str());
|
||||
|
||||
for(uint i=2; i<m_funcs.size(); ++i)
|
||||
for (uint i = 2; i<m_funcs.size(); ++i)
|
||||
{
|
||||
f += fmt::Format("\nvoid %s()\n{\n%s}\n", m_funcs[i].name.c_str(), BuildFuncBody(m_funcs[i]).c_str());
|
||||
}
|
||||
@ -445,16 +514,85 @@ void GLVertexDecompilerThread::Task()
|
||||
m_instr_count = 0;
|
||||
|
||||
for (int i = 0; i < m_max_instr_count; ++i)
|
||||
{
|
||||
m_instructions[i].reset();
|
||||
}
|
||||
|
||||
for (u32 i = 0; m_instr_count < m_max_instr_count; m_instr_count++)
|
||||
bool is_has_BRA = false;
|
||||
|
||||
for (u32 i = 1; m_instr_count < m_max_instr_count; m_instr_count++)
|
||||
{
|
||||
m_cur_instr = &m_instructions[m_instr_count];
|
||||
|
||||
d0.HEX = m_data[i++];
|
||||
d1.HEX = m_data[i++];
|
||||
d2.HEX = m_data[i++];
|
||||
d3.HEX = m_data[i++];
|
||||
if (is_has_BRA)
|
||||
{
|
||||
d3.HEX = m_data[i];
|
||||
i += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
d1.HEX = m_data[i++];
|
||||
|
||||
switch (d1.sca_opcode)
|
||||
{
|
||||
case 0x08: //BRA
|
||||
LOG_WARNING(RSX, "BRA found. Please report to RPCS3 team.");
|
||||
is_has_BRA = true;
|
||||
m_jump_lvls.clear();
|
||||
d3.HEX = m_data[++i];
|
||||
i += 4;
|
||||
break;
|
||||
|
||||
case 0x09: //BRI
|
||||
d2.HEX = m_data[i++];
|
||||
d3.HEX = m_data[i];
|
||||
i += 2;
|
||||
m_jump_lvls.emplace(GetAddr());
|
||||
break;
|
||||
|
||||
default:
|
||||
d3.HEX = m_data[++i];
|
||||
i += 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (d3.end)
|
||||
{
|
||||
m_instr_count++;
|
||||
|
||||
if (i < m_data.size())
|
||||
{
|
||||
LOG_ERROR(RSX, "Program end before buffer end.");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint jump_position = 0;
|
||||
|
||||
if (is_has_BRA || !m_jump_lvls.empty())
|
||||
{
|
||||
m_cur_instr = &m_instructions[0];
|
||||
AddCode("int jump_position = 0;");
|
||||
AddCode("while (true)");
|
||||
AddCode("{");
|
||||
m_cur_instr->open_scopes++;
|
||||
|
||||
AddCode(fmt::Format("if (jump_position <= %u)", jump_position++));
|
||||
AddCode("{");
|
||||
m_cur_instr->open_scopes++;
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < m_instr_count; ++i)
|
||||
{
|
||||
m_cur_instr = &m_instructions[i];
|
||||
|
||||
d0.HEX = m_data[i * 4 + 0];
|
||||
d1.HEX = m_data[i * 4 + 1];
|
||||
d2.HEX = m_data[i * 4 + 2];
|
||||
d3.HEX = m_data[i * 4 + 3];
|
||||
|
||||
src[0].src0l = d2.src0l;
|
||||
src[0].src0h = d1.src0h;
|
||||
@ -462,107 +600,168 @@ void GLVertexDecompilerThread::Task()
|
||||
src[2].src2l = d3.src2l;
|
||||
src[2].src2h = d2.src2h;
|
||||
|
||||
if(!d1.sca_opcode && !d1.vec_opcode)
|
||||
if (i && (is_has_BRA || std::find(m_jump_lvls.begin(), m_jump_lvls.end(), i) != m_jump_lvls.end()))
|
||||
{
|
||||
m_body.push_back("//nop");
|
||||
m_cur_instr->close_scopes++;
|
||||
AddCode("}");
|
||||
AddCode("");
|
||||
|
||||
AddCode(fmt::Format("if (jump_position <= %u)", jump_position++));
|
||||
AddCode("{");
|
||||
m_cur_instr->open_scopes++;
|
||||
}
|
||||
|
||||
switch(d1.sca_opcode)
|
||||
if (!d1.sca_opcode && !d1.vec_opcode)
|
||||
{
|
||||
case 0x00: break; // NOP
|
||||
case 0x01: SetDSTSca("$s"); break; // MOV
|
||||
case 0x02: SetDSTSca("(1.0 / $s)"); break; // RCP
|
||||
case 0x03: SetDSTSca("clamp(1.0 / $s, 5.42101e-20, 1.884467e19)"); break; // RCC
|
||||
case 0x04: SetDSTSca("inversesqrt(abs($s))"); break; // RSQ
|
||||
case 0x05: SetDSTSca("exp($s)"); break; // EXP
|
||||
case 0x06: SetDSTSca("log($s)"); break; // LOG
|
||||
case 0x07: SetDSTSca("vec4(1.0, $s.x, ($s.x > 0 ? exp2($s.w * log2($s.y)) : 0.0), 1.0)"); break; // LIT
|
||||
//case 0x08: break; // BRA
|
||||
case 0x09: // BRI : works differently (BRI o[1].x(TR) L0;)
|
||||
//AddCode("$ifcond { $f(); return; }");
|
||||
if (GetAddr() > m_instr_count)
|
||||
AddCode("//nop");
|
||||
}
|
||||
|
||||
switch (d1.sca_opcode)
|
||||
{
|
||||
case RSX_SCA_OPCODE_NOP: break;
|
||||
case RSX_SCA_OPCODE_MOV: SetDSTSca("$s"); break;
|
||||
case RSX_SCA_OPCODE_RCP: SetDSTSca("(1.0 / $s)"); break;
|
||||
case RSX_SCA_OPCODE_RCC: SetDSTSca("clamp(1.0 / $s, 5.42101e-20, 1.884467e19)"); break;
|
||||
case RSX_SCA_OPCODE_RSQ: SetDSTSca("inversesqrt(abs($s))"); break;
|
||||
case RSX_SCA_OPCODE_EXP: SetDSTSca("exp($s)"); break;
|
||||
case RSX_SCA_OPCODE_LOG: SetDSTSca("log($s)"); break;
|
||||
case RSX_SCA_OPCODE_LIT: SetDSTSca("vec4(1.0, $s.x, ($s.x > 0.0 ? exp($s.w * log2($s.y)) : 0.0), 1.0)"); break;
|
||||
case RSX_SCA_OPCODE_BRA:
|
||||
{
|
||||
AddCode("$if ($cond)");
|
||||
AddCode("{");
|
||||
m_cur_instr->open_scopes++;
|
||||
AddCode("jump_position = $a$am;");
|
||||
AddCode("continue;");
|
||||
m_cur_instr->close_scopes++;
|
||||
AddCode("}");
|
||||
}
|
||||
break;
|
||||
/* This triggers opengl driver lost connection error code 7
|
||||
case RSX_SCA_OPCODE_BRI: // works differently (BRI o[1].x(TR) L0;)
|
||||
{
|
||||
uint jump_position;
|
||||
|
||||
if (is_has_BRA)
|
||||
{
|
||||
AddCode("if(!$cond)");
|
||||
AddCode("{");
|
||||
m_cur_instr->open_scopes++;
|
||||
m_instructions[GetAddr()].put_close_scopes++;
|
||||
jump_position = GetAddr();
|
||||
}
|
||||
else
|
||||
{
|
||||
AddCode("} while ($cond);");
|
||||
m_cur_instr->close_scopes++;
|
||||
m_instructions[GetAddr()].do_count++;
|
||||
int addr = GetAddr();
|
||||
|
||||
jump_position = 0;
|
||||
for (auto pos : m_jump_lvls)
|
||||
{
|
||||
if (addr == pos)
|
||||
break;
|
||||
|
||||
++jump_position;
|
||||
}
|
||||
}
|
||||
|
||||
AddCode("$ifcond ");
|
||||
AddCode("{");
|
||||
m_cur_instr->open_scopes++;
|
||||
AddCode(fmt::Format("jump_position = %u;", jump_position));
|
||||
AddCode("continue;");
|
||||
m_cur_instr->close_scopes++;
|
||||
AddCode("}");
|
||||
}
|
||||
break;
|
||||
//case 0x0a: AddCode("$ifcond $f(); //CAL"); break; // CAL : works same as BRI
|
||||
case 0x0b: AddCode("$ifcond $f(); //CLI"); break; // CLI : works same as BRI
|
||||
case 0x0c: AddCode("$ifcond return;"); break; // RET : works like BRI but shorter (RET o[1].x(TR);)
|
||||
case 0x0d: SetDSTSca("log2($s)"); break; // LG2
|
||||
case 0x0e: SetDSTSca("exp2($s)"); break; // EX2
|
||||
case 0x0f: SetDSTSca("sin($s)"); break; // SIN
|
||||
case 0x10: SetDSTSca("cos($s)"); break; // COS
|
||||
//case 0x11: break; // BRB : works differently (BRB o[1].x !b0, L0;)
|
||||
//case 0x12: break; // CLB : works same as BRB
|
||||
//case 0x13: break; // PSH : works differently (PSH o[1].x A0;)
|
||||
//case 0x14: break; // POP : works differently (POP o[1].x;)
|
||||
*/
|
||||
case RSX_SCA_OPCODE_CAL:
|
||||
// works same as BRI
|
||||
AddCode("$ifcond $f(); //CAL");
|
||||
break;
|
||||
case RSX_SCA_OPCODE_CLI:
|
||||
// works same as BRI
|
||||
AddCode("$ifcond $f(); //CLI");
|
||||
break;
|
||||
case RSX_SCA_OPCODE_RET:
|
||||
// works like BRI but shorter (RET o[1].x(TR);)
|
||||
AddCode("$ifcond return;");
|
||||
break;
|
||||
case RSX_SCA_OPCODE_LG2: SetDSTSca("log2($s)"); break;
|
||||
case RSX_SCA_OPCODE_EX2: SetDSTSca("exp2($s)"); break;
|
||||
case RSX_SCA_OPCODE_SIN: SetDSTSca("sin($s)"); break;
|
||||
case RSX_SCA_OPCODE_COS: SetDSTSca("cos($s)"); break;
|
||||
case RSX_SCA_OPCODE_BRB:
|
||||
// works differently (BRB o[1].x !b0, L0;)
|
||||
LOG_ERROR(RSX, "Unimplemented sca_opcode BRB");
|
||||
break;
|
||||
case RSX_SCA_OPCODE_CLB: break;
|
||||
// works same as BRB
|
||||
LOG_ERROR(RSX, "Unimplemented sca_opcode CLB");
|
||||
break;
|
||||
case RSX_SCA_OPCODE_PSH: break;
|
||||
// works differently (PSH o[1].x A0;)
|
||||
LOG_ERROR(RSX, "Unimplemented sca_opcode PSH");
|
||||
break;
|
||||
case RSX_SCA_OPCODE_POP: break;
|
||||
// works differently (POP o[1].x;)
|
||||
LOG_ERROR(RSX, "Unimplemented sca_opcode POP");
|
||||
break;
|
||||
|
||||
default:
|
||||
m_body.push_back(fmt::Format("//Unknown vp sca_opcode 0x%x", fmt::by_value(d1.sca_opcode)));
|
||||
AddCode(fmt::Format("//Unknown vp sca_opcode 0x%x", fmt::by_value(d1.sca_opcode)));
|
||||
LOG_ERROR(RSX, "Unknown vp sca_opcode 0x%x", fmt::by_value(d1.sca_opcode));
|
||||
Emu.Pause();
|
||||
break;
|
||||
break;
|
||||
}
|
||||
|
||||
switch(d1.vec_opcode)
|
||||
switch (d1.vec_opcode)
|
||||
{
|
||||
case 0x00: break; //NOP
|
||||
case 0x01: SetDSTVec("$0"); break; //MOV
|
||||
case 0x02: SetDSTVec("($0 * $1)"); break; //MUL
|
||||
case 0x03: SetDSTVec("($0 + $2)"); break; //ADD
|
||||
case 0x04: SetDSTVec("($0 * $1 + $2)"); break; //MAD
|
||||
case 0x05: SetDSTVec("vec4(dot($0.xyz, $1.xyz))"); break; //DP3
|
||||
case 0x06: SetDSTVec("vec4(dot(vec4($0.xyz, 1.0), $1))"); break; //DPH
|
||||
case 0x07: SetDSTVec("vec4(dot($0, $1))"); break; //DP4
|
||||
case 0x08: SetDSTVec("vec4(distance($0, $1))"); break; //DST
|
||||
case 0x09: SetDSTVec("min($0, $1)"); break; //MIN
|
||||
case 0x0a: SetDSTVec("max($0, $1)"); break; //MAX
|
||||
case 0x0b: SetDSTVec("vec4(lessThan($0, $1))"); break; //SLT
|
||||
case 0x0c: SetDSTVec("vec4(greaterThanEqual($0, $1))"); break; //SGE
|
||||
case 0x0d: AddCode("$ifcond $a = ivec4($0)$am;"); break; //ARL
|
||||
case 0x0e: SetDSTVec("fract($0)"); break; //FRC
|
||||
case 0x0f: SetDSTVec("floor($0)"); break; //FLR
|
||||
case 0x10: SetDSTVec("vec4(equal($0, $1))"); break; //SEQ
|
||||
case 0x11: SetDSTVec("vec4(equal($0, vec4(0.0)))"); break; //SFL
|
||||
case 0x12: SetDSTVec("vec4(greaterThan($0, $1))"); break; //SGT
|
||||
case 0x13: SetDSTVec("vec4(lessThanEqual($0, $1))"); break; //SLE
|
||||
case 0x14: SetDSTVec("vec4(notEqual($0, $1))"); break; //SNE
|
||||
case 0x15: SetDSTVec("vec4(equal($0, vec4(1.0)))"); break; //STR
|
||||
case 0x16: SetDSTVec("sign($0)"); break; //SSG
|
||||
case RSX_VEC_OPCODE_NOP: break;
|
||||
case RSX_VEC_OPCODE_MOV: SetDSTVec("$0"); break;
|
||||
case RSX_VEC_OPCODE_MUL: SetDSTVec("($0 * $1)"); break;
|
||||
case RSX_VEC_OPCODE_ADD: SetDSTVec("($0 + $2)"); break;
|
||||
case RSX_VEC_OPCODE_MAD: SetDSTVec("($0 * $1 + $2)"); break;
|
||||
case RSX_VEC_OPCODE_DP3: SetDSTVec("vec4(dot($0.xyz, $1.xyz))"); break;
|
||||
case RSX_VEC_OPCODE_DPH: SetDSTVec("vec4(dot(vec4($0.xyz, 1.0), $1))"); break;
|
||||
case RSX_VEC_OPCODE_DP4: SetDSTVec("vec4(dot($0, $1))"); break;
|
||||
case RSX_VEC_OPCODE_DST: SetDSTVec("vec4(distance($0, $1))"); break;
|
||||
case RSX_VEC_OPCODE_MIN: SetDSTVec("min($0, $1)"); break;
|
||||
case RSX_VEC_OPCODE_MAX: SetDSTVec("max($0, $1)"); break;
|
||||
case RSX_VEC_OPCODE_SLT: SetDSTVec("vec4(lessThan($0, $1))"); break;
|
||||
case RSX_VEC_OPCODE_SGE: SetDSTVec("vec4(greaterThanEqual($0, $1))"); break;
|
||||
case RSX_VEC_OPCODE_ARL: AddCode("$ifcond $a = ivec4($0)$am;"); break;
|
||||
case RSX_VEC_OPCODE_FRC: SetDSTVec("fract($0)"); break;
|
||||
case RSX_VEC_OPCODE_FLR: SetDSTVec("floor($0)"); break;
|
||||
case RSX_VEC_OPCODE_SEQ: SetDSTVec("vec4(equal($0, $1))"); break;
|
||||
case RSX_VEC_OPCODE_SFL: SetDSTVec("vec4(equal($0, vec4(0.0)))"); break;
|
||||
case RSX_VEC_OPCODE_SGT: SetDSTVec("vec4(greaterThan($0, $1))"); break;
|
||||
case RSX_VEC_OPCODE_SLE: SetDSTVec("vec4(lessThanEqual($0, $1))"); break;
|
||||
case RSX_VEC_OPCODE_SNE: SetDSTVec("vec4(notEqual($0, $1))"); break;
|
||||
case RSX_VEC_OPCODE_STR: SetDSTVec("vec4(equal($0, vec4(1.0)))"); break;
|
||||
case RSX_VEC_OPCODE_SSG: SetDSTVec("sign($0)"); break;
|
||||
case RSX_VEC_OPCODE_TEX: SetDSTVec("texture($t, $0.xy)"); break;
|
||||
|
||||
default:
|
||||
m_body.push_back(fmt::Format("//Unknown vp opcode 0x%x", fmt::by_value(d1.vec_opcode)));
|
||||
AddCode(fmt::Format("//Unknown vp opcode 0x%x", fmt::by_value(d1.vec_opcode)));
|
||||
LOG_ERROR(RSX, "Unknown vp opcode 0x%x", fmt::by_value(d1.vec_opcode));
|
||||
Emu.Pause();
|
||||
break;
|
||||
}
|
||||
|
||||
if(d3.end)
|
||||
{
|
||||
m_instr_count++;
|
||||
|
||||
if(i < m_data.size())
|
||||
LOG_ERROR(RSX, "Program end before buffer end.");
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_has_BRA || !m_jump_lvls.empty())
|
||||
{
|
||||
m_cur_instr = &m_instructions[m_instr_count - 1];
|
||||
m_cur_instr->close_scopes++;
|
||||
AddCode("}");
|
||||
AddCode("break;");
|
||||
m_cur_instr->close_scopes++;
|
||||
AddCode("}");
|
||||
}
|
||||
|
||||
m_shader = BuildCode();
|
||||
|
||||
m_jump_lvls.clear();
|
||||
m_body.clear();
|
||||
if (m_funcs.size() > 2)
|
||||
{
|
||||
m_funcs.erase(m_funcs.begin()+2, m_funcs.end());
|
||||
m_funcs.erase(m_funcs.begin() + 2, m_funcs.end());
|
||||
}
|
||||
}
|
||||
|
||||
@ -574,10 +773,10 @@ GLVertexProgram::GLVertexProgram()
|
||||
|
||||
GLVertexProgram::~GLVertexProgram()
|
||||
{
|
||||
if(m_decompiler_thread)
|
||||
if (m_decompiler_thread)
|
||||
{
|
||||
Wait();
|
||||
if(m_decompiler_thread->IsAlive())
|
||||
if (m_decompiler_thread->IsAlive())
|
||||
{
|
||||
m_decompiler_thread->Stop();
|
||||
}
|
||||
@ -591,7 +790,7 @@ GLVertexProgram::~GLVertexProgram()
|
||||
|
||||
void GLVertexProgram::Wait()
|
||||
{
|
||||
if(m_decompiler_thread && m_decompiler_thread->IsAlive())
|
||||
if (m_decompiler_thread && m_decompiler_thread->IsAlive())
|
||||
{
|
||||
m_decompiler_thread->Join();
|
||||
}
|
||||
@ -623,7 +822,10 @@ void GLVertexProgram::DecompileAsync(RSXVertexProgram& prog)
|
||||
|
||||
void GLVertexProgram::Compile()
|
||||
{
|
||||
if(id) glDeleteShader(id);
|
||||
if (id)
|
||||
{
|
||||
glDeleteShader(id);
|
||||
}
|
||||
|
||||
id = glCreateShader(GL_VERTEX_SHADER);
|
||||
|
||||
@ -635,13 +837,13 @@ void GLVertexProgram::Compile()
|
||||
|
||||
GLint r = GL_FALSE;
|
||||
glGetShaderiv(id, GL_COMPILE_STATUS, &r);
|
||||
if(r != GL_TRUE)
|
||||
if (r != GL_TRUE)
|
||||
{
|
||||
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &r);
|
||||
|
||||
if(r)
|
||||
if (r)
|
||||
{
|
||||
char* buf = new char[r+1]();
|
||||
char* buf = new char[r + 1]();
|
||||
GLsizei len;
|
||||
glGetShaderInfoLog(id, r, &len, buf);
|
||||
LOG_ERROR(RSX, "Failed to compile vertex shader: %s", buf);
|
||||
@ -660,7 +862,7 @@ void GLVertexProgram::Delete()
|
||||
parr.params.clear();
|
||||
shader.clear();
|
||||
|
||||
if(id)
|
||||
if (id)
|
||||
{
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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() {}
|
||||
};
|
||||
|
@ -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)
|
||||
|
@ -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)];
|
||||
}
|
@ -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
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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";
|
||||
|
@ -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
|
||||
|
@ -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 },
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
@ -10,67 +10,112 @@
|
||||
|
||||
Module *cellDmux = nullptr;
|
||||
|
||||
#define DMUX_ERROR(...) { cellDmux->Error(__VA_ARGS__); Emu.Pause(); return; } // only for demuxer thread
|
||||
|
||||
PesHeader::PesHeader(DemuxerStream& stream)
|
||||
: pts(0xffffffffffffffffull)
|
||||
, dts(0xffffffffffffffffull)
|
||||
: pts(CODEC_TS_INVALID)
|
||||
, dts(CODEC_TS_INVALID)
|
||||
, size(0)
|
||||
, has_ts(false)
|
||||
, is_ok(false)
|
||||
{
|
||||
u16 header;
|
||||
stream.get(header);
|
||||
stream.get(size);
|
||||
if (size)
|
||||
if (!stream.get(header))
|
||||
{
|
||||
u8 empty = 0;
|
||||
u8 v;
|
||||
while (true)
|
||||
{
|
||||
stream.get(v);
|
||||
if (v != 0xFF) break; // skip padding bytes
|
||||
empty++;
|
||||
if (empty == size) return;
|
||||
};
|
||||
DMUX_ERROR("PesHeader(): end of stream (header)");
|
||||
}
|
||||
if (!stream.get(size))
|
||||
{
|
||||
DMUX_ERROR("PesHeader(): end of stream (size)");
|
||||
}
|
||||
if (!stream.check(size))
|
||||
{
|
||||
DMUX_ERROR("PesHeader(): end of stream (size=%d)", size);
|
||||
}
|
||||
|
||||
if ((v & 0xF0) == 0x20 && (size - empty) >= 5) // pts only
|
||||
u8 pos = 0;
|
||||
while (pos++ < size)
|
||||
{
|
||||
u8 v;
|
||||
if (!stream.get(v))
|
||||
{
|
||||
has_ts = true;
|
||||
return; // should never occur
|
||||
}
|
||||
|
||||
if (v == 0xff) // skip padding bytes
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((v & 0xf0) == 0x20 && (size - pos) >= 4) // pts only
|
||||
{
|
||||
pos += 4;
|
||||
pts = stream.get_ts(v);
|
||||
stream.skip(size - empty - 5);
|
||||
has_ts = true;
|
||||
}
|
||||
else if ((v & 0xf0) == 0x30 && (size - pos) >= 9) // pts and dts
|
||||
{
|
||||
pos += 5;
|
||||
pts = stream.get_ts(v);
|
||||
stream.get(v);
|
||||
has_ts = true;
|
||||
|
||||
if ((v & 0xf0) != 0x10)
|
||||
{
|
||||
cellDmux->Error("PesHeader(): dts not found (v=0x%x, size=%d, pos=%d)", v, size, pos - 1);
|
||||
stream.skip(size - pos);
|
||||
return;
|
||||
}
|
||||
pos += 4;
|
||||
dts = stream.get_ts(v);
|
||||
}
|
||||
else
|
||||
{
|
||||
has_ts = true;
|
||||
if ((v & 0xF0) != 0x30 || (size - empty) < 10)
|
||||
{
|
||||
cellDmux->Error("PesHeader(): pts not found");
|
||||
Emu.Pause();
|
||||
}
|
||||
pts = stream.get_ts(v);
|
||||
stream.get(v);
|
||||
if ((v & 0xF0) != 0x10)
|
||||
{
|
||||
cellDmux->Error("PesHeader(): dts not found");
|
||||
Emu.Pause();
|
||||
}
|
||||
dts = stream.get_ts(v);
|
||||
stream.skip(size - empty - 10);
|
||||
cellDmux->Warning("PesHeader(): unknown code (v=0x%x, size=%d, pos=%d)", v, size, pos - 1);
|
||||
stream.skip(size - pos);
|
||||
pos = size;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
is_ok = true;
|
||||
}
|
||||
|
||||
ElementaryStream::ElementaryStream(Demuxer* dmux, u32 addr, u32 size, u32 fidMajor, u32 fidMinor, u32 sup1, u32 sup2, vm::ptr<CellDmuxCbEsMsg> cbFunc, u32 cbArg, u32 spec)
|
||||
: dmux(dmux)
|
||||
, memAddr(a128(addr))
|
||||
, memSize(size - (addr - memAddr))
|
||||
, fidMajor(fidMajor)
|
||||
, fidMinor(fidMinor)
|
||||
, sup1(sup1)
|
||||
, sup2(sup2)
|
||||
, cbFunc(cbFunc)
|
||||
, cbArg(cbArg)
|
||||
, spec(spec)
|
||||
, put(a128(addr))
|
||||
, put_count(0)
|
||||
, got_count(0)
|
||||
, released(0)
|
||||
, raw_pos(0)
|
||||
, last_dts(CODEC_TS_INVALID)
|
||||
, last_pts(CODEC_TS_INVALID)
|
||||
{
|
||||
}
|
||||
|
||||
bool ElementaryStream::is_full(u32 space)
|
||||
{
|
||||
if (released < put_count)
|
||||
{
|
||||
if (entries.IsFull())
|
||||
if (entries.is_full())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
u32 first = 0;
|
||||
if (!entries.Peek(first, &dmux->is_closed) || !first)
|
||||
if (!entries.peek(first, 0, &dmux->is_closed) || !first)
|
||||
{
|
||||
throw "es::is_full() error: entries.Peek() failed";
|
||||
assert(!"es::is_full() error: entries.Peek() failed");
|
||||
return false;
|
||||
}
|
||||
else if (first >= put)
|
||||
{
|
||||
@ -103,10 +148,7 @@ void ElementaryStream::push_au(u32 size, u64 dts, u64 pts, u64 userdata, bool ra
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
|
||||
if (is_full(size))
|
||||
{
|
||||
throw "es::push_au() error: buffer is full";
|
||||
}
|
||||
assert(!is_full(size));
|
||||
|
||||
if (put + size + 128 > memAddr + memSize)
|
||||
{
|
||||
@ -146,9 +188,9 @@ void ElementaryStream::push_au(u32 size, u64 dts, u64 pts, u64 userdata, bool ra
|
||||
|
||||
put_count++;
|
||||
}
|
||||
if (!entries.Push(addr, &dmux->is_closed))
|
||||
if (!entries.push(addr, &dmux->is_closed))
|
||||
{
|
||||
throw "es::push_au() error: entries.Push() failed";
|
||||
assert(!"es::push_au() error: entries.Push() failed");
|
||||
}
|
||||
}
|
||||
|
||||
@ -180,7 +222,7 @@ bool ElementaryStream::release()
|
||||
}
|
||||
|
||||
u32 addr = 0;
|
||||
if (!entries.Pop(addr, &dmux->is_closed) || !addr)
|
||||
if (!entries.pop(addr, &dmux->is_closed) || !addr)
|
||||
{
|
||||
cellDmux->Error("es::release() error: entries.Pop() failed");
|
||||
Emu.Pause();
|
||||
@ -206,7 +248,7 @@ bool ElementaryStream::peek(u32& out_data, bool no_ex, u32& out_spec, bool updat
|
||||
}
|
||||
|
||||
u32 addr = 0;
|
||||
if (!entries.Peek(addr, &dmux->is_closed, got_count - released) || !addr)
|
||||
if (!entries.peek(addr, got_count - released, &dmux->is_closed) || !addr)
|
||||
{
|
||||
cellDmux->Error("es::peek() error: entries.Peek() failed");
|
||||
Emu.Pause();
|
||||
@ -227,7 +269,7 @@ void ElementaryStream::reset()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
put = memAddr;
|
||||
entries.Clear();
|
||||
entries.clear();
|
||||
put_count = 0;
|
||||
got_count = 0;
|
||||
released = 0;
|
||||
@ -248,17 +290,18 @@ void dmuxQueryEsAttr(u32 info_addr /* may be 0 */, vm::ptr<const CellCodecEsFilt
|
||||
if (esFilterId->filterIdMajor >= 0xe0)
|
||||
attr->memSize = 0x500000; // 0x45fa49 from ps3
|
||||
else
|
||||
attr->memSize = 0x8000; // 0x73d9 from ps3
|
||||
attr->memSize = 0x7000; // 0x73d9 from ps3
|
||||
|
||||
cellDmux->Warning("*** filter(0x%x, 0x%x, 0x%x, 0x%x)", (u32)esFilterId->filterIdMajor, (u32)esFilterId->filterIdMinor,
|
||||
(u32)esFilterId->supplementalInfo1, (u32)esFilterId->supplementalInfo2);
|
||||
}
|
||||
|
||||
u32 dmuxOpen(Demuxer* data)
|
||||
u32 dmuxOpen(Demuxer* dmux_ptr)
|
||||
{
|
||||
Demuxer& dmux = *data;
|
||||
std::shared_ptr<Demuxer> sptr(dmux_ptr);
|
||||
Demuxer& dmux = *dmux_ptr;
|
||||
|
||||
u32 dmux_id = cellDmux->GetNewId(data);
|
||||
u32 dmux_id = cellDmux->GetNewId(sptr);
|
||||
|
||||
dmux.id = dmux_id;
|
||||
|
||||
@ -271,19 +314,20 @@ u32 dmuxOpen(Demuxer* data)
|
||||
dmux.dmuxCb->InitRegs();
|
||||
dmux.dmuxCb->DoRun();
|
||||
|
||||
thread t("Demuxer[" + std::to_string(dmux_id) + "] Thread", [&]()
|
||||
thread t("Demuxer[" + std::to_string(dmux_id) + "] Thread", [dmux_ptr, sptr]()
|
||||
{
|
||||
Demuxer& dmux = *dmux_ptr;
|
||||
cellDmux->Notice("Demuxer thread started (mem=0x%x, size=0x%x, cb=0x%x, arg=0x%x)", dmux.memAddr, dmux.memSize, dmux.cbFunc, dmux.cbArg);
|
||||
|
||||
DemuxerTask task;
|
||||
DemuxerStream stream = {};
|
||||
ElementaryStream* esALL[192]; memset(esALL, 0, sizeof(esALL));
|
||||
ElementaryStream** esAVC = &esALL[0]; // AVC (max 16)
|
||||
ElementaryStream** esM2V = &esALL[16]; // MPEG-2 (max 16)
|
||||
ElementaryStream* esALL[96]; memset(esALL, 0, sizeof(esALL));
|
||||
ElementaryStream** esAVC = &esALL[0]; // AVC (max 16 minus M2V count)
|
||||
ElementaryStream** esM2V = &esALL[16]; // M2V (max 16 minus AVC count)
|
||||
ElementaryStream** esDATA = &esALL[32]; // user data (max 16)
|
||||
ElementaryStream** esATX = &esALL[48]; // ATRAC3+ (max 48)
|
||||
ElementaryStream** esAC3 = &esALL[96]; // AC3 (max 48)
|
||||
ElementaryStream** esPCM = &esALL[144]; // LPCM (max 48)
|
||||
ElementaryStream** esATX = &esALL[48]; // ATRAC3+ (max 16)
|
||||
ElementaryStream** esAC3 = &esALL[64]; // AC3 (max 16)
|
||||
ElementaryStream** esPCM = &esALL[80]; // LPCM (max 16)
|
||||
|
||||
u32 cb_add = 0;
|
||||
|
||||
@ -294,12 +338,11 @@ u32 dmuxOpen(Demuxer* data)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!dmux.job.Peek(task, &sq_no_wait) && dmux.is_running && stream.addr)
|
||||
if (!dmux.job.try_peek(task) && dmux.is_running && stream.addr)
|
||||
{
|
||||
// default task (demuxing) (if there is no other work)
|
||||
be_t<u32> code;
|
||||
be_t<u16> len;
|
||||
u8 ch;
|
||||
|
||||
if (!stream.peek(code))
|
||||
{
|
||||
@ -310,64 +353,119 @@ u32 dmuxOpen(Demuxer* data)
|
||||
dmux.cbFunc.call(*dmux.dmuxCb, dmux.id, dmuxMsg, dmux.cbArg);
|
||||
|
||||
dmux.is_running = false;
|
||||
continue;
|
||||
}
|
||||
else switch (code.ToLE())
|
||||
|
||||
switch (code.ToLE())
|
||||
{
|
||||
case PACK_START_CODE:
|
||||
{
|
||||
if (!stream.check(14))
|
||||
{
|
||||
DMUX_ERROR("End of stream (PACK_START_CODE)");
|
||||
}
|
||||
stream.skip(14);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case SYSTEM_HEADER_START_CODE:
|
||||
{
|
||||
if (!stream.check(18))
|
||||
{
|
||||
DMUX_ERROR("End of stream (SYSTEM_HEADER_START_CODE)");
|
||||
}
|
||||
stream.skip(18);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case PADDING_STREAM:
|
||||
{
|
||||
if (!stream.check(6))
|
||||
{
|
||||
DMUX_ERROR("End of stream (PADDING_STREAM)");
|
||||
}
|
||||
stream.skip(4);
|
||||
stream.get(len);
|
||||
|
||||
if (!stream.check(len.ToLE()))
|
||||
{
|
||||
DMUX_ERROR("End of stream (PADDING_STREAM, len=%d)", len.ToLE());
|
||||
}
|
||||
stream.skip(len);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case PRIVATE_STREAM_2:
|
||||
{
|
||||
if (!stream.check(6))
|
||||
{
|
||||
DMUX_ERROR("End of stream (PRIVATE_STREAM_2)");
|
||||
}
|
||||
stream.skip(4);
|
||||
stream.get(len);
|
||||
|
||||
cellDmux->Notice("PRIVATE_STREAM_2 (%d)", len.ToLE());
|
||||
|
||||
if (!stream.check(len.ToLE()))
|
||||
{
|
||||
DMUX_ERROR("End of stream (PRIVATE_STREAM_2, len=%d)", len.ToLE());
|
||||
}
|
||||
stream.skip(len);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case PRIVATE_STREAM_1:
|
||||
{
|
||||
// audio and user data stream
|
||||
DemuxerStream backup = stream;
|
||||
|
||||
// audio AT3+ (and probably LPCM or user data)
|
||||
if (!stream.check(6))
|
||||
{
|
||||
DMUX_ERROR("End of stream (PRIVATE_STREAM_1)");
|
||||
}
|
||||
stream.skip(4);
|
||||
stream.get(len);
|
||||
|
||||
PesHeader pes(stream);
|
||||
if (!stream.check(len.ToLE()))
|
||||
{
|
||||
DMUX_ERROR("End of stream (PRIVATE_STREAM_1, len=%d)", len.ToLE());
|
||||
}
|
||||
|
||||
// read additional header:
|
||||
stream.peek(ch); // ???
|
||||
//stream.skip(4);
|
||||
//pes.size += 4;
|
||||
const PesHeader pes(stream);
|
||||
if (!pes.is_ok)
|
||||
{
|
||||
DMUX_ERROR("PesHeader error (PRIVATE_STREAM_1, len=%d)", len.ToLE());
|
||||
}
|
||||
|
||||
if (esATX[ch])
|
||||
if (len < pes.size + 4)
|
||||
{
|
||||
DMUX_ERROR("End of block (PRIVATE_STREAM_1, PesHeader + fid_minor, len=%d)", len.ToLE());
|
||||
}
|
||||
len -= pes.size + 4;
|
||||
|
||||
u8 fid_minor;
|
||||
if (!stream.get(fid_minor))
|
||||
{
|
||||
DMUX_ERROR("End of stream (PRIVATE_STREAM1, fid_minor)");
|
||||
}
|
||||
|
||||
const u32 ch = fid_minor % 16;
|
||||
if ((fid_minor & -0x10) == 0 && esATX[ch])
|
||||
{
|
||||
ElementaryStream& es = *esATX[ch];
|
||||
if (es.raw_data.size() > 1024 * 1024)
|
||||
{
|
||||
stream = backup;
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
|
||||
continue;
|
||||
}
|
||||
|
||||
stream.skip(4);
|
||||
len -= 4;
|
||||
if (len < 3 || !stream.check(3))
|
||||
{
|
||||
DMUX_ERROR("End of block (ATX, unknown header, len=%d)", len.ToLE());
|
||||
}
|
||||
len -= 3;
|
||||
stream.skip(3);
|
||||
|
||||
if (pes.has_ts)
|
||||
{
|
||||
@ -375,7 +473,7 @@ u32 dmuxOpen(Demuxer* data)
|
||||
es.last_pts = pes.pts;
|
||||
}
|
||||
|
||||
es.push(stream, len - pes.size - 3);
|
||||
es.push(stream, len);
|
||||
|
||||
while (true)
|
||||
{
|
||||
@ -386,9 +484,7 @@ u32 dmuxOpen(Demuxer* data)
|
||||
|
||||
if (data[0] != 0x0f || data[1] != 0xd0)
|
||||
{
|
||||
cellDmux->Error("ATX: 0x0fd0 header not found (ats=0x%llx)", ((be_t<u64>*)data)->ToLE());
|
||||
Emu.Pause();
|
||||
return;
|
||||
DMUX_ERROR("ATX: 0x0fd0 header not found (ats=0x%llx)", ((be_t<u64>*)data)->ToLE());
|
||||
}
|
||||
|
||||
u32 frame_size = ((((u32)data[2] & 0x3) << 8) | (u32)data[3]) * 8 + 8;
|
||||
@ -399,6 +495,8 @@ u32 dmuxOpen(Demuxer* data)
|
||||
|
||||
es.push_au(frame_size + 8, es.last_dts, es.last_pts, stream.userdata, false /* TODO: set correct value */, 0);
|
||||
|
||||
//cellDmux->Notice("ATX AU pushed (ats=0x%llx, frame_size=%d)", ((be_t<u64>*)data)->ToLE(), frame_size);
|
||||
|
||||
auto esMsg = vm::ptr<CellDmuxEsMsg>::make(a128(dmux.memAddr) + (cb_add ^= 16));
|
||||
esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_AU_FOUND;
|
||||
esMsg->supplementalInfo = stream.userdata;
|
||||
@ -407,38 +505,60 @@ u32 dmuxOpen(Demuxer* data)
|
||||
}
|
||||
else
|
||||
{
|
||||
stream.skip(len - pes.size - 3);
|
||||
cellDmux->Notice("PRIVATE_STREAM_1 (len=%d, fid_minor=0x%x)", len.ToLE(), fid_minor);
|
||||
stream.skip(len);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x1e0: case 0x1e1: case 0x1e2: case 0x1e3:
|
||||
case 0x1e4: case 0x1e5: case 0x1e6: case 0x1e7:
|
||||
case 0x1e8: case 0x1e9: case 0x1ea: case 0x1eb:
|
||||
case 0x1ec: case 0x1ed: case 0x1ee: case 0x1ef:
|
||||
{
|
||||
// video AVC
|
||||
ch = code - 0x1e0;
|
||||
// video stream (AVC or M2V)
|
||||
DemuxerStream backup = stream;
|
||||
|
||||
if (!stream.check(6))
|
||||
{
|
||||
DMUX_ERROR("End of stream (video, code=0x%x)", code.ToLE());
|
||||
}
|
||||
stream.skip(4);
|
||||
stream.get(len);
|
||||
|
||||
if (!stream.check(len.ToLE()))
|
||||
{
|
||||
DMUX_ERROR("End of stream (video, code=0x%x, len=%d)", code.ToLE(), len.ToLE());
|
||||
}
|
||||
|
||||
const PesHeader pes(stream);
|
||||
if (!pes.is_ok)
|
||||
{
|
||||
DMUX_ERROR("PesHeader error (video, code=0x%x, len=%d)", code.ToLE(), len.ToLE());
|
||||
}
|
||||
|
||||
if (len < pes.size + 3)
|
||||
{
|
||||
DMUX_ERROR("End of block (video, code=0x%x, PesHeader)", code.ToLE());
|
||||
}
|
||||
len -= pes.size + 3;
|
||||
|
||||
const u32 ch = code.ToLE() % 16;
|
||||
if (esAVC[ch])
|
||||
{
|
||||
ElementaryStream& es = *esAVC[ch];
|
||||
DemuxerStream backup = stream;
|
||||
|
||||
stream.skip(4);
|
||||
stream.get(len);
|
||||
PesHeader pes(stream);
|
||||
|
||||
const u32 old_size = (u32)es.raw_data.size();
|
||||
if (es.isfull(old_size))
|
||||
{
|
||||
stream = backup;
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((pes.has_ts && old_size) || old_size >= 0x70000)
|
||||
if ((pes.has_ts && old_size) || old_size >= 0x69800)
|
||||
{
|
||||
// push AU if it becomes too big or the next packet contains ts data
|
||||
// push AU if it becomes too big or the next packet contains PTS/DTS
|
||||
es.push_au(old_size, es.last_dts, es.last_pts, stream.userdata, false /* TODO: set correct value */, 0);
|
||||
|
||||
// callback
|
||||
@ -456,54 +576,35 @@ u32 dmuxOpen(Demuxer* data)
|
||||
}
|
||||
|
||||
// reconstruction of MPEG2-PS stream for vdec module
|
||||
const u32 size = len + 6 /*- pes.size - 3*/;
|
||||
const u32 size = (u32)len.ToLE() + pes.size + 9;
|
||||
stream = backup;
|
||||
es.push(stream, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
stream.skip(4);
|
||||
stream.get(len);
|
||||
cellDmux->Notice("Video stream (code=0x%x, len=%d)", code.ToLE(), len.ToLE());
|
||||
stream.skip(len);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x1c0: case 0x1c1: case 0x1c2: case 0x1c3:
|
||||
case 0x1c4: case 0x1c5: case 0x1c6: case 0x1c7:
|
||||
case 0x1c8: case 0x1c9: case 0x1ca: case 0x1cb:
|
||||
case 0x1cc: case 0x1cd: case 0x1ce: case 0x1cf:
|
||||
case 0x1d0: case 0x1d1: case 0x1d2: case 0x1d3:
|
||||
case 0x1d4: case 0x1d5: case 0x1d6: case 0x1d7:
|
||||
case 0x1d8: case 0x1d9: case 0x1da: case 0x1db:
|
||||
case 0x1dc: case 0x1dd: case 0x1de: case 0x1df:
|
||||
{
|
||||
// unknown
|
||||
cellDmux->Warning("Unknown MPEG stream found");
|
||||
stream.skip(4);
|
||||
stream.get(len);
|
||||
stream.skip(len);
|
||||
}
|
||||
break;
|
||||
|
||||
case USER_DATA_START_CODE:
|
||||
{
|
||||
cellDmux->Error("USER_DATA_START_CODE found");
|
||||
Emu.Pause();
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
if ((code.ToLE() & PACKET_START_CODE_MASK) == PACKET_START_CODE_PREFIX)
|
||||
{
|
||||
DMUX_ERROR("Unknown code found (0x%x)", code.ToLE());
|
||||
}
|
||||
|
||||
// search
|
||||
stream.skip(1);
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// wait for task with yielding (if no default work)
|
||||
if (!dmux.job.Pop(task, &dmux.is_closed))
|
||||
// wait for task if no work
|
||||
if (!dmux.job.pop(task, &dmux.is_closed))
|
||||
{
|
||||
break; // Emu is stopped
|
||||
}
|
||||
@ -515,7 +616,7 @@ u32 dmuxOpen(Demuxer* data)
|
||||
if (task.stream.discontinuity)
|
||||
{
|
||||
cellDmux->Warning("dmuxSetStream (beginning)");
|
||||
for (u32 i = 0; i < 192; i++)
|
||||
for (u32 i = 0; i < sizeof(esALL) / sizeof(esALL[0]); i++)
|
||||
{
|
||||
if (esALL[i])
|
||||
{
|
||||
@ -527,8 +628,8 @@ u32 dmuxOpen(Demuxer* data)
|
||||
stream = task.stream;
|
||||
//LOG_NOTICE(HLE, "*** stream updated(addr=0x%x, size=0x%x, discont=%d, userdata=0x%llx)",
|
||||
//stream.addr, stream.size, stream.discontinuity, stream.userdata);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case dmuxResetStream:
|
||||
case dmuxResetStreamAndWaitDone:
|
||||
@ -543,44 +644,55 @@ u32 dmuxOpen(Demuxer* data)
|
||||
//if (task.type == dmuxResetStreamAndWaitDone)
|
||||
//{
|
||||
//}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case dmuxEnableEs:
|
||||
{
|
||||
ElementaryStream& es = *task.es.es_ptr;
|
||||
if (es.fidMajor >= 0xe0 &&
|
||||
es.fidMajor <= 0xef &&
|
||||
es.fidMinor == 0 &&
|
||||
es.sup1 == 1 &&
|
||||
es.sup2 == 0)
|
||||
|
||||
// TODO: uncomment when ready to use
|
||||
if ((es.fidMajor & -0x10) == 0xe0 && es.fidMinor == 0 && es.sup1 == 1 && !es.sup2)
|
||||
{
|
||||
esAVC[es.fidMajor - 0xe0] = task.es.es_ptr;
|
||||
esAVC[es.fidMajor % 16] = task.es.es_ptr;
|
||||
}
|
||||
else if (es.fidMajor == 0xbd &&
|
||||
es.fidMinor == 0 &&
|
||||
es.sup1 == 0 &&
|
||||
es.sup2 == 0)
|
||||
//else if ((es.fidMajor & -0x10) == 0xe0 && es.fidMinor == 0 && !es.sup1 && !es.sup2)
|
||||
//{
|
||||
// esM2V[es.fidMajor % 16] = task.es.es_ptr;
|
||||
//}
|
||||
else if (es.fidMajor == 0xbd && (es.fidMinor & -0x10) == 0 && !es.sup1 && !es.sup2)
|
||||
{
|
||||
esATX[0] = task.es.es_ptr;
|
||||
esATX[es.fidMinor % 16] = task.es.es_ptr;
|
||||
}
|
||||
//else if (es.fidMajor == 0xbd && (es.fidMinor & -0x10) == 0x20 && !es.sup1 && !es.sup2)
|
||||
//{
|
||||
// esDATA[es.fidMinor % 16] = task.es.es_ptr;
|
||||
//}
|
||||
//else if (es.fidMajor == 0xbd && (es.fidMinor & -0x10) == 0x30 && !es.sup1 && !es.sup2)
|
||||
//{
|
||||
// esAC3[es.fidMinor % 16] = task.es.es_ptr;
|
||||
//}
|
||||
//else if (es.fidMajor == 0xbd && (es.fidMinor & -0x10) == 0x40 && !es.sup1 && !es.sup2)
|
||||
//{
|
||||
// esPCM[es.fidMinor % 16] = task.es.es_ptr;
|
||||
//}
|
||||
else
|
||||
{
|
||||
cellDmux->Warning("dmuxEnableEs: (TODO) unsupported filter (0x%x, 0x%x, 0x%x, 0x%x)", es.fidMajor, es.fidMinor, es.sup1, es.sup2);
|
||||
DMUX_ERROR("dmuxEnableEs: unknown filter (0x%x, 0x%x, 0x%x, 0x%x)", es.fidMajor, es.fidMinor, es.sup1, es.sup2);
|
||||
}
|
||||
es.dmux = &dmux;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case dmuxDisableEs:
|
||||
{
|
||||
ElementaryStream& es = *task.es.es_ptr;
|
||||
if (es.dmux != &dmux)
|
||||
{
|
||||
cellDmux->Warning("dmuxDisableEs: invalid elementary stream");
|
||||
break;
|
||||
DMUX_ERROR("dmuxDisableEs: invalid elementary stream");
|
||||
}
|
||||
for (u32 i = 0; i < 192; i++)
|
||||
|
||||
for (u32 i = 0; i < sizeof(esALL) / sizeof(esALL[0]); i++)
|
||||
{
|
||||
if (esALL[i] == &es)
|
||||
{
|
||||
@ -589,22 +701,22 @@ u32 dmuxOpen(Demuxer* data)
|
||||
}
|
||||
es.dmux = nullptr;
|
||||
Emu.GetIdManager().RemoveID(task.es.es);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case dmuxFlushEs:
|
||||
{
|
||||
ElementaryStream& es = *task.es.es_ptr;
|
||||
|
||||
const u32 old_size = (u32)es.raw_data.size();
|
||||
if (old_size && (es.fidMajor & 0xf0) == 0xe0)
|
||||
if (old_size && (es.fidMajor & -0x10) == 0xe0)
|
||||
{
|
||||
// TODO (it's only for AVC, some ATX data may be lost)
|
||||
while (es.isfull(old_size))
|
||||
{
|
||||
if (Emu.IsStopped() || dmux.is_closed) break;
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
|
||||
}
|
||||
|
||||
es.push_au(old_size, es.last_dts, es.last_pts, stream.userdata, false, 0);
|
||||
@ -626,22 +738,23 @@ u32 dmuxOpen(Demuxer* data)
|
||||
esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_FLUSH_DONE;
|
||||
esMsg->supplementalInfo = stream.userdata;
|
||||
es.cbFunc.call(*dmux.dmuxCb, dmux.id, es.id, esMsg, es.cbArg);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case dmuxResetEs:
|
||||
{
|
||||
task.es.es_ptr->reset();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case dmuxClose: break;
|
||||
case dmuxClose:
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
cellDmux->Error("Demuxer thread error: unknown task(%d)", task.type);
|
||||
Emu.Pause();
|
||||
return;
|
||||
DMUX_ERROR("Demuxer thread error: unknown task (0x%x)", task.type);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -740,14 +853,14 @@ int cellDmuxClose(u32 demuxerHandle)
|
||||
{
|
||||
cellDmux->Warning("cellDmuxClose(demuxerHandle=%d)", demuxerHandle);
|
||||
|
||||
Demuxer* dmux;
|
||||
std::shared_ptr<Demuxer> dmux;
|
||||
if (!Emu.GetIdManager().GetIDData(demuxerHandle, dmux))
|
||||
{
|
||||
return CELL_DMUX_ERROR_ARG;
|
||||
}
|
||||
|
||||
dmux->is_closed = true;
|
||||
dmux->job.Push(DemuxerTask(dmuxClose), &sq_no_wait);
|
||||
dmux->job.try_push(DemuxerTask(dmuxClose));
|
||||
|
||||
while (!dmux->is_finished)
|
||||
{
|
||||
@ -757,7 +870,7 @@ int cellDmuxClose(u32 demuxerHandle)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
|
||||
}
|
||||
|
||||
if (dmux->dmuxCb) Emu.GetCPU().RemoveThread(dmux->dmuxCb->GetId());
|
||||
@ -770,7 +883,7 @@ int cellDmuxSetStream(u32 demuxerHandle, const u32 streamAddress, u32 streamSize
|
||||
cellDmux->Log("cellDmuxSetStream(demuxerHandle=%d, streamAddress=0x%x, streamSize=%d, discontinuity=%d, userData=0x%llx",
|
||||
demuxerHandle, streamAddress, streamSize, discontinuity, userData);
|
||||
|
||||
Demuxer* dmux;
|
||||
std::shared_ptr<Demuxer> dmux;
|
||||
if (!Emu.GetIdManager().GetIDData(demuxerHandle, dmux))
|
||||
{
|
||||
return CELL_DMUX_ERROR_ARG;
|
||||
@ -789,7 +902,7 @@ int cellDmuxSetStream(u32 demuxerHandle, const u32 streamAddress, u32 streamSize
|
||||
info.discontinuity = discontinuity;
|
||||
info.userdata = userData;
|
||||
|
||||
dmux->job.Push(task, &dmux->is_closed);
|
||||
dmux->job.push(task, &dmux->is_closed);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
@ -797,13 +910,13 @@ int cellDmuxResetStream(u32 demuxerHandle)
|
||||
{
|
||||
cellDmux->Warning("cellDmuxResetStream(demuxerHandle=%d)", demuxerHandle);
|
||||
|
||||
Demuxer* dmux;
|
||||
std::shared_ptr<Demuxer> dmux;
|
||||
if (!Emu.GetIdManager().GetIDData(demuxerHandle, dmux))
|
||||
{
|
||||
return CELL_DMUX_ERROR_ARG;
|
||||
}
|
||||
|
||||
dmux->job.Push(DemuxerTask(dmuxResetStream), &dmux->is_closed);
|
||||
dmux->job.push(DemuxerTask(dmuxResetStream), &dmux->is_closed);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
@ -811,13 +924,13 @@ int cellDmuxResetStreamAndWaitDone(u32 demuxerHandle)
|
||||
{
|
||||
cellDmux->Warning("cellDmuxResetStreamAndWaitDone(demuxerHandle=%d)", demuxerHandle);
|
||||
|
||||
Demuxer* dmux;
|
||||
std::shared_ptr<Demuxer> dmux;
|
||||
if (!Emu.GetIdManager().GetIDData(demuxerHandle, dmux))
|
||||
{
|
||||
return CELL_DMUX_ERROR_ARG;
|
||||
}
|
||||
|
||||
dmux->job.Push(DemuxerTask(dmuxResetStreamAndWaitDone), &dmux->is_closed);
|
||||
dmux->job.push(DemuxerTask(dmuxResetStreamAndWaitDone), &dmux->is_closed);
|
||||
while (dmux->is_running && !dmux->is_closed) // TODO: ensure that it is safe
|
||||
{
|
||||
if (Emu.IsStopped())
|
||||
@ -825,7 +938,7 @@ int cellDmuxResetStreamAndWaitDone(u32 demuxerHandle)
|
||||
cellDmux->Warning("cellDmuxResetStreamAndWaitDone(%d) aborted", demuxerHandle);
|
||||
return CELL_OK;
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
|
||||
}
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -870,7 +983,7 @@ int cellDmuxEnableEs(u32 demuxerHandle, vm::ptr<const CellCodecEsFilterId> esFil
|
||||
"esSpecificInfo_addr=0x%x, esHandle_addr=0x%x)", demuxerHandle, esFilterId.addr(), esResourceInfo.addr(),
|
||||
esCb.addr(), esSpecificInfo_addr, esHandle.addr());
|
||||
|
||||
Demuxer* dmux;
|
||||
std::shared_ptr<Demuxer> dmux;
|
||||
if (!Emu.GetIdManager().GetIDData(demuxerHandle, dmux))
|
||||
{
|
||||
return CELL_DMUX_ERROR_ARG;
|
||||
@ -878,9 +991,9 @@ int cellDmuxEnableEs(u32 demuxerHandle, vm::ptr<const CellCodecEsFilterId> esFil
|
||||
|
||||
// TODO: check esFilterId, esResourceInfo, esCb and esSpecificInfo correctly
|
||||
|
||||
ElementaryStream* es = new ElementaryStream(dmux, esResourceInfo->memAddr, esResourceInfo->memSize,
|
||||
std::shared_ptr<ElementaryStream> es(new ElementaryStream(dmux.get(), esResourceInfo->memAddr, esResourceInfo->memSize,
|
||||
esFilterId->filterIdMajor, esFilterId->filterIdMinor, esFilterId->supplementalInfo1, esFilterId->supplementalInfo2,
|
||||
vm::ptr<CellDmuxCbEsMsg>::make(esCb->cbEsMsgFunc.addr()), esCb->cbArg, esSpecificInfo_addr);
|
||||
vm::ptr<CellDmuxCbEsMsg>::make(esCb->cbEsMsgFunc.addr()), esCb->cbArg, esSpecificInfo_addr));
|
||||
|
||||
u32 id = cellDmux->GetNewId(es);
|
||||
es->id = id;
|
||||
@ -891,9 +1004,9 @@ int cellDmuxEnableEs(u32 demuxerHandle, vm::ptr<const CellCodecEsFilterId> esFil
|
||||
|
||||
DemuxerTask task(dmuxEnableEs);
|
||||
task.es.es = id;
|
||||
task.es.es_ptr = es;
|
||||
task.es.es_ptr = es.get();
|
||||
|
||||
dmux->job.Push(task, &dmux->is_closed);
|
||||
dmux->job.push(task, &dmux->is_closed);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
@ -901,7 +1014,7 @@ int cellDmuxDisableEs(u32 esHandle)
|
||||
{
|
||||
cellDmux->Warning("cellDmuxDisableEs(esHandle=0x%x)", esHandle);
|
||||
|
||||
ElementaryStream* es;
|
||||
std::shared_ptr<ElementaryStream> es;
|
||||
if (!Emu.GetIdManager().GetIDData(esHandle, es))
|
||||
{
|
||||
return CELL_DMUX_ERROR_ARG;
|
||||
@ -909,9 +1022,9 @@ int cellDmuxDisableEs(u32 esHandle)
|
||||
|
||||
DemuxerTask task(dmuxDisableEs);
|
||||
task.es.es = esHandle;
|
||||
task.es.es_ptr = es;
|
||||
task.es.es_ptr = es.get();
|
||||
|
||||
es->dmux->job.Push(task, &es->dmux->is_closed);
|
||||
es->dmux->job.push(task, &es->dmux->is_closed);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
@ -919,7 +1032,7 @@ int cellDmuxResetEs(u32 esHandle)
|
||||
{
|
||||
cellDmux->Log("cellDmuxResetEs(esHandle=0x%x)", esHandle);
|
||||
|
||||
ElementaryStream* es;
|
||||
std::shared_ptr<ElementaryStream> es;
|
||||
if (!Emu.GetIdManager().GetIDData(esHandle, es))
|
||||
{
|
||||
return CELL_DMUX_ERROR_ARG;
|
||||
@ -927,9 +1040,9 @@ int cellDmuxResetEs(u32 esHandle)
|
||||
|
||||
DemuxerTask task(dmuxResetEs);
|
||||
task.es.es = esHandle;
|
||||
task.es.es_ptr = es;
|
||||
task.es.es_ptr = es.get();
|
||||
|
||||
es->dmux->job.Push(task, &es->dmux->is_closed);
|
||||
es->dmux->job.push(task, &es->dmux->is_closed);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
@ -938,7 +1051,7 @@ int cellDmuxGetAu(u32 esHandle, vm::ptr<u32> auInfo_ptr, vm::ptr<u32> auSpecific
|
||||
cellDmux->Log("cellDmuxGetAu(esHandle=0x%x, auInfo_ptr_addr=0x%x, auSpecificInfo_ptr_addr=0x%x)",
|
||||
esHandle, auInfo_ptr.addr(), auSpecificInfo_ptr.addr());
|
||||
|
||||
ElementaryStream* es;
|
||||
std::shared_ptr<ElementaryStream> es;
|
||||
if (!Emu.GetIdManager().GetIDData(esHandle, es))
|
||||
{
|
||||
return CELL_DMUX_ERROR_ARG;
|
||||
@ -961,7 +1074,7 @@ int cellDmuxPeekAu(u32 esHandle, vm::ptr<u32> auInfo_ptr, vm::ptr<u32> auSpecifi
|
||||
cellDmux->Log("cellDmuxPeekAu(esHandle=0x%x, auInfo_ptr_addr=0x%x, auSpecificInfo_ptr_addr=0x%x)",
|
||||
esHandle, auInfo_ptr.addr(), auSpecificInfo_ptr.addr());
|
||||
|
||||
ElementaryStream* es;
|
||||
std::shared_ptr<ElementaryStream> es;
|
||||
if (!Emu.GetIdManager().GetIDData(esHandle, es))
|
||||
{
|
||||
return CELL_DMUX_ERROR_ARG;
|
||||
@ -984,7 +1097,7 @@ int cellDmuxGetAuEx(u32 esHandle, vm::ptr<u32> auInfoEx_ptr, vm::ptr<u32> auSpec
|
||||
cellDmux->Log("cellDmuxGetAuEx(esHandle=0x%x, auInfoEx_ptr_addr=0x%x, auSpecificInfo_ptr_addr=0x%x)",
|
||||
esHandle, auInfoEx_ptr.addr(), auSpecificInfo_ptr.addr());
|
||||
|
||||
ElementaryStream* es;
|
||||
std::shared_ptr<ElementaryStream> es;
|
||||
if (!Emu.GetIdManager().GetIDData(esHandle, es))
|
||||
{
|
||||
return CELL_DMUX_ERROR_ARG;
|
||||
@ -1007,7 +1120,7 @@ int cellDmuxPeekAuEx(u32 esHandle, vm::ptr<u32> auInfoEx_ptr, vm::ptr<u32> auSpe
|
||||
cellDmux->Log("cellDmuxPeekAuEx(esHandle=0x%x, auInfoEx_ptr_addr=0x%x, auSpecificInfo_ptr_addr=0x%x)",
|
||||
esHandle, auInfoEx_ptr.addr(), auSpecificInfo_ptr.addr());
|
||||
|
||||
ElementaryStream* es;
|
||||
std::shared_ptr<ElementaryStream> es;
|
||||
if (!Emu.GetIdManager().GetIDData(esHandle, es))
|
||||
{
|
||||
return CELL_DMUX_ERROR_ARG;
|
||||
@ -1029,7 +1142,7 @@ int cellDmuxReleaseAu(u32 esHandle)
|
||||
{
|
||||
cellDmux->Log("cellDmuxReleaseAu(esHandle=0x%x)", esHandle);
|
||||
|
||||
ElementaryStream* es;
|
||||
std::shared_ptr<ElementaryStream> es;
|
||||
if (!Emu.GetIdManager().GetIDData(esHandle, es))
|
||||
{
|
||||
return CELL_DMUX_ERROR_ARG;
|
||||
@ -1046,7 +1159,7 @@ int cellDmuxFlushEs(u32 esHandle)
|
||||
{
|
||||
cellDmux->Warning("cellDmuxFlushEs(esHandle=0x%x)", esHandle);
|
||||
|
||||
ElementaryStream* es;
|
||||
std::shared_ptr<ElementaryStream> es;
|
||||
if (!Emu.GetIdManager().GetIDData(esHandle, es))
|
||||
{
|
||||
return CELL_DMUX_ERROR_ARG;
|
||||
@ -1054,9 +1167,9 @@ int cellDmuxFlushEs(u32 esHandle)
|
||||
|
||||
DemuxerTask task(dmuxFlushEs);
|
||||
task.es.es = esHandle;
|
||||
task.es.es_ptr = es;
|
||||
task.es.es_ptr = es.get();
|
||||
|
||||
es->dmux->job.Push(task, &es->dmux->is_closed);
|
||||
es->dmux->job.push(task, &es->dmux->is_closed);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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];
|
||||
|
@ -1,157 +1,203 @@
|
||||
#include "stdafx.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/SysCalls/Modules.h"
|
||||
|
||||
#include "cellPamf.h"
|
||||
|
||||
Module *cellPamf = nullptr;
|
||||
|
||||
int pamfStreamTypeToEsFilterId(u8 type, u8 ch, vm::ptr<CellCodecEsFilterId> pEsFilterId)
|
||||
s32 pamfStreamTypeToEsFilterId(u8 type, u8 ch, CellCodecEsFilterId& pEsFilterId)
|
||||
{
|
||||
//TODO: convert type and ch to EsFilterId
|
||||
pEsFilterId->filterIdMajor = 0;
|
||||
pEsFilterId->filterIdMinor = 0;
|
||||
pEsFilterId->supplementalInfo1 = 0;
|
||||
pEsFilterId->supplementalInfo2 = 0;
|
||||
// convert type and ch to EsFilterId
|
||||
assert(ch < 16);
|
||||
pEsFilterId.supplementalInfo1 = type == CELL_PAMF_STREAM_TYPE_AVC;
|
||||
pEsFilterId.supplementalInfo2 = 0;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case CELL_PAMF_STREAM_TYPE_AVC:
|
||||
{
|
||||
if (ch < 16)
|
||||
{
|
||||
pEsFilterId->filterIdMajor = 0xe0 + ch;
|
||||
pEsFilterId->filterIdMinor = 0;
|
||||
pEsFilterId->supplementalInfo1 = 0x01;
|
||||
pEsFilterId->supplementalInfo2 = 0;
|
||||
}
|
||||
else
|
||||
cellPamf->Error("pamfStreamTypeToEsFilterId: invalid CELL_PAMF_STREAM_TYPE_AVC channel (ch=%d)", ch);
|
||||
}
|
||||
break;
|
||||
case CELL_PAMF_STREAM_TYPE_ATRAC3PLUS:
|
||||
if (ch == 0)
|
||||
{
|
||||
pEsFilterId->filterIdMajor = 0xbd;
|
||||
pEsFilterId->filterIdMinor = 0;
|
||||
pEsFilterId->supplementalInfo1 = 0;
|
||||
pEsFilterId->supplementalInfo2 = 0;
|
||||
}
|
||||
else
|
||||
cellPamf->Todo("pamfStreamTypeToEsFilterId: CELL_PAMF_STREAM_TYPE_ATRAC3PLUS (ch=%d)", ch);
|
||||
break;
|
||||
case CELL_PAMF_STREAM_TYPE_PAMF_LPCM:
|
||||
if (ch == 0)
|
||||
{
|
||||
pEsFilterId->filterIdMajor = 0xbd;
|
||||
pEsFilterId->filterIdMinor = 0x40;
|
||||
pEsFilterId->supplementalInfo1 = 0;
|
||||
pEsFilterId->supplementalInfo2 = 0;
|
||||
}
|
||||
else
|
||||
cellPamf->Todo("pamfStreamTypeToEsFilterId: CELL_PAMF_STREAM_TYPE_LPCM (ch=%d)", ch);
|
||||
break;
|
||||
case CELL_PAMF_STREAM_TYPE_USER_DATA:
|
||||
if (ch == 0)
|
||||
{
|
||||
pEsFilterId->filterIdMajor = 0xbd;
|
||||
pEsFilterId->filterIdMinor = 0x20;
|
||||
pEsFilterId->supplementalInfo1 = 0;
|
||||
pEsFilterId->supplementalInfo2 = 0;
|
||||
}
|
||||
else
|
||||
cellPamf->Todo("pamfStreamTypeToEsFilterId: CELL_PAMF_STREAM_TYPE_USER_DATA (ch=%d)", ch);
|
||||
break;
|
||||
case CELL_PAMF_STREAM_TYPE_AC3:
|
||||
cellPamf->Todo("pamfStreamTypeToEsFilterId: CELL_PAMF_STREAM_TYPE_AC3 (ch=%d)", ch);
|
||||
{
|
||||
// code = 0x1b
|
||||
pEsFilterId.filterIdMajor = 0xe0 | ch;
|
||||
pEsFilterId.filterIdMinor = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case CELL_PAMF_STREAM_TYPE_M2V:
|
||||
cellPamf->Todo("pamfStreamTypeToEsFilterId: CELL_PAMF_STREAM_TYPE_M2V (ch=%d)", ch);
|
||||
{
|
||||
// code = 0x02
|
||||
pEsFilterId.filterIdMajor = 0xe0 | ch;
|
||||
pEsFilterId.filterIdMinor = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case CELL_PAMF_STREAM_TYPE_ATRAC3PLUS:
|
||||
{
|
||||
// code = 0xdc
|
||||
pEsFilterId.filterIdMajor = 0xbd;
|
||||
pEsFilterId.filterIdMinor = ch;
|
||||
break;
|
||||
}
|
||||
|
||||
case CELL_PAMF_STREAM_TYPE_PAMF_LPCM:
|
||||
{
|
||||
// code = 0x80
|
||||
pEsFilterId.filterIdMajor = 0xbd;
|
||||
pEsFilterId.filterIdMinor = 0x40 | ch;
|
||||
break;
|
||||
}
|
||||
|
||||
case CELL_PAMF_STREAM_TYPE_AC3:
|
||||
{
|
||||
// code = 0x81
|
||||
pEsFilterId.filterIdMajor = 0xbd;
|
||||
pEsFilterId.filterIdMinor = 0x30 | ch;
|
||||
break;
|
||||
}
|
||||
|
||||
case CELL_PAMF_STREAM_TYPE_USER_DATA:
|
||||
{
|
||||
// code = 0xdd
|
||||
pEsFilterId.filterIdMajor = 0xbd;
|
||||
pEsFilterId.filterIdMinor = 0x20 | ch;
|
||||
break;
|
||||
}
|
||||
|
||||
case 6:
|
||||
{
|
||||
// code = 0xff
|
||||
pEsFilterId.filterIdMajor = 0xe0 | ch;
|
||||
pEsFilterId.filterIdMinor = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case 7:
|
||||
{
|
||||
// code = 0xff
|
||||
pEsFilterId.filterIdMajor = 0xbd;
|
||||
pEsFilterId.filterIdMinor = ch;
|
||||
break;
|
||||
}
|
||||
|
||||
case 8:
|
||||
{
|
||||
// code = 0xff
|
||||
pEsFilterId.filterIdMajor = 0xbd;
|
||||
pEsFilterId.filterIdMinor = 0x10 | ch;
|
||||
break;
|
||||
}
|
||||
|
||||
case 9:
|
||||
{
|
||||
// code = 0xff
|
||||
pEsFilterId.filterIdMajor = 0xbd;
|
||||
pEsFilterId.filterIdMinor = 0x20 | ch;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
cellPamf->Error("pamfStreamTypeToEsFilterId(): unknown type (%d, ch=%d)", type, ch);
|
||||
Emu.Pause();
|
||||
return CELL_PAMF_ERROR_INVALID_ARG;
|
||||
}
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
u8 pamfGetStreamType(vm::ptr<CellPamfReader> pSelf, u8 stream)
|
||||
u8 pamfGetStreamType(vm::ptr<CellPamfReader> pSelf, u32 stream)
|
||||
{
|
||||
//TODO: get stream type correctly
|
||||
switch (pSelf->pAddr->stream_headers[stream].type)
|
||||
// TODO: get stream type correctly
|
||||
assert(stream < (u32)pSelf->pAddr->stream_count);
|
||||
auto& header = pSelf->pAddr->stream_headers[stream];
|
||||
|
||||
switch (header.type)
|
||||
{
|
||||
case 0x1b: return CELL_PAMF_STREAM_TYPE_AVC;
|
||||
case 0x02: return CELL_PAMF_STREAM_TYPE_M2V;
|
||||
case 0xdc: return CELL_PAMF_STREAM_TYPE_ATRAC3PLUS;
|
||||
case 0x80: return CELL_PAMF_STREAM_TYPE_PAMF_LPCM;
|
||||
case 0x81: return CELL_PAMF_STREAM_TYPE_AC3;
|
||||
case 0xdd: return CELL_PAMF_STREAM_TYPE_USER_DATA;
|
||||
default:
|
||||
cellPamf->Todo("pamfGetStreamType: unsupported stream type found(0x%x)", pSelf->pAddr->stream_headers[stream].type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
cellPamf->Todo("pamfGetStreamType(): unsupported stream type found(0x%x)", header.type);
|
||||
Emu.Pause();
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
u8 pamfGetStreamChannel(vm::ptr<CellPamfReader> pSelf, u8 stream)
|
||||
u8 pamfGetStreamChannel(vm::ptr<CellPamfReader> pSelf, u32 stream)
|
||||
{
|
||||
//TODO: get stream channel correctly
|
||||
// TODO: get stream channel correctly
|
||||
assert(stream < (u32)pSelf->pAddr->stream_count);
|
||||
auto& header = pSelf->pAddr->stream_headers[stream];
|
||||
|
||||
switch (pSelf->pAddr->stream_headers[stream].type)
|
||||
switch (header.type)
|
||||
{
|
||||
case 0x1b:
|
||||
if ((pSelf->pAddr->stream_headers[stream].stream_id >= 0xe0) && (pSelf->pAddr->stream_headers[stream].stream_id <= 0xef))
|
||||
{
|
||||
return pSelf->pAddr->stream_headers[stream].stream_id - 0xe0;
|
||||
}
|
||||
else
|
||||
{
|
||||
cellPamf->Error("pamfGetStreamChannel: stream type 0x%x got invalid stream id=0x%x",
|
||||
pSelf->pAddr->stream_headers[stream].type, pSelf->pAddr->stream_headers[stream].stream_id);
|
||||
return 0;
|
||||
}
|
||||
case 0xdc:
|
||||
cellPamf->Todo("pamfGetStreamChannel: CELL_PAMF_STREAM_TYPE_ATRAC3PLUS");
|
||||
return 0;
|
||||
case 0x80:
|
||||
cellPamf->Todo("pamfGetStreamChannel: CELL_PAMF_STREAM_TYPE_PAMF_LPCM");
|
||||
return 0;
|
||||
case 0xdd:
|
||||
cellPamf->Todo("pamfGetStreamChannel: CELL_PAMF_STREAM_TYPE_USER_DATA");
|
||||
return 0;
|
||||
default:
|
||||
cellPamf->Todo("pamfGetStreamType: unsupported stream type found(0x%x)", pSelf->pAddr->stream_headers[stream].type);
|
||||
return 0;
|
||||
case 0x1b: // AVC
|
||||
case 0x02: // M2V
|
||||
{
|
||||
assert((header.fid_major & 0xf0) == 0xe0 && header.fid_minor == 0);
|
||||
return header.fid_major % 16;
|
||||
}
|
||||
|
||||
case 0xdc: // ATRAC3PLUS
|
||||
{
|
||||
assert(header.fid_major == 0xbd && (header.fid_minor & 0xf0) == 0);
|
||||
return header.fid_minor % 16;
|
||||
}
|
||||
|
||||
case 0x80: // LPCM
|
||||
{
|
||||
assert(header.fid_major == 0xbd && (header.fid_minor & 0xf0) == 0x40);
|
||||
return header.fid_minor % 16;
|
||||
}
|
||||
case 0x81: // AC3
|
||||
{
|
||||
assert(header.fid_major == 0xbd && (header.fid_minor & 0xf0) == 0x30);
|
||||
return header.fid_minor % 16;
|
||||
}
|
||||
case 0xdd:
|
||||
{
|
||||
assert(header.fid_major == 0xbd && (header.fid_minor & 0xf0) == 0x20);
|
||||
return header.fid_minor % 16;
|
||||
}
|
||||
}
|
||||
|
||||
cellPamf->Todo("pamfGetStreamChannel(): unsupported stream type found(0x%x)", header.type);
|
||||
Emu.Pause();
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
int cellPamfGetHeaderSize(vm::ptr<PamfHeader> pAddr, u64 fileSize, vm::ptr<u64> pSize)
|
||||
s32 cellPamfGetHeaderSize(vm::ptr<PamfHeader> pAddr, u64 fileSize, vm::ptr<u64> pSize)
|
||||
{
|
||||
cellPamf->Warning("cellPamfGetHeaderSize(pAddr=0x%x, fileSize=%d, pSize_addr=0x%x)", pAddr.addr(), fileSize, pSize.addr());
|
||||
|
||||
//if ((u32)pAddr->magic != 0x464d4150)
|
||||
//return CELL_PAMF_ERROR_UNKNOWN_TYPE;
|
||||
//if ((u32)pAddr->magic != 0x464d4150) return CELL_PAMF_ERROR_UNKNOWN_TYPE;
|
||||
|
||||
const u64 offset = (u64)pAddr->data_offset << 11;
|
||||
*pSize = offset;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellPamfGetHeaderSize2(vm::ptr<PamfHeader> pAddr, u64 fileSize, u32 attribute, vm::ptr<u64> pSize)
|
||||
s32 cellPamfGetHeaderSize2(vm::ptr<PamfHeader> pAddr, u64 fileSize, u32 attribute, vm::ptr<u64> pSize)
|
||||
{
|
||||
cellPamf->Warning("cellPamfGetHeaderSize2(pAddr=0x%x, fileSize=%d, attribute=0x%x, pSize_addr=0x%x)", pAddr.addr(), fileSize, attribute, pSize.addr());
|
||||
|
||||
//if ((u32)pAddr->magic != 0x464d4150)
|
||||
//return CELL_PAMF_ERROR_UNKNOWN_TYPE;
|
||||
//if ((u32)pAddr->magic != 0x464d4150) return CELL_PAMF_ERROR_UNKNOWN_TYPE;
|
||||
|
||||
const u64 offset = (u64)pAddr->data_offset << 11;
|
||||
*pSize = offset;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellPamfGetStreamOffsetAndSize(vm::ptr<PamfHeader> pAddr, u64 fileSize, vm::ptr<u64> pOffset, vm::ptr<u64> pSize)
|
||||
s32 cellPamfGetStreamOffsetAndSize(vm::ptr<PamfHeader> pAddr, u64 fileSize, vm::ptr<u64> pOffset, vm::ptr<u64> pSize)
|
||||
{
|
||||
cellPamf->Warning("cellPamfGetStreamOffsetAndSize(pAddr=0x%x, fileSize=%d, pOffset_addr=0x%x, pSize_addr=0x%x)", pAddr.addr(), fileSize, pOffset.addr(), pSize.addr());
|
||||
|
||||
//if ((u32)pAddr->magic != 0x464d4150)
|
||||
//return CELL_PAMF_ERROR_UNKNOWN_TYPE;
|
||||
//if ((u32)pAddr->magic != 0x464d4150) return CELL_PAMF_ERROR_UNKNOWN_TYPE;
|
||||
|
||||
const u64 offset = (u64)pAddr->data_offset << 11;
|
||||
*pOffset = offset;
|
||||
@ -160,14 +206,15 @@ int cellPamfGetStreamOffsetAndSize(vm::ptr<PamfHeader> pAddr, u64 fileSize, vm::
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellPamfVerify(vm::ptr<PamfHeader> pAddr, u64 fileSize)
|
||||
s32 cellPamfVerify(vm::ptr<PamfHeader> pAddr, u64 fileSize)
|
||||
{
|
||||
cellPamf->Warning("cellPamfVerify(pAddr=0x%x, fileSize=%d)", pAddr.addr(), fileSize);
|
||||
cellPamf->Todo("cellPamfVerify(pAddr=0x%x, fileSize=%d)", pAddr.addr(), fileSize);
|
||||
|
||||
// TODO
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellPamfReaderInitialize(vm::ptr<CellPamfReader> pSelf, vm::ptr<const PamfHeader> pAddr, u64 fileSize, u32 attribute)
|
||||
s32 cellPamfReaderInitialize(vm::ptr<CellPamfReader> pSelf, vm::ptr<const PamfHeader> pAddr, u64 fileSize, u32 attribute)
|
||||
{
|
||||
cellPamf->Warning("cellPamfReaderInitialize(pSelf=0x%x, pAddr=0x%x, fileSize=%d, attribute=0x%x)", pSelf.addr(), pAddr.addr(), fileSize, attribute);
|
||||
|
||||
@ -175,7 +222,7 @@ int cellPamfReaderInitialize(vm::ptr<CellPamfReader> pSelf, vm::ptr<const PamfHe
|
||||
{
|
||||
pSelf->fileSize = fileSize;
|
||||
}
|
||||
else //if fileSize is unknown
|
||||
else // if fileSize is unknown
|
||||
{
|
||||
pSelf->fileSize = ((u64)pAddr->data_offset << 11) + ((u64)pAddr->data_size << 11);
|
||||
}
|
||||
@ -183,70 +230,59 @@ int cellPamfReaderInitialize(vm::ptr<CellPamfReader> pSelf, vm::ptr<const PamfHe
|
||||
|
||||
if (attribute & CELL_PAMF_ATTRIBUTE_VERIFY_ON)
|
||||
{
|
||||
//TODO
|
||||
// TODO
|
||||
cellPamf->Todo("cellPamfReaderInitialize(): verification");
|
||||
}
|
||||
|
||||
pSelf->stream = 0; //??? currently set stream
|
||||
pSelf->stream = 0; // currently set stream
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellPamfReaderGetPresentationStartTime(vm::ptr<CellPamfReader> pSelf, vm::ptr<CellCodecTimeStamp> pTimeStamp)
|
||||
s32 cellPamfReaderGetPresentationStartTime(vm::ptr<CellPamfReader> pSelf, vm::ptr<CellCodecTimeStamp> pTimeStamp)
|
||||
{
|
||||
cellPamf->Warning("cellPamfReaderGetPresentationStartTime(pSelf=0x%x, pTimeStamp_addr=0x%x)", pSelf.addr(), pTimeStamp.addr());
|
||||
|
||||
if (!pSelf->pAddr) {
|
||||
return CELL_PAMF_ERROR_INVALID_PAMF;
|
||||
}
|
||||
// always returns CELL_OK
|
||||
|
||||
pTimeStamp->upper = (u32)(u16)pSelf->pAddr->start_pts_high;
|
||||
pTimeStamp->lower = pSelf->pAddr->start_pts_low;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellPamfReaderGetPresentationEndTime(vm::ptr<CellPamfReader> pSelf, vm::ptr<CellCodecTimeStamp> pTimeStamp)
|
||||
s32 cellPamfReaderGetPresentationEndTime(vm::ptr<CellPamfReader> pSelf, vm::ptr<CellCodecTimeStamp> pTimeStamp)
|
||||
{
|
||||
cellPamf->Warning("cellPamfReaderGetPresentationEndTime(pSelf=0x%x, pTimeStamp_addr=0x%x)", pSelf.addr(), pTimeStamp.addr());
|
||||
|
||||
if (!pSelf->pAddr) {
|
||||
return CELL_PAMF_ERROR_INVALID_PAMF;
|
||||
}
|
||||
// always returns CELL_OK
|
||||
|
||||
pTimeStamp->upper = (u32)(u16)pSelf->pAddr->end_pts_high;
|
||||
pTimeStamp->lower = pSelf->pAddr->end_pts_low;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellPamfReaderGetMuxRateBound(vm::ptr<CellPamfReader> pSelf)
|
||||
u32 cellPamfReaderGetMuxRateBound(vm::ptr<CellPamfReader> pSelf)
|
||||
{
|
||||
cellPamf->Warning("cellPamfReaderGetMuxRateBound(pSelf=0x%x)", pSelf.addr());
|
||||
|
||||
if (!pSelf->pAddr) {
|
||||
return CELL_PAMF_ERROR_INVALID_PAMF;
|
||||
}
|
||||
|
||||
// cannot return error code
|
||||
return pSelf->pAddr->mux_rate_max;
|
||||
}
|
||||
|
||||
int cellPamfReaderGetNumberOfStreams(vm::ptr<CellPamfReader> pSelf)
|
||||
u8 cellPamfReaderGetNumberOfStreams(vm::ptr<CellPamfReader> pSelf)
|
||||
{
|
||||
cellPamf->Warning("cellPamfReaderGetNumberOfStreams(pSelf=0x%x)", pSelf.addr());
|
||||
|
||||
if (!pSelf->pAddr) {
|
||||
return CELL_PAMF_ERROR_INVALID_PAMF;
|
||||
}
|
||||
|
||||
// cannot return error code
|
||||
return pSelf->pAddr->stream_count;
|
||||
}
|
||||
|
||||
int cellPamfReaderGetNumberOfSpecificStreams(vm::ptr<CellPamfReader> pSelf, u8 streamType)
|
||||
u8 cellPamfReaderGetNumberOfSpecificStreams(vm::ptr<CellPamfReader> pSelf, u8 streamType)
|
||||
{
|
||||
cellPamf->Warning("cellPamfReaderGetNumberOfSpecificStreams(pSelf=0x%x, streamType=%d)", pSelf.addr(), streamType);
|
||||
|
||||
if (!pSelf->pAddr) {
|
||||
return CELL_PAMF_ERROR_INVALID_PAMF;
|
||||
}
|
||||
// cannot return error code
|
||||
|
||||
int counts[6] = {0, 0, 0, 0, 0, 0};
|
||||
u8 counts[256] = {};
|
||||
|
||||
for (u8 i = 0; i < pSelf->pAddr->stream_count; i++)
|
||||
{
|
||||
@ -261,46 +297,48 @@ int cellPamfReaderGetNumberOfSpecificStreams(vm::ptr<CellPamfReader> pSelf, u8 s
|
||||
case CELL_PAMF_STREAM_TYPE_PAMF_LPCM:
|
||||
case CELL_PAMF_STREAM_TYPE_AC3:
|
||||
case CELL_PAMF_STREAM_TYPE_USER_DATA:
|
||||
{
|
||||
return counts[streamType];
|
||||
case CELL_PAMF_STREAM_TYPE_VIDEO:
|
||||
return counts[CELL_PAMF_STREAM_TYPE_AVC] + counts[CELL_PAMF_STREAM_TYPE_M2V];
|
||||
case CELL_PAMF_STREAM_TYPE_AUDIO:
|
||||
return counts[CELL_PAMF_STREAM_TYPE_ATRAC3PLUS] + counts[CELL_PAMF_STREAM_TYPE_PAMF_LPCM] + counts[CELL_PAMF_STREAM_TYPE_AC3];
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
case CELL_PAMF_STREAM_TYPE_VIDEO:
|
||||
{
|
||||
return counts[CELL_PAMF_STREAM_TYPE_AVC] + counts[CELL_PAMF_STREAM_TYPE_M2V];
|
||||
}
|
||||
|
||||
case CELL_PAMF_STREAM_TYPE_AUDIO:
|
||||
{
|
||||
return counts[CELL_PAMF_STREAM_TYPE_ATRAC3PLUS] + counts[CELL_PAMF_STREAM_TYPE_PAMF_LPCM] + counts[CELL_PAMF_STREAM_TYPE_AC3];
|
||||
}
|
||||
}
|
||||
|
||||
cellPamf->Todo("cellPamfReaderGetNumberOfSpecificStreams(): unsupported stream type (0x%x)", streamType);
|
||||
Emu.Pause();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cellPamfReaderSetStreamWithIndex(vm::ptr<CellPamfReader> pSelf, u8 streamIndex)
|
||||
s32 cellPamfReaderSetStreamWithIndex(vm::ptr<CellPamfReader> pSelf, u8 streamIndex)
|
||||
{
|
||||
cellPamf->Warning("cellPamfReaderSetStreamWithIndex(pSelf=0x%x, streamIndex=%d)", pSelf.addr(), streamIndex);
|
||||
|
||||
if (!pSelf->pAddr) {
|
||||
return CELL_PAMF_ERROR_INVALID_PAMF;
|
||||
}
|
||||
|
||||
if (streamIndex < pSelf->pAddr->stream_count)
|
||||
if (streamIndex >= pSelf->pAddr->stream_count)
|
||||
{
|
||||
pSelf->stream = streamIndex;
|
||||
return CELL_OK;
|
||||
return CELL_PAMF_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
cellPamf->Error("cellPamfReaderSetStreamWithIndex: CELL_PAMF_ERROR_INVALID_ARG");
|
||||
return CELL_PAMF_ERROR_INVALID_ARG;
|
||||
pSelf->stream = streamIndex;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellPamfReaderSetStreamWithTypeAndChannel(vm::ptr<CellPamfReader> pSelf, u8 streamType, u8 ch)
|
||||
s32 cellPamfReaderSetStreamWithTypeAndChannel(vm::ptr<CellPamfReader> pSelf, u8 streamType, u8 ch)
|
||||
{
|
||||
cellPamf->Warning("cellPamfReaderSetStreamWithTypeAndChannel(pSelf=0x%x, streamType=%d, ch=%d)", pSelf.addr(), streamType, ch);
|
||||
|
||||
if (!pSelf->pAddr) {
|
||||
return CELL_PAMF_ERROR_INVALID_PAMF;
|
||||
}
|
||||
|
||||
if (streamType > 5)
|
||||
// it probably doesn't support "any audio" or "any video" argument
|
||||
if (streamType > 5 || ch >= 16)
|
||||
{
|
||||
cellPamf->Error("cellPamfReaderSetStreamWithTypeAndChannel: invalid stream type(%d)", streamType);
|
||||
//it probably doesn't support "any audio" or "any video" argument
|
||||
cellPamf->Error("cellPamfReaderSetStreamWithTypeAndChannel(): invalid arguments (streamType=%d, ch=%d)", streamType, ch);
|
||||
Emu.Pause();
|
||||
return CELL_PAMF_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
@ -319,14 +357,10 @@ int cellPamfReaderSetStreamWithTypeAndChannel(vm::ptr<CellPamfReader> pSelf, u8
|
||||
return CELL_PAMF_ERROR_STREAM_NOT_FOUND;
|
||||
}
|
||||
|
||||
int cellPamfReaderSetStreamWithTypeAndIndex(vm::ptr<CellPamfReader> pSelf, u8 streamType, u8 streamIndex)
|
||||
s32 cellPamfReaderSetStreamWithTypeAndIndex(vm::ptr<CellPamfReader> pSelf, u8 streamType, u8 streamIndex)
|
||||
{
|
||||
cellPamf->Warning("cellPamfReaderSetStreamWithTypeAndIndex(pSelf=0x%x, streamType=%d, streamIndex=%d)", pSelf.addr(), streamType, streamIndex);
|
||||
|
||||
if (!pSelf->pAddr) {
|
||||
return CELL_PAMF_ERROR_INVALID_PAMF;
|
||||
}
|
||||
|
||||
u32 found = 0;
|
||||
|
||||
for (u8 i = 0; i < pSelf->pAddr->stream_count; i++)
|
||||
@ -340,23 +374,31 @@ int cellPamfReaderSetStreamWithTypeAndIndex(vm::ptr<CellPamfReader> pSelf, u8 st
|
||||
else switch(streamType)
|
||||
{
|
||||
case CELL_PAMF_STREAM_TYPE_VIDEO:
|
||||
{
|
||||
if (type == CELL_PAMF_STREAM_TYPE_AVC || type == CELL_PAMF_STREAM_TYPE_M2V)
|
||||
{
|
||||
found++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case CELL_PAMF_STREAM_TYPE_AUDIO:
|
||||
{
|
||||
if (type == CELL_PAMF_STREAM_TYPE_ATRAC3PLUS || type == CELL_PAMF_STREAM_TYPE_AC3 || type == CELL_PAMF_STREAM_TYPE_PAMF_LPCM)
|
||||
{
|
||||
found++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
if (streamType > 5)
|
||||
{
|
||||
return CELL_PAMF_ERROR_INVALID_ARG;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (found > streamIndex)
|
||||
{
|
||||
@ -368,199 +410,328 @@ int cellPamfReaderSetStreamWithTypeAndIndex(vm::ptr<CellPamfReader> pSelf, u8 st
|
||||
return CELL_PAMF_ERROR_STREAM_NOT_FOUND;
|
||||
}
|
||||
|
||||
int cellPamfStreamTypeToEsFilterId(u8 type, u8 ch, vm::ptr<CellCodecEsFilterId> pEsFilterId)
|
||||
s32 cellPamfStreamTypeToEsFilterId(u8 type, u8 ch, vm::ptr<CellCodecEsFilterId> pEsFilterId)
|
||||
{
|
||||
cellPamf->Warning("cellPamfStreamTypeToEsFilterId(type=%d, ch=%d, pEsFilterId_addr=0x%x)", type, ch, pEsFilterId.addr());
|
||||
|
||||
return pamfStreamTypeToEsFilterId(type, ch, pEsFilterId);
|
||||
if (!pEsFilterId)
|
||||
{
|
||||
return CELL_PAMF_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
return pamfStreamTypeToEsFilterId(type, ch, *pEsFilterId);
|
||||
}
|
||||
|
||||
int cellPamfReaderGetStreamIndex(vm::ptr<CellPamfReader> pSelf)
|
||||
s32 cellPamfReaderGetStreamIndex(vm::ptr<CellPamfReader> pSelf)
|
||||
{
|
||||
cellPamf->Log("cellPamfReaderGetStreamIndex(pSelf=0x%x)", pSelf.addr());
|
||||
|
||||
// seems that CELL_PAMF_ERROR_INVALID_PAMF must be already written in pSelf->stream if it's the case
|
||||
return pSelf->stream;
|
||||
}
|
||||
|
||||
int cellPamfReaderGetStreamTypeAndChannel(vm::ptr<CellPamfReader> pSelf, vm::ptr<u8> pType, vm::ptr<u8> pCh)
|
||||
s32 cellPamfReaderGetStreamTypeAndChannel(vm::ptr<CellPamfReader> pSelf, vm::ptr<u8> pType, vm::ptr<u8> pCh)
|
||||
{
|
||||
cellPamf->Warning("cellPamfReaderGetStreamTypeAndChannel(pSelf=0x%x (stream=%d), pType_addr=0x%x, pCh_addr=0x%x",
|
||||
pSelf.addr(), pSelf->stream, pType.addr(), pCh.addr());
|
||||
|
||||
// unclear
|
||||
|
||||
*pType = pamfGetStreamType(pSelf, pSelf->stream);
|
||||
*pCh = pamfGetStreamChannel(pSelf, pSelf->stream);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellPamfReaderGetEsFilterId(vm::ptr<CellPamfReader> pSelf, vm::ptr<CellCodecEsFilterId> pEsFilterId)
|
||||
s32 cellPamfReaderGetEsFilterId(vm::ptr<CellPamfReader> pSelf, vm::ptr<CellCodecEsFilterId> pEsFilterId)
|
||||
{
|
||||
cellPamf->Warning("cellPamfReaderGetEsFilterId(pSelf=0x%x (stream=%d), pEsFilterId_addr=0x%x)", pSelf.addr(), pSelf->stream, pEsFilterId.addr());
|
||||
|
||||
return pamfStreamTypeToEsFilterId(pamfGetStreamType(pSelf, pSelf->stream),
|
||||
pamfGetStreamChannel(pSelf, pSelf->stream), pEsFilterId);
|
||||
// always returns CELL_OK
|
||||
|
||||
assert((u32)pSelf->stream < (u32)pSelf->pAddr->stream_count);
|
||||
auto& header = pSelf->pAddr->stream_headers[pSelf->stream];
|
||||
pEsFilterId->filterIdMajor = header.fid_major;
|
||||
pEsFilterId->filterIdMinor = header.fid_minor;
|
||||
pEsFilterId->supplementalInfo1 = header.type == 0x1b ? 1 : 0;
|
||||
pEsFilterId->supplementalInfo2 = 0;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellPamfReaderGetStreamInfo(vm::ptr<CellPamfReader> pSelf, u32 pInfo_addr, u32 size)
|
||||
s32 cellPamfReaderGetStreamInfo(vm::ptr<CellPamfReader> pSelf, u32 pInfo_addr, u32 size)
|
||||
{
|
||||
cellPamf->Warning("cellPamfReaderGetStreamInfo(pSelf=0x%x, stream=%d, pInfo_addr=0x%x, size=%d)", pSelf.addr(), pSelf->stream, pInfo_addr, size);
|
||||
|
||||
if (!pSelf->pAddr) {
|
||||
return CELL_PAMF_ERROR_INVALID_PAMF;
|
||||
}
|
||||
assert((u32)pSelf->stream < (u32)pSelf->pAddr->stream_count);
|
||||
auto& header = pSelf->pAddr->stream_headers[pSelf->stream];
|
||||
const u8 type = pamfGetStreamType(pSelf, pSelf->stream);
|
||||
const u8 ch = pamfGetStreamChannel(pSelf, pSelf->stream);
|
||||
|
||||
memset(vm::get_ptr<void>(pInfo_addr), 0, size);
|
||||
|
||||
switch (pamfGetStreamType(pSelf, pSelf->stream))
|
||||
switch (type)
|
||||
{
|
||||
case CELL_PAMF_STREAM_TYPE_AVC:
|
||||
{
|
||||
if (size < sizeof(CellPamfAvcInfo))
|
||||
{
|
||||
auto pInfo = vm::ptr<CellPamfAvcInfo>::make(pInfo_addr);
|
||||
auto pAVC = vm::ptr<PamfStreamHeader_AVC>::make(pSelf->pAddr.addr() + 0x98 + pSelf->stream * 0x30);
|
||||
|
||||
if (size != sizeof(CellPamfAvcInfo))
|
||||
{
|
||||
cellPamf->Error("cellPamfReaderGetStreamInfo: wrong AVC data size(%d)", size);
|
||||
return CELL_PAMF_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
pInfo->profileIdc = pAVC->profileIdc;
|
||||
pInfo->levelIdc = pAVC->levelIdc;
|
||||
|
||||
pInfo->frameMbsOnlyFlag = 1; //fake
|
||||
pInfo->frameRateInfo = (pAVC->unk0 & 0x7) - 1;
|
||||
pInfo->aspectRatioIdc = 1; //fake
|
||||
|
||||
pInfo->horizontalSize = 16 * (u16)pAVC->horizontalSize;
|
||||
pInfo->verticalSize = 16 * (u16)pAVC->verticalSize;
|
||||
|
||||
pInfo->videoSignalInfoFlag = 1; //fake
|
||||
pInfo->colourPrimaries = 1; //fake
|
||||
pInfo->transferCharacteristics = 1; //fake
|
||||
pInfo->matrixCoefficients = 1; //fake
|
||||
//pInfo->deblockingFilterFlag = 1; //???
|
||||
|
||||
cellPamf->Warning("cellPamfReaderGetStreamInfo: CELL_PAMF_STREAM_TYPE_AVC");
|
||||
}
|
||||
break;
|
||||
case CELL_PAMF_STREAM_TYPE_M2V:
|
||||
{
|
||||
//TODO
|
||||
cellPamf->Error("TODO: cellPamfReaderGetStreamInfo: CELL_PAMF_STREAM_TYPE_M2V");
|
||||
}
|
||||
break;
|
||||
case CELL_PAMF_STREAM_TYPE_ATRAC3PLUS:
|
||||
{
|
||||
auto pInfo = vm::ptr<CellPamfAtrac3plusInfo>::make(pInfo_addr);
|
||||
auto pAudio = vm::ptr<PamfStreamHeader_Audio>::make(pSelf->pAddr.addr() + 0x98 + pSelf->stream * 0x30);
|
||||
|
||||
if (size != sizeof(CellPamfAtrac3plusInfo))
|
||||
{
|
||||
cellPamf->Error("cellPamfReaderGetStreamInfo: wrong ATRAC3+ data size(%d)", size);
|
||||
return CELL_PAMF_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
pInfo->numberOfChannels = pAudio->channels;
|
||||
pInfo->samplingFrequency = CELL_PAMF_FS_48kHz;
|
||||
}
|
||||
break;
|
||||
case CELL_PAMF_STREAM_TYPE_AC3:
|
||||
{
|
||||
auto pInfo = vm::ptr<CellPamfAc3Info>::make(pInfo_addr);
|
||||
auto pAudio = vm::ptr<PamfStreamHeader_Audio>::make(pSelf->pAddr.addr() + 0x98 + pSelf->stream * 0x30);
|
||||
|
||||
if (size != sizeof(CellPamfAc3Info))
|
||||
{
|
||||
cellPamf->Error("cellPamfReaderGetStreamInfo: wrong AC3 data size(%d)", size);
|
||||
return CELL_PAMF_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
pInfo->numberOfChannels = pAudio->channels;
|
||||
pInfo->samplingFrequency = CELL_PAMF_FS_48kHz;
|
||||
}
|
||||
break;
|
||||
case CELL_PAMF_STREAM_TYPE_PAMF_LPCM:
|
||||
{
|
||||
auto pInfo = vm::ptr<CellPamfLpcmInfo>::make(pInfo_addr);
|
||||
auto pAudio = vm::ptr<PamfStreamHeader_Audio>::make(pSelf->pAddr.addr() + 0x98 + pSelf->stream * 0x30);
|
||||
|
||||
if (size != sizeof(CellPamfLpcmInfo))
|
||||
{
|
||||
cellPamf->Error("cellPamfReaderGetStreamInfo: wrong LPCM data size(%d)", size);
|
||||
return CELL_PAMF_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
pInfo->numberOfChannels = pAudio->channels;
|
||||
pInfo->samplingFrequency = CELL_PAMF_FS_48kHz;
|
||||
|
||||
if (pAudio->bps == 0x40)
|
||||
pInfo->bitsPerSample = CELL_PAMF_BIT_LENGTH_16;
|
||||
else
|
||||
//TODO: CELL_PAMF_BIT_LENGTH_24
|
||||
cellPamf->Error("cellPamfReaderGetStreamInfo: unknown bps(0x%x)", (u8)pAudio->bps);
|
||||
}
|
||||
break;
|
||||
case CELL_PAMF_STREAM_TYPE_USER_DATA:
|
||||
{
|
||||
cellPamf->Error("cellPamfReaderGetStreamInfo: CELL_PAMF_STREAM_TYPE_USER_DATA");
|
||||
return CELL_PAMF_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
auto info = vm::ptr<CellPamfAvcInfo>::make(pInfo_addr);
|
||||
|
||||
info->profileIdc = header.AVC.profileIdc;
|
||||
info->levelIdc = header.AVC.levelIdc;
|
||||
info->frameMbsOnlyFlag = (header.AVC.x2 & 0x80) >> 7;
|
||||
info->videoSignalInfoFlag = (header.AVC.x2 & 0x40) >> 6;
|
||||
info->frameRateInfo = (header.AVC.x2 & 0x0f) - 1;
|
||||
info->aspectRatioIdc = header.AVC.aspectRatioIdc;
|
||||
|
||||
if (header.AVC.aspectRatioIdc == 0xff)
|
||||
{
|
||||
info->sarWidth = header.AVC.sarWidth;
|
||||
info->sarHeight = header.AVC.sarHeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
info->sarWidth = 0;
|
||||
info->sarHeight = 0;
|
||||
}
|
||||
|
||||
info->horizontalSize = ((u16)header.AVC.horizontalSize & 0xff) * 16;
|
||||
info->verticalSize = ((u16)header.AVC.verticalSize & 0xff) * 16;
|
||||
info->frameCropLeftOffset = header.AVC.frameCropLeftOffset;
|
||||
info->frameCropRightOffset = header.AVC.frameCropRightOffset;
|
||||
info->frameCropTopOffset = header.AVC.frameCropTopOffset;
|
||||
info->frameCropBottomOffset = header.AVC.frameCropBottomOffset;
|
||||
|
||||
if (info->videoSignalInfoFlag)
|
||||
{
|
||||
info->videoFormat = header.AVC.x14 >> 5;
|
||||
info->videoFullRangeFlag = (header.AVC.x14 & 0x10) >> 4;
|
||||
info->colourPrimaries = header.AVC.colourPrimaries;
|
||||
info->transferCharacteristics = header.AVC.transferCharacteristics;
|
||||
info->matrixCoefficients = header.AVC.matrixCoefficients;
|
||||
}
|
||||
else
|
||||
{
|
||||
info->videoFormat = 0;
|
||||
info->videoFullRangeFlag = 0;
|
||||
info->colourPrimaries = 0;
|
||||
info->transferCharacteristics = 0;
|
||||
info->matrixCoefficients = 0;
|
||||
}
|
||||
|
||||
info->entropyCodingModeFlag = (header.AVC.x18 & 0x80) >> 7;
|
||||
info->deblockingFilterFlag = (header.AVC.x18 & 0x40) >> 6;
|
||||
info->minNumSlicePerPictureIdc = (header.AVC.x18 & 0x30) >> 4;
|
||||
info->nfwIdc = header.AVC.x18 & 0x03;
|
||||
info->maxMeanBitrate = header.AVC.maxMeanBitrate;
|
||||
|
||||
cellPamf->Notice("cellPamfReaderGetStreamInfo(): CELL_PAMF_STREAM_TYPE_AVC");
|
||||
break;
|
||||
}
|
||||
|
||||
case CELL_PAMF_STREAM_TYPE_M2V:
|
||||
{
|
||||
if (size < sizeof(CellPamfM2vInfo))
|
||||
{
|
||||
return CELL_PAMF_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
auto info = vm::ptr<CellPamfM2vInfo>::make(pInfo_addr);
|
||||
|
||||
switch (header.M2V.x0)
|
||||
{
|
||||
case 0x44: info->profileAndLevelIndication = 3; break;
|
||||
case 0x48: info->profileAndLevelIndication = 1; break;
|
||||
default: info->profileAndLevelIndication = CELL_PAMF_M2V_UNKNOWN;
|
||||
}
|
||||
|
||||
info->progressiveSequence = (header.M2V.x2 & 0x80) >> 7;
|
||||
info->videoSignalInfoFlag = (header.M2V.x2 & 0x40) >> 6;
|
||||
info->frameRateInfo = header.M2V.x2 & 0xf;
|
||||
info->aspectRatioIdc = header.M2V.aspectRatioIdc;
|
||||
|
||||
if (header.M2V.aspectRatioIdc == 0xff)
|
||||
{
|
||||
info->sarWidth = header.M2V.sarWidth;
|
||||
info->sarHeight = header.M2V.sarHeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
info->sarWidth = 0;
|
||||
info->sarHeight = 0;
|
||||
}
|
||||
|
||||
info->horizontalSize = ((u16)header.M2V.horizontalSize & 0xff) * 16;
|
||||
info->verticalSize = ((u16)header.M2V.verticalSize & 0xff) * 16;
|
||||
info->horizontalSizeValue = header.M2V.horizontalSizeValue;
|
||||
info->verticalSizeValue = header.M2V.verticalSizeValue;
|
||||
|
||||
if (info->videoSignalInfoFlag)
|
||||
{
|
||||
info->videoFormat = header.M2V.x14 >> 5;
|
||||
info->videoFullRangeFlag = (header.M2V.x14 & 0x10) >> 4;
|
||||
info->colourPrimaries = header.M2V.colourPrimaries;
|
||||
info->transferCharacteristics = header.M2V.transferCharacteristics;
|
||||
info->matrixCoefficients = header.M2V.matrixCoefficients;
|
||||
}
|
||||
else
|
||||
{
|
||||
info->videoFormat = 0;
|
||||
info->videoFullRangeFlag = 0;
|
||||
info->colourPrimaries = 0;
|
||||
info->transferCharacteristics = 0;
|
||||
info->matrixCoefficients = 0;
|
||||
}
|
||||
|
||||
cellPamf->Notice("cellPamfReaderGetStreamInfo(): CELL_PAMF_STREAM_TYPE_M2V");
|
||||
break;
|
||||
}
|
||||
|
||||
case CELL_PAMF_STREAM_TYPE_ATRAC3PLUS:
|
||||
{
|
||||
if (size < sizeof(CellPamfAtrac3plusInfo))
|
||||
{
|
||||
return CELL_PAMF_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
auto info = vm::ptr<CellPamfAtrac3plusInfo>::make(pInfo_addr);
|
||||
|
||||
info->samplingFrequency = header.audio.freq & 0xf;
|
||||
info->numberOfChannels = header.audio.channels & 0xf;
|
||||
|
||||
cellPamf->Notice("cellPamfReaderGetStreamInfo(): CELL_PAMF_STREAM_TYPE_ATRAC3PLUS");
|
||||
break;
|
||||
}
|
||||
|
||||
case CELL_PAMF_STREAM_TYPE_PAMF_LPCM:
|
||||
{
|
||||
if (size < sizeof(CellPamfLpcmInfo))
|
||||
{
|
||||
return CELL_PAMF_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
auto info = vm::ptr<CellPamfLpcmInfo>::make(pInfo_addr);
|
||||
|
||||
info->samplingFrequency = header.audio.freq & 0xf;
|
||||
info->numberOfChannels = header.audio.channels & 0xf;
|
||||
info->bitsPerSample = header.audio.bps >> 6;
|
||||
|
||||
cellPamf->Notice("cellPamfReaderGetStreamInfo(): CELL_PAMF_STREAM_TYPE_PAMF_LPCM");
|
||||
break;
|
||||
}
|
||||
|
||||
case CELL_PAMF_STREAM_TYPE_AC3:
|
||||
{
|
||||
if (size < sizeof(CellPamfAc3Info))
|
||||
{
|
||||
return CELL_PAMF_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
auto info = vm::ptr<CellPamfAc3Info>::make(pInfo_addr);
|
||||
|
||||
info->samplingFrequency = header.audio.freq & 0xf;
|
||||
info->numberOfChannels = header.audio.channels & 0xf;
|
||||
|
||||
cellPamf->Notice("cellPamfReaderGetStreamInfo(): CELL_PAMF_STREAM_TYPE_AC3");
|
||||
break;
|
||||
}
|
||||
|
||||
case CELL_PAMF_STREAM_TYPE_USER_DATA:
|
||||
{
|
||||
cellPamf->Error("cellPamfReaderGetStreamInfo(): invalid type CELL_PAMF_STREAM_TYPE_USER_DATA");
|
||||
return CELL_PAMF_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
case 6:
|
||||
{
|
||||
if (size < 4)
|
||||
{
|
||||
return CELL_PAMF_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
cellPamf->Todo("cellPamfReaderGetStreamInfo(): type 6");
|
||||
break;
|
||||
}
|
||||
|
||||
case 7:
|
||||
{
|
||||
if (size < 2)
|
||||
{
|
||||
return CELL_PAMF_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
cellPamf->Todo("cellPamfReaderGetStreamInfo(): type 7");
|
||||
break;
|
||||
}
|
||||
|
||||
case 8:
|
||||
{
|
||||
if (size < 2)
|
||||
{
|
||||
return CELL_PAMF_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
cellPamf->Todo("cellPamfReaderGetStreamInfo(): type 8");
|
||||
break;
|
||||
}
|
||||
|
||||
case 9:
|
||||
{
|
||||
cellPamf->Error("cellPamfReaderGetStreamInfo(): invalid type 9");
|
||||
return CELL_PAMF_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
// invalid type or getting type/ch failed
|
||||
cellPamf->Error("cellPamfReaderGetStreamInfo(): invalid type %d (ch=%d)", type, ch);
|
||||
return CELL_PAMF_ERROR_INVALID_PAMF;
|
||||
}
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellPamfReaderGetNumberOfEp(vm::ptr<CellPamfReader> pSelf)
|
||||
u32 cellPamfReaderGetNumberOfEp(vm::ptr<CellPamfReader> pSelf)
|
||||
{
|
||||
cellPamf->Warning("cellPamfReaderGetNumberOfEp(pSelf=0x%x, stream=%d)", pSelf.addr(), pSelf->stream);
|
||||
cellPamf->Todo("cellPamfReaderGetNumberOfEp(pSelf=0x%x, stream=%d)", pSelf.addr(), pSelf->stream);
|
||||
|
||||
if (!pSelf->pAddr) {
|
||||
return CELL_PAMF_ERROR_INVALID_PAMF;
|
||||
}
|
||||
|
||||
return pSelf->pAddr->stream_headers[pSelf->stream].ep_num;
|
||||
// cannot return error code
|
||||
return 0; //pSelf->pAddr->stream_headers[pSelf->stream].ep_num;
|
||||
}
|
||||
|
||||
int cellPamfReaderGetEpIteratorWithIndex(vm::ptr<CellPamfReader> pSelf, u32 epIndex, vm::ptr<CellPamfEpIterator> pIt)
|
||||
s32 cellPamfReaderGetEpIteratorWithIndex(vm::ptr<CellPamfReader> pSelf, u32 epIndex, vm::ptr<CellPamfEpIterator> pIt)
|
||||
{
|
||||
cellPamf->Todo("cellPamfReaderGetEpIteratorWithIndex(pSelf=0x%x, stream=%d, epIndex=%d, pIt_addr=0x%x)", pSelf.addr(), pSelf->stream, epIndex, pIt.addr());
|
||||
|
||||
if (!pSelf->pAddr) {
|
||||
return CELL_PAMF_ERROR_INVALID_PAMF;
|
||||
}
|
||||
|
||||
//TODO:
|
||||
// TODO
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellPamfReaderGetEpIteratorWithTimeStamp(vm::ptr<CellPamfReader> pSelf, vm::ptr<CellCodecTimeStamp> pTimeStamp, vm::ptr<CellPamfEpIterator> pIt)
|
||||
s32 cellPamfReaderGetEpIteratorWithTimeStamp(vm::ptr<CellPamfReader> pSelf, vm::ptr<CellCodecTimeStamp> pTimeStamp, vm::ptr<CellPamfEpIterator> pIt)
|
||||
{
|
||||
cellPamf->Todo("cellPamfReaderGetEpIteratorWithTimeStamp(pSelf=0x%x, pTimeStamp_addr=0x%x, pIt_addr=0x%x)", pSelf.addr(), pTimeStamp.addr(), pIt.addr());
|
||||
|
||||
if (!pSelf->pAddr) {
|
||||
return CELL_PAMF_ERROR_INVALID_PAMF;
|
||||
}
|
||||
|
||||
//TODO:
|
||||
|
||||
// TODO
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellPamfEpIteratorGetEp(vm::ptr<CellPamfEpIterator> pIt, vm::ptr<CellPamfEp> pEp)
|
||||
s32 cellPamfEpIteratorGetEp(vm::ptr<CellPamfEpIterator> pIt, vm::ptr<CellPamfEp> pEp)
|
||||
{
|
||||
cellPamf->Todo("cellPamfEpIteratorGetEp(pIt_addr=0x%x, pEp_addr=0x%x)", pIt.addr(), pEp.addr());
|
||||
|
||||
//TODO:
|
||||
|
||||
// always returns CELL_OK
|
||||
// TODO
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellPamfEpIteratorMove(vm::ptr<CellPamfEpIterator> pIt, s32 steps, vm::ptr<CellPamfEp> pEp)
|
||||
s32 cellPamfEpIteratorMove(vm::ptr<CellPamfEpIterator> pIt, s32 steps, vm::ptr<CellPamfEp> pEp)
|
||||
{
|
||||
cellPamf->Todo("cellPamfEpIteratorMove(pIt_addr=0x%x, steps=%d, pEp_addr=0x%x)", pIt.addr(), steps, pEp.addr());
|
||||
|
||||
//TODO:
|
||||
|
||||
return CELL_OK;
|
||||
// cannot return error code
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cellPamf_init(Module *pxThis)
|
||||
|
@ -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);
|
@ -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;
|
||||
|
||||
|
@ -1,8 +1,10 @@
|
||||
#include "stdafx.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/SysCalls/Modules.h"
|
||||
#include "Emu/FS/vfsFile.h"
|
||||
|
||||
#include "cellSail.h"
|
||||
#include "cellPamf.h"
|
||||
|
||||
Module *cellSail = nullptr;
|
||||
|
||||
@ -11,6 +13,7 @@ int cellSailMemAllocatorInitialize(vm::ptr<CellSailMemAllocator> pSelf, vm::ptr<
|
||||
cellSail->Warning("cellSailMemAllocatorInitialize(pSelf_addr=0x%x, pCallbacks_addr=0x%x)", pSelf.addr(), pCallbacks.addr());
|
||||
|
||||
pSelf->callbacks = pCallbacks;
|
||||
// TODO: Create a cellSail thread
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -71,7 +74,7 @@ int cellSailDescriptorGetMediaInfo()
|
||||
|
||||
int cellSailDescriptorSetAutoSelection(vm::ptr<CellSailDescriptor> pSelf, bool autoSelection)
|
||||
{
|
||||
cellSail->Todo("cellSailDescriptorSetAutoSelection(pSelf_addr=0x%x, autoSelection=%s)", pSelf.addr(), autoSelection ? "true" : "false");
|
||||
cellSail->Warning("cellSailDescriptorSetAutoSelection(pSelf_addr=0x%x, autoSelection=%s)", pSelf.addr(), autoSelection ? "true" : "false");
|
||||
|
||||
if (pSelf) {
|
||||
pSelf->autoSelection = autoSelection;
|
||||
@ -91,9 +94,22 @@ int cellSailDescriptorIsAutoSelection(vm::ptr<CellSailDescriptor> pSelf)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellSailDescriptorCreateDatabase()
|
||||
int cellSailDescriptorCreateDatabase(vm::ptr<CellSailDescriptor> pSelf, vm::ptr<void> pDatabase, be_t<u32> size, be_t<u64> arg)
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSail);
|
||||
cellSail->Warning("cellSailDescriptorCreateDatabase(pSelf=0x%x, pDatabase=0x%x, size=0x%x, arg=0x%x", pSelf.addr(), pDatabase.addr(), size, arg);
|
||||
|
||||
switch ((s32)pSelf->streamType) {
|
||||
case CELL_SAIL_STREAM_PAMF:
|
||||
{
|
||||
u32 addr = pSelf->internalData[1];
|
||||
auto ptr = vm::ptr<CellPamfReader>::make(addr);
|
||||
memcpy(pDatabase.get_ptr(), ptr.get_ptr(), sizeof(CellPamfReader));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
cellSail->Error("Unhandled stream type: %d", pSelf->streamType);
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
@ -616,23 +632,52 @@ int cellSailPlayerAddDescriptor(vm::ptr<CellSailPlayer> pSelf, vm::ptr<CellSailD
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellSailPlayerCreateDescriptor(vm::ptr<CellSailPlayer> pSelf, s32 streamType, vm::ptr<u32> pMediaInfo, vm::ptr<const char> pUri, vm::ptr<CellSailDescriptor> ppDesc)
|
||||
int cellSailPlayerCreateDescriptor(vm::ptr<CellSailPlayer> pSelf, s32 streamType, vm::ptr<u32> pMediaInfo, vm::ptr<const char> pUri, vm::ptr<u32> ppDesc)
|
||||
{
|
||||
cellSail->Todo("cellSailPlayerCreateDescriptor(pSelf_addr=0x%x, streamType=%d, pMediaInfo_addr=0x%x, pUri_addr=0x%x, ppDesc_addr=0x%x)", pSelf.addr(), streamType,
|
||||
cellSail->Warning("cellSailPlayerCreateDescriptor(pSelf_addr=0x%x, streamType=%d, pMediaInfo_addr=0x%x, pUri_addr=0x%x, ppDesc_addr=0x%x)", pSelf.addr(), streamType,
|
||||
pMediaInfo.addr(), pUri.addr(), ppDesc.addr());
|
||||
|
||||
// TODO: Let the game allocate memory for the descriptor, setup the descriptor and pass it back to the game
|
||||
u32 descriptorAddress = Memory.Alloc(sizeof(CellSailDescriptor), 1);
|
||||
auto descriptor = vm::ptr<CellSailDescriptor>::make(descriptorAddress);
|
||||
*ppDesc = descriptorAddress;
|
||||
descriptor->streamType = streamType;
|
||||
descriptor->registered = false;
|
||||
|
||||
//CellSailDescriptor *pDesc = new CellSailDescriptor();
|
||||
//u32 descriptorAddress = pSelf->allocator->callbacks->pAlloc(pSelf->allocator->pArg, 4, descriptorAddress);
|
||||
//cellSail->Error("Address: 0x%x", descriptorAddress);
|
||||
//vm::ptr<CellSailDescriptor> descriptor = vm::ptr<CellSailDescriptor>::make(Memory.RealToVirtualAddr(&descriptorAddress));
|
||||
//descriptor->streamType = streamType;
|
||||
//descriptor->registered = false;
|
||||
|
||||
pSelf->descriptors = 0;
|
||||
//pSelf->descriptors = 0;
|
||||
pSelf->repeatMode = 0;
|
||||
//ppDesc = descriptor;
|
||||
|
||||
switch (streamType)
|
||||
{
|
||||
case CELL_SAIL_STREAM_PAMF:
|
||||
{
|
||||
std::string uri = pUri.get_ptr();
|
||||
if (uri.substr(0, 12) == "x-cell-fs://") {
|
||||
std::string path = uri.substr(12);
|
||||
vfsFile f;
|
||||
if (f.Open(path)) {
|
||||
u64 size = f.GetSize();
|
||||
u32 buf_ = Memory.Alloc(size, 1);
|
||||
auto bufPtr = vm::ptr<const PamfHeader>::make(buf_);
|
||||
PamfHeader *buf = const_cast<PamfHeader*>(bufPtr.get_ptr());
|
||||
assert(f.Read(buf, size) == size);
|
||||
u32 sp_ = Memory.Alloc(sizeof(CellPamfReader), 1);
|
||||
auto sp = vm::ptr<CellPamfReader>::make(sp_);
|
||||
u32 r = cellPamfReaderInitialize(sp, bufPtr, size, 0);
|
||||
|
||||
descriptor->internalData[0] = buf_;
|
||||
descriptor->internalData[1] = sp_;
|
||||
}
|
||||
else
|
||||
cellSail->Warning("Couldn't open PAMF: %s", uri.c_str());
|
||||
|
||||
}
|
||||
else
|
||||
cellSail->Warning("Unhandled uri: %s", uri.c_str());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
cellSail->Error("Unhandled stream type: %d", streamType);
|
||||
}
|
||||
|
||||
//cellSail->Todo("pSelf_addr=0x%x, pDesc_addr=0x%x", pSelf.addr(), descriptor.addr());
|
||||
//cellSailPlayerAddDescriptor(pSelf, ppDesc);
|
||||
@ -766,16 +811,16 @@ int cellSailPlayerCancel()
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellSailPlayerSetPaused()
|
||||
int cellSailPlayerSetPaused(vm::ptr<CellSailPlayer> pSelf, bool paused)
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSail);
|
||||
cellSail->Todo("cellSailPlayerSetPaused(pSelf_addr=0x%x, paused=)", pSelf.addr(), paused);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int cellSailPlayerIsPaused()
|
||||
int cellSailPlayerIsPaused(vm::ptr<CellSailPlayer> pSelf)
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSail);
|
||||
return CELL_OK;
|
||||
cellSail->Warning("cellSailPlayerIsPaused(pSelf_addr=0x%x)", pSelf.addr());
|
||||
return pSelf->paused;
|
||||
}
|
||||
|
||||
int cellSailPlayerSetRepeatMode(vm::ptr<CellSailPlayer> pSelf, s32 repeatMode, vm::ptr<CellSailStartCommand> pCommand)
|
||||
|
@ -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");
|
@ -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;
|
||||
|
@ -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,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"
|
||||
|
||||
//
|
||||
|
@ -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
|
||||
|
83
rpcs3/Emu/SysCalls/Modules/cellSubdisplay.h
Normal file
83
rpcs3/Emu/SysCalls/Modules/cellSubdisplay.h
Normal file
@ -0,0 +1,83 @@
|
||||
#pragma once
|
||||
|
||||
// Return Codes
|
||||
enum
|
||||
{
|
||||
CELL_SUBDISPLAY_ERROR_OUT_OF_MEMORY = 0x80029851,
|
||||
CELL_SUBDISPLAY_ERROR_FATAL = 0x80029852,
|
||||
CELL_SUBDISPLAY_ERROR_NOT_FOUND = 0x80029853,
|
||||
CELL_SUBDISPLAY_ERROR_INVALID_VALUE = 0x80029854,
|
||||
CELL_SUBDISPLAY_ERROR_NOT_INITIALIZED = 0x80029855,
|
||||
CELL_SUBDISPLAY_ERROR_SET_SAMPLE = 0x80029860,
|
||||
CELL_SUBDISPLAY_ERROR_AUDIOOUT_IS_BUSY = 0x80029861,
|
||||
CELL_SUBDISPLAY_ERROR_ZERO_REGISTERED = 0x80029813,
|
||||
};
|
||||
|
||||
// Different constants
|
||||
enum
|
||||
{
|
||||
CELL_SUBDISPLAY_STATUS_JOIN = 1,
|
||||
CELL_SUBDISPLAY_STATUS_LEAVE = 2,
|
||||
CELL_SUBDISPLAY_STATUS_FATALERROR = 3,
|
||||
CELL_SUBDISPLAY_VERSION_0001 = 1,
|
||||
CELL_SUBDISPLAY_VERSION_0002 = 2,
|
||||
CELL_SUBDISPLAY_MODE_REMOTEPLAY = 1,
|
||||
CELL_SUBDISPLAY_VIDEO_FORMAT_A8R8G8B8 = 1,
|
||||
CELL_SUBDISPLAY_VIDEO_FORMAT_R8G8B8A8 = 2,
|
||||
CELL_SUBDISPLAY_VIDEO_ASPECT_RATIO_16_9 = 0,
|
||||
CELL_SUBDISPLAY_VIDEO_ASPECT_RATIO_4_3 = 1,
|
||||
CELL_SUBDISPLAY_VIDEO_MODE_SETDATA = 0,
|
||||
CELL_SUBDISPLAY_VIDEO_MODE_CAPTURE = 1,
|
||||
CELL_SUBDISPLAY_AUDIO_MODE_SETDATA = 0,
|
||||
CELL_SUBDISPLAY_AUDIO_MODE_CAPTURE = 1,
|
||||
CELL_SUBDISPLAY_0001_MEMORY_CONTAINER_SIZE = 8 * 1024 * 1024,
|
||||
CELL_SUBDISPLAY_0002_MEMORY_CONTAINER_SIZE = 10 * 1024 * 1024,
|
||||
CELL_SUBDISPLAY_NICKNAME_LEN = 256,
|
||||
CELL_SUBDISPLAY_PSPID_LEN = 16,
|
||||
};
|
||||
|
||||
struct CellSubDisplayVideoParam
|
||||
{
|
||||
be_t<s32> format;
|
||||
be_t<s32> width;
|
||||
be_t<s32> height;
|
||||
be_t<s32> pitch;
|
||||
be_t<s32> aspectRatio;
|
||||
be_t<s32> videoMode;
|
||||
};
|
||||
|
||||
struct CellSubDisplayAudioParam
|
||||
{
|
||||
be_t<s32> ch;
|
||||
be_t<s32> audioMode;
|
||||
};
|
||||
|
||||
struct CellSubDisplayParam
|
||||
{
|
||||
be_t<s32> version;
|
||||
be_t<s32> mode;
|
||||
be_t<s32> nGroup;
|
||||
be_t<s32> nPeer;
|
||||
vm::ptr<CellSubDisplayVideoParam> videoParam;
|
||||
vm::ptr<CellSubDisplayAudioParam> audioParam;
|
||||
};
|
||||
|
||||
struct CellSubDisplayPSPId
|
||||
{
|
||||
char data[CELL_SUBDISPLAY_PSPID_LEN];
|
||||
};
|
||||
|
||||
struct CellSubDisplayNickname
|
||||
{
|
||||
char data[CELL_SUBDISPLAY_NICKNAME_LEN];
|
||||
};
|
||||
|
||||
struct CellSubDisplayPeerInfo
|
||||
{
|
||||
be_t<u64> sessionId;
|
||||
be_t<u32> portNo;
|
||||
CellSubDisplayPSPId pspId;
|
||||
CellSubDisplayNickname pspNickname;
|
||||
};
|
||||
|
||||
typedef void(*CellSubDisplayHandler)(s32 cbMsg, u64 cbParam, u32 *userdata);
|
@ -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"
|
||||
|
@ -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
Loading…
x
Reference in New Issue
Block a user