Performance improvements and CR fixes

This commit is contained in:
Farseer
2018-01-27 23:05:35 +02:00
committed by Zangetsu38
parent 15330a86ee
commit 1b63bf130c
14 changed files with 195 additions and 116 deletions
+6 -5
View File
@@ -176,14 +176,16 @@ void mfc_thread::cpu_task()
data = to_write; data = to_write;
vm::reservation_update(cmd.eal, 128); vm::reservation_update(cmd.eal, 128);
vm::notify(cmd.eal, 128);
_xend(); _xend();
vm::notify(cmd.eal, 128);
} }
else else
{ {
vm::writer_lock lock(0); {
data = to_write; vm::writer_lock lock(0);
vm::reservation_update(cmd.eal, 128); data = to_write;
vm::reservation_update(cmd.eal, 128);
}
vm::notify(cmd.eal, 128); vm::notify(cmd.eal, 128);
} }
} }
@@ -356,7 +358,6 @@ void mfc_thread::cpu_task()
} }
else else
{ {
vm::reader_lock lock;
vm::notify_all(); vm::notify_all();
} }
} }
+22 -14
View File
@@ -967,14 +967,18 @@ extern bool ppu_stwcx(ppu_thread& ppu, u32 addr, u32 reg_value)
return result; return result;
} }
vm::writer_lock lock(0); bool result;
const bool result = ppu.rtime == vm::reservation_acquire(addr, sizeof(u32)) && data.compare_and_swap_test(static_cast<u32>(ppu.rdata), reg_value);
if (result)
{ {
vm::reservation_update(addr, sizeof(u32)); vm::writer_lock lock(0);
vm::notify(addr, sizeof(u32));
result = ppu.rtime == vm::reservation_acquire(addr, sizeof(u32)) && data.compare_and_swap_test(static_cast<u32>(ppu.rdata), reg_value);
if (result)
{
vm::reservation_update(addr, sizeof(u32));
lock.unlock();
vm::notify(addr, sizeof(u32));
}
} }
ppu.raddr = 0; ppu.raddr = 0;
@@ -1011,14 +1015,18 @@ extern bool ppu_stdcx(ppu_thread& ppu, u32 addr, u64 reg_value)
return result; return result;
} }
vm::writer_lock lock(0); bool result;
const bool result = ppu.rtime == vm::reservation_acquire(addr, sizeof(u64)) && data.compare_and_swap_test(ppu.rdata, reg_value);
if (result)
{ {
vm::reservation_update(addr, sizeof(u64)); vm::writer_lock lock(0);
vm::notify(addr, sizeof(u64));
result = ppu.rtime == vm::reservation_acquire(addr, sizeof(u64)) && data.compare_and_swap_test(ppu.rdata, reg_value);
if (result)
{
vm::reservation_update(addr, sizeof(u64));
lock.unlock();
vm::notify(addr, sizeof(u64));
}
} }
ppu.raddr = 0; ppu.raddr = 0;
+7 -3
View File
@@ -31,7 +31,7 @@ spu_recompiler::spu_recompiler()
} }
} }
bool spu_recompiler::compile(std::shared_ptr<spu_function_contents_t> f) bool spu_recompiler::compile(spu_function_contents_t* f)
{ {
std::lock_guard<std::mutex> lock(m_mutex); std::lock_guard<std::mutex> lock(m_mutex);
@@ -451,10 +451,12 @@ void spu_recompiler::LNOP(spu_opcode_t op)
void invalidate_jit(SPUThread* _spu) void invalidate_jit(SPUThread* _spu)
{ {
for (auto& func : _spu->compiled_functions) for (u32 i = _spu->first_clean_func_index; i < _spu->last_clean_func_index; i++)
{ {
func->dirty_bit = true; _spu->compiled_functions[i].dirty_bit = true;
} }
_spu->first_clean_func_index = -1;
_spu->last_clean_func_index = 0;
} }
void spu_recompiler::SYNC(spu_opcode_t op) void spu_recompiler::SYNC(spu_opcode_t op)
@@ -468,6 +470,8 @@ void spu_recompiler::DSYNC(spu_opcode_t op)
{ {
// This instruction forces all earlier load, store, and channel instructions to complete before proceeding. // This instruction forces all earlier load, store, and channel instructions to complete before proceeding.
c->mfence(); c->mfence();
asmjit::CCFuncCall* call = c->call(asmjit::imm_ptr(asmjit::Internal::ptr_cast<void*, void(SPUThread*)>(invalidate_jit)), asmjit::FuncSignature1<u32, SPUThread*>(asmjit::CallConv::kIdHost));
call->setArg(0, *cpu);
} }
void spu_recompiler::MFSPR(spu_opcode_t op) void spu_recompiler::MFSPR(spu_opcode_t op)
+1 -1
View File
@@ -15,7 +15,7 @@ class spu_recompiler : public spu_recompiler_base
public: public:
spu_recompiler(); spu_recompiler();
virtual bool compile(std::shared_ptr<spu_function_contents_t> f) override; virtual bool compile(spu_function_contents_t* f) override;
private: private:
// emitter: // emitter:
+37 -6
View File
@@ -5,16 +5,16 @@
const spu_decoder<spu_itype> s_spu_itype; const spu_decoder<spu_itype> s_spu_itype;
std::shared_ptr<spu_function_contents_t> SPUDatabase::find(const be_t<u32>* data, u64 key, u32 max_size, void* ignore) spu_function_contents_t* SPUDatabase::find(const be_t<u32>* data, u64 key, u32 max_size, void* ignore)
{ {
for (auto found = m_db.equal_range(key); found.first != found.second; found.first++) for (auto found = m_db.equal_range(key); found.first != found.second; found.first++)
{ {
const auto & func = found.first->second; const auto & func = found.first->second;
// TODO remove code after a while if it hasn't been touched, else there's a big memory bloat here // TODO remove code after a while if it hasn't been touched, else there's a big memory bloat here and switch memcmp with compare_func
// Compare binary data explicitly (TODO: optimize) // Compare binary data explicitly (TODO: optimize)
if (func.get() != ignore && LIKELY(func->size <= max_size) && memcmp(func->data.data(), data, func->size) == 0) if (func != ignore && LIKELY(func->size <= max_size) && std::memcmp(func->data.data(), data, func->size) == 0)
{ {
return func; return func;
} }
@@ -35,7 +35,15 @@ SPUDatabase::~SPUDatabase()
// TODO: serialize database // TODO: serialize database
} }
std::shared_ptr<spu_function_contents_t> SPUDatabase::analyse(const be_t<u32>* ls, u32 entry, void* ignore /*=nullptr*/) bool IsDeterministicBranch(spu_itype::type type)
{
return type == spu_itype::BR || type == spu_itype::BRSL
|| type == spu_itype::BRA || type == spu_itype::BRASL
|| type == spu_itype::BI || type == spu_itype::BISL
|| type == spu_itype::IRET;
}
spu_function_contents_t* SPUDatabase::analyse(const be_t<u32>* ls, u32 entry, void* ignore /*=nullptr*/)
{ {
const u32 max_limit = 0x40000; const u32 max_limit = 0x40000;
// Check arguments (bounds and alignment) // Check arguments (bounds and alignment)
@@ -77,6 +85,8 @@ std::shared_ptr<spu_function_contents_t> SPUDatabase::analyse(const be_t<u32>* l
// Initialize block entries with the function entry point // Initialize block entries with the function entry point
std::set<u32> blocks{ entry }; std::set<u32> blocks{ entry };
std::vector<u32> blocks_size;
// Entries of adjacent functions; jump table entries // Entries of adjacent functions; jump table entries
std::set<u32> adjacent, jt; std::set<u32> adjacent, jt;
@@ -321,8 +331,27 @@ std::shared_ptr<spu_function_contents_t> SPUDatabase::analyse(const be_t<u32>* l
return nullptr; return nullptr;
} }
blocks_size.reserve(blocks.size());
for (u32 block : blocks)
{
u32 size = 0;
for (u32 i = block / 4; i < 0x10000; i++)
{
if (ls[i] == 0 || IsDeterministicBranch(s_spu_itype.decode(ls[i])))
{
size = (i * 4) - block + 4;
break;
}
}
if (size == 0)
{
verify("No way out of a block"), size != 0;
}
blocks_size.push_back(size);
}
// Prepare new function (set addr and size) // Prepare new function (set addr and size)
auto func = std::make_shared<spu_function_contents_t>(entry, limit - entry); auto func = new spu_function_contents_t(entry, limit - entry);
// Copy function contents // Copy function contents
func->data = { ls + entry / 4, ls + limit / 4 }; func->data = { ls + entry / 4, ls + limit / 4 };
@@ -354,6 +383,8 @@ std::shared_ptr<spu_function_contents_t> SPUDatabase::analyse(const be_t<u32>* l
} }
} }
func->blocks_size = std::move(blocks_size);
// Set whether the function can reset stack // Set whether the function can reset stack
func->does_reset_stack = ila_sp_pos < limit; func->does_reset_stack = ila_sp_pos < limit;
@@ -366,7 +397,7 @@ std::shared_ptr<spu_function_contents_t> SPUDatabase::analyse(const be_t<u32>* l
m_db.emplace(key, func); m_db.emplace(key, func);
} }
LOG_NOTICE(SPU, "Function detected [0x%05x-0x%05x] (size=0x%x)", func->addr, func->addr + func->size, func->size); LOG_FATAL(SPU, "Function detected [0x%05x-0x%05x] (size=0x%x)", func->addr, func->addr + func->size, func->size);
return func; return func;
} }
+8 -5
View File
@@ -265,6 +265,9 @@ struct spu_function_contents_t
// Basic blocks (start addresses) // Basic blocks (start addresses)
std::set<u32> blocks; std::set<u32> blocks;
// Basic blocks size
std::vector<u32> blocks_size;
// Functions possibly called by this function (may not be available) // Functions possibly called by this function (may not be available)
std::set<u32> adjacent; std::set<u32> adjacent;
@@ -288,7 +291,7 @@ struct spu_function_contents_t
union spu_function_t union spu_function_t
{ {
// The function itself and its data // The function itself and its data
std::shared_ptr<spu_function_contents_t> contents; spu_function_contents_t * contents;
// Whether pages the function is in were written to since its last execution // Whether pages the function is in were written to since its last execution
bool dirty_bit : 1; bool dirty_bit : 1;
@@ -299,7 +302,7 @@ union spu_function_t
} }
spu_function_t() : contents(nullptr) {}; spu_function_t() : contents(nullptr) {};
~spu_function_t() {dirty_bit = false; contents.reset();}; ~spu_function_t() {};
}; };
// SPU Function Database (must be global or PS3 process-local) // SPU Function Database (must be global or PS3 process-local)
@@ -308,15 +311,15 @@ class SPUDatabase final : spu_itype
shared_mutex m_mutex; shared_mutex m_mutex;
// All registered functions (uses addr and first instruction as a key) // All registered functions (uses addr and first instruction as a key)
std::unordered_multimap<u64, std::shared_ptr<spu_function_contents_t>> m_db; std::unordered_multimap<u64, spu_function_contents_t*> m_db;
// For internal use // For internal use
std::shared_ptr<spu_function_contents_t> find(const be_t<u32>* data, u64 key, u32 max_size, void* ignore = nullptr); spu_function_contents_t* find(const be_t<u32>* data, u64 key, u32 max_size, void* ignore = nullptr);
public: public:
SPUDatabase(); SPUDatabase();
~SPUDatabase(); ~SPUDatabase();
// Try to retrieve SPU function information // Try to retrieve SPU function information
std::shared_ptr<spu_function_contents_t> analyse(const be_t<u32>* ls, u32 entry, void * ignore=nullptr); spu_function_contents_t* analyse(const be_t<u32>* ls, u32 entry, void * ignore=nullptr);
}; };
+1 -1
View File
@@ -102,7 +102,7 @@ void spu_interpreter::RDCH(SPUThread& spu, spu_opcode_t op)
else else
{ {
memset(&spu.gpr[op.rt], 0, 3*sizeof(u32)); memset(&spu.gpr[op.rt], 0, 3*sizeof(u32));
spu.gpr[op.rt]._u32[3] = result; v128::from32r(result); spu.gpr[op.rt]._u32[3] = result;
} }
} }
+21 -14
View File
@@ -24,46 +24,53 @@ void spu_recompiler_base::enter(SPUThread& spu)
const auto _ls = vm::_ptr<u32>(spu.offset); const auto _ls = vm::_ptr<u32>(spu.offset);
// Search if cached data matches // Search if cached data matches
auto & func = spu.compiled_cache[spu.pc / 4]; auto func_ptr = spu.compiled_cache[spu.pc / 4];
// func.contents is there only as a temporary test, to see if SPU codfe not getting invalidated is the reason for the crashes // func.contents is there only as a temporary test, to see if SPU code not getting invalidated is the reason for the crashes
if (func.contents || func.dirty_bit) if (func_ptr && func_ptr->dirty_bit)
{ {
auto & func = *func_ptr;
func.dirty_bit = false; func.dirty_bit = false;
u32 index = (reinterpret_cast<size_t>(func_ptr) - reinterpret_cast<size_t>(&spu.compiled_functions[0])) / sizeof(func);
// This memcmp acts as a fast path instead of finding it again in analyse. spu.first_clean_func_index = std::min<u32>(index, spu.first_clean_func_index);
if (memcmp(func.contents->data.data(), _ls + (spu.pc / 4), func.contents->size) != 0) spu.last_clean_func_index = std::max<u32>(index + 1, spu.last_clean_func_index);
if (!spu.same_function(func.contents, _ls + (spu.pc / 4)))
{ {
func.contents = spu.spu_db->analyse(_ls, spu.pc, func.contents.get()); func.contents = spu.spu_db->analyse(_ls, spu.pc, func.contents);
} }
} }
else if (!func) else if (!func_ptr)
{ {
auto & func = spu.compiled_functions[++spu.next_compiled_func_index];
func.contents = spu.spu_db->analyse(_ls, spu.pc); func.contents = spu.spu_db->analyse(_ls, spu.pc);
spu.compiled_functions.push_back(&func); func_ptr = &func;
spu.compiled_cache[spu.pc / 4] = func_ptr;
spu.last_clean_func_index = spu.next_compiled_func_index + 1;
spu.first_clean_func_index = std::min<u32>(spu.first_clean_func_index, spu.next_compiled_func_index);
} }
// Reset callstack if necessary // Reset callstack if necessary
if ((func.contents->does_reset_stack && spu.recursion_level) || spu.recursion_level >= 128) if ((func_ptr->contents->does_reset_stack && spu.recursion_level) || spu.recursion_level >= 128)
{ {
spu.state += cpu_flag::ret; spu.state += cpu_flag::ret;
return; return;
} }
// Compile if needed // Compile if needed
if (!func.contents->compiled) if (!func_ptr->contents->compiled)
{ {
if (!spu.spu_rec) if (!spu.spu_rec)
{ {
spu.spu_rec = fxm::get_always<spu_recompiler>(); spu.spu_rec = fxm::get_always<spu_recompiler>();
} }
spu.spu_rec->compile(func.contents); spu.spu_rec->compile(func_ptr->contents);
if (!func.contents->compiled) fmt::throw_exception("Compilation failed" HERE); if (!func_ptr->contents->compiled) fmt::throw_exception("Compilation failed" HERE);
} }
const u32 res = func.contents->compiled(&spu, _ls); const u32 res = func_ptr->contents->compiled(&spu, _ls);
if (spu.pending_exception) if (spu.pending_exception)
{ {
+2 -2
View File
@@ -10,7 +10,7 @@ class spu_recompiler_base
protected: protected:
std::mutex m_mutex; // must be locked in compile() std::mutex m_mutex; // must be locked in compile()
std::shared_ptr<const spu_function_contents_t> m_func; // current function const spu_function_contents_t* m_func; // current function
u32 m_pos; // current position u32 m_pos; // current position
@@ -18,7 +18,7 @@ public:
virtual ~spu_recompiler_base(); virtual ~spu_recompiler_base();
// Compile specified function // Compile specified function
virtual bool compile(std::shared_ptr<spu_function_contents_t>) = 0; virtual bool compile(spu_function_contents_t*) = 0;
// Run // Run
static void enter(class SPUThread&); static void enter(class SPUThread&);
+50 -24
View File
@@ -557,14 +557,15 @@ void SPUThread::do_dma_transfer(const spu_mfc_cmd& args, bool from_mfc)
if (spu) if (spu)
{ {
for (auto& func : spu->compiled_functions) for (u32 i = 0; i < spu->next_compiled_func_index; i++)
{ {
auto faddr = func->contents->addr; auto& func = spu->compiled_functions[i];
auto fsize = func->contents->size; auto faddr = func.contents->addr;
auto fsize = func.contents->size;
if (faddr >= eal && faddr + fsize < eal + args.size) if (faddr >= eal && faddr + fsize < eal + args.size)
{ {
func->dirty_bit = true; func.dirty_bit = true;
} }
} }
} }
@@ -639,6 +640,7 @@ void SPUThread::process_mfc_cmd()
} }
waiter->remove(); waiter->remove();
waiter = nullptr;
} }
else if (s_use_rtm && utils::transaction_enter()) else if (s_use_rtm && utils::transaction_enter())
{ {
@@ -820,18 +822,22 @@ void SPUThread::process_mfc_cmd()
// Try to process small transfers immediately // Try to process small transfers immediately
if (ch_mfc_cmd.size <= max_imm_dma_size && mfc_queue.size() == 0) if (ch_mfc_cmd.size <= max_imm_dma_size && mfc_queue.size() == 0)
{ {
vm::reader_lock lock(vm::try_to_lock); /* TODO catch the exception (Currently they are ignored and slow things down by grabbing a lock)
if (!lock)
{ {
break; vm::reader_lock lock(vm::try_to_lock);
}
if (!vm::check_addr(ch_mfc_cmd.eal, ch_mfc_cmd.size, vm::page_readable | (ch_mfc_cmd.cmd & MFC_PUT_CMD ? vm::page_writable : 0))) if (!lock)
{ {
// TODO break;
break; }
if (!vm::check_addr(ch_mfc_cmd.eal, ch_mfc_cmd.size, vm::page_readable | (ch_mfc_cmd.cmd & MFC_PUT_CMD ? vm::page_writable : 0)))
{
// TODO
break;
}
} }
*/
do_dma_transfer(ch_mfc_cmd, false); do_dma_transfer(ch_mfc_cmd, false);
return; return;
@@ -851,13 +857,6 @@ void SPUThread::process_mfc_cmd()
{ {
if (ch_mfc_cmd.size <= max_imm_dma_size && mfc_queue.size() == 0) if (ch_mfc_cmd.size <= max_imm_dma_size && mfc_queue.size() == 0)
{ {
vm::reader_lock lock(vm::try_to_lock);
if (!lock)
{
break;
}
struct list_element struct list_element
{ {
be_t<u16> sb; be_t<u16> sb;
@@ -888,11 +887,20 @@ void SPUThread::process_mfc_cmd()
break; break;
} }
if (!vm::check_addr(addr, size, vm::page_readable | (ch_mfc_cmd.cmd & MFC_PUT_CMD ? vm::page_writable : 0))) /* TODO Catch and handle exceptions here
{ {
// TODO vm::reader_lock lock(vm::try_to_lock);
break;
} if (!lock)
{
break;
}
if (!vm::check_addr(addr, size, vm::page_readable | (ch_mfc_cmd.cmd & MFC_PUT_CMD ? vm::page_writable : 0)))
{
// TODO
break;
}
}*/
spu_mfc_cmd transfer; spu_mfc_cmd transfer;
transfer.eal = addr; transfer.eal = addr;
@@ -1184,6 +1192,7 @@ bool SPUThread::get_ch_value(u32 ch, u32& out)
if (test(state & cpu_flag::stop)) if (test(state & cpu_flag::stop))
{ {
waiter->remove(); waiter->remove();
waiter = nullptr;
return false; return false;
} }
@@ -1193,6 +1202,7 @@ bool SPUThread::get_ch_value(u32 ch, u32& out)
if (waiter != nullptr) if (waiter != nullptr)
{ {
waiter->remove(); waiter->remove();
waiter = nullptr;
} }
out = res; out = res;
@@ -1826,6 +1836,22 @@ bool SPUThread::stop_and_signal(u32 code)
} }
} }
bool SPUThread::same_function(const spu_function_contents_t * func, const void * addr)
{
auto size = func->blocks_size.cbegin();
auto dst = reinterpret_cast<const u8 *>(addr);
auto src = vm::ps3::_ptr<u8>(offset);
for (auto block : func->blocks)
{
u32 offset = block - func->addr;
if (memcmp(src + offset, dst + offset, *size) != 0) return false;
size++;
}
return true;
}
void SPUThread::halt() void SPUThread::halt()
{ {
LOG_TRACE(SPU, "halt()"); LOG_TRACE(SPU, "halt()");
+9 -4
View File
@@ -215,8 +215,7 @@ public:
{ {
const auto old = data.fetch_op([](sync_var_t& data) const auto old = data.fetch_op([](sync_var_t& data)
{ {
sync_var_t t; sync_var_t t{};
*reinterpret_cast<u64*>(&t) = 0;
t.wait = !data.count; t.wait = !data.count;
data = t; data = t;
}); });
@@ -582,8 +581,13 @@ public:
// No need for shared_ptr in the following two, as whenever something is removed or added to one, // No need for shared_ptr in the following two, as whenever something is removed or added to one,
// the same goes for the other. // the same goes for the other.
std::array<spu_function_t, 65536> compiled_cache{}; std::array<spu_function_t*, 65536> compiled_cache{};
std::vector<spu_function_t*> compiled_functions{}; std::array<spu_function_t, 65536> compiled_functions{};
u32 next_compiled_func_index = -1;
u32 first_clean_func_index = 0;
u32 last_clean_func_index = 0;
std::shared_ptr<class SPUDatabase> spu_db; std::shared_ptr<class SPUDatabase> spu_db;
std::shared_ptr<class spu_recompiler_base> spu_rec; std::shared_ptr<class spu_recompiler_base> spu_rec;
u32 recursion_level = 0; u32 recursion_level = 0;
@@ -599,6 +603,7 @@ public:
bool get_ch_value(u32 ch, u32& out); bool get_ch_value(u32 ch, u32& out);
bool set_ch_value(u32 ch, u32 value); bool set_ch_value(u32 ch, u32 value);
bool stop_and_signal(u32 code); bool stop_and_signal(u32 code);
bool same_function(const spu_function_contents_t * func, const void * addr);
void halt(); void halt();
void fast_call(u32 ls_addr); void fast_call(u32 ls_addr);
+6
View File
@@ -777,6 +777,12 @@ error_code sys_spu_thread_write_ls(u32 id, u32 lsa, u64 value, u32 type)
default: return CELL_EINVAL; default: return CELL_EINVAL;
} }
auto func = thread->compiled_cache[lsa / 4];
if (func)
{
func->dirty_bit = true;
}
return CELL_OK; return CELL_OK;
} }
+5 -10
View File
@@ -131,25 +131,20 @@ u64 get_timebased_time()
// Returns some relative time in microseconds, don't change this fact // Returns some relative time in microseconds, don't change this fact
u64 get_system_time() u64 get_system_time()
{ {
#ifdef _WIN32
// Pull the time directly from Windows shared page (Constant location on all Windows machines)
return *reinterpret_cast<u64*>(0x7ffe0014) / 10;
#else
while (true) while (true)
{ {
#ifdef _WIN32
LARGE_INTEGER count;
verify(HERE), QueryPerformanceCounter(&count);
const u64 time = count.QuadPart;
const u64 freq = s_time_aux_info.perf_freq;
const u64 result = time / freq * 1000000u + (time % freq) * 1000000u / freq;
#else
struct timespec ts; struct timespec ts;
verify(HERE), ::clock_gettime(CLOCK_MONOTONIC, &ts) == 0; verify(HERE), ::clock_gettime(CLOCK_MONOTONIC, &ts) == 0;
const u64 result = static_cast<u64>(ts.tv_sec) * 1000000u + static_cast<u64>(ts.tv_nsec) / 1000u; const u64 result = static_cast<u64>(ts.tv_sec) * 1000000u + static_cast<u64>(ts.tv_nsec) / 1000u;
#endif
if (result) return result; if (result) return result;
} }
#endif
} }
// Functions // Functions
+20 -27
View File
@@ -35,7 +35,7 @@ void fmt_class_string<frame_limit_type>::format(std::string& out, u64 arg)
namespace rsx namespace rsx
{ {
rsx_state method_registers; rsx_state method_registers;
std::array<rsx_method_t, 0x10000 / 4> methods{}; std::array<rsx_method_t, 0x10000 / 4> methods{};
void invalid_method(thread* rsx, u32 _reg, u32 arg) void invalid_method(thread* rsx, u32 _reg, u32 arg)
@@ -64,10 +64,10 @@ namespace rsx
{ {
rsx->sync_point_request = true; rsx->sync_point_request = true;
const u32 addr = get_address(method_registers.semaphore_offset_406e(), method_registers.semaphore_context_dma_406e()); const u32 addr = get_address(method_registers.semaphore_offset_406e(), method_registers.semaphore_context_dma_406e());
if (vm::read32(addr) == arg) return; if (vm::ps3::read32(addr) == arg) return;
u64 start = get_system_time(); u64 start = get_system_time();
while (vm::read32(addr) != arg) while (vm::ps3::read32(addr) != arg)
{ {
// todo: LLE: why does this one keep hanging? is it vsh system semaphore? whats actually pushing this to the command buffer?! // todo: LLE: why does this one keep hanging? is it vsh system semaphore? whats actually pushing this to the command buffer?!
if (addr == 0x40000030) if (addr == 0x40000030)
@@ -116,12 +116,11 @@ namespace rsx
if (addr >> 28 == 0x4) if (addr >> 28 == 0x4)
{ {
// TODO: check no reservation area instead // TODO: check no reservation area instead
vm::write32(addr, arg); vm::ps3::write32(addr, arg);
return; return;
} }
vm::reader_lock lock; vm::ps3::write32(addr, arg);
vm::write32(addr, arg);
vm::notify(addr, 4); vm::notify(addr, 4);
} }
} }
@@ -162,7 +161,7 @@ namespace rsx
{ {
// //
} }
auto& sema = vm::_ref<RsxReports>(rsx->label_addr); auto& sema = vm::ps3::_ref<RsxReports>(rsx->label_addr);
sema.semaphore[index].val = arg; sema.semaphore[index].val = arg;
sema.semaphore[index].pad = 0; sema.semaphore[index].pad = 0;
sema.semaphore[index].timestamp = rsx->timestamp(); sema.semaphore[index].timestamp = rsx->timestamp();
@@ -177,7 +176,7 @@ namespace rsx
} }
u32 val = (arg & 0xff00ff00) | ((arg & 0xff) << 16) | ((arg >> 16) & 0xff); u32 val = (arg & 0xff00ff00) | ((arg & 0xff) << 16) | ((arg >> 16) & 0xff);
auto& sema = vm::_ref<RsxReports>(rsx->label_addr); auto& sema = vm::ps3::_ref<RsxReports>(rsx->label_addr);
sema.semaphore[index].val = val; sema.semaphore[index].val = val;
sema.semaphore[index].pad = 0; sema.semaphore[index].pad = 0;
sema.semaphore[index].timestamp = rsx->timestamp(); sema.semaphore[index].timestamp = rsx->timestamp();
@@ -352,7 +351,7 @@ namespace rsx
{ {
rsx::method_registers.current_draw_clause.first_count_commands.resize(0); rsx::method_registers.current_draw_clause.first_count_commands.resize(0);
rsx::method_registers.current_draw_clause.command = draw_command::none; rsx::method_registers.current_draw_clause.command = draw_command::none;
rsx::method_registers.current_draw_clause.primitive = to_primitive_type(arg); rsx::method_registers.current_draw_clause.primitive = rsx::method_registers.primitive_mode();
rsxthr->begin(); rsxthr->begin();
return; return;
} }
@@ -416,7 +415,7 @@ namespace rsx
return; return;
} }
vm::ptr<CellGcmReportData> result = address_ptr; vm::ps3::ptr<CellGcmReportData> result = address_ptr;
switch (type) switch (type)
{ {
@@ -484,7 +483,7 @@ namespace rsx
return; return;
} }
vm::ptr<CellGcmReportData> result = address_ptr; vm::ps3::ptr<CellGcmReportData> result = address_ptr;
rsx->conditional_render_test_failed = (result->value == 0); rsx->conditional_render_test_failed = (result->value == 0);
} }
@@ -553,7 +552,7 @@ namespace rsx
const u32 pixel_offset = (method_registers.blit_engine_output_pitch_nv3062() * y) + (x << 2); const u32 pixel_offset = (method_registers.blit_engine_output_pitch_nv3062() * y) + (x << 2);
u32 address = get_address(method_registers.blit_engine_output_offset_nv3062() + pixel_offset + index * 4, method_registers.blit_engine_output_location_nv3062()); u32 address = get_address(method_registers.blit_engine_output_offset_nv3062() + pixel_offset + index * 4, method_registers.blit_engine_output_location_nv3062());
vm::write32(address, arg); vm::ps3::write32(address, arg);
} }
}; };
} }
@@ -662,7 +661,7 @@ namespace rsx
const tiled_region dst_region = rsx->get_tiled_address(dst_offset + out_offset, dst_dma & 0xf); const tiled_region dst_region = rsx->get_tiled_address(dst_offset + out_offset, dst_dma & 0xf);
u8* pixels_src = src_region.tile ? src_region.ptr + src_region.base : src_region.ptr; u8* pixels_src = src_region.tile ? src_region.ptr + src_region.base : src_region.ptr;
u8* pixels_dst = vm::_ptr<u8>(get_address(dst_offset + out_offset, dst_dma)); u8* pixels_dst = vm::ps3::_ptr<u8>(get_address(dst_offset + out_offset, dst_dma));
if (out_pitch == 0) if (out_pitch == 0)
{ {
@@ -694,8 +693,7 @@ namespace rsx
if (convert_w == 0 || convert_h == 0) if (convert_w == 0 || convert_h == 0)
{ {
LOG_ERROR(RSX, "NV3089_IMAGE_IN: Invalid dimensions or scaling factor. Request ignored (ds_dx=%d, dt_dy=%d)", LOG_ERROR(RSX, "NV3089_IMAGE_IN: Invalid dimensions or scaling factor. Request ignored");
method_registers.blit_engine_ds_dx(), method_registers.blit_engine_dt_dy());
return; return;
} }
@@ -790,7 +788,7 @@ namespace rsx
if (method_registers.blit_engine_context_surface() != blit_engine::context_surface::swizzle2d) if (method_registers.blit_engine_context_surface() != blit_engine::context_surface::swizzle2d)
{ {
if (need_convert || need_clip) if (need_convert || need_clip)
{ {
if (need_clip) if (need_clip)
{ {
if (need_convert) if (need_convert)
@@ -856,7 +854,7 @@ namespace rsx
pixels_src = temp2.get(); pixels_src = temp2.get();
} }
// It looks like rsx may ignore the requested swizzle size and just always // It looks like rsx may ignore the requested swizzle size and just always
// round up to nearest power of 2 // round up to nearest power of 2
/*u8 sw_width_log2 = method_registers.nv309e_sw_width_log2(); /*u8 sw_width_log2 = method_registers.nv309e_sw_width_log2();
u8 sw_height_log2 = method_registers.nv309e_sw_height_log2(); u8 sw_height_log2 = method_registers.nv309e_sw_height_log2();
@@ -934,7 +932,7 @@ namespace rsx
LOG_ERROR(RSX, "NV0039_OFFSET_IN: Unsupported format: inFormat=%d, outFormat=%d", in_format, out_format); LOG_ERROR(RSX, "NV0039_OFFSET_IN: Unsupported format: inFormat=%d, outFormat=%d", in_format, out_format);
} }
LOG_TRACE(RSX, "NV0039_OFFSET_IN: pitch(in=0x%x, out=0x%x), line(len=0x%x, cnt=0x%x), fmt(in=0x%x, out=0x%x), notify=0x%x", LOG_NOTICE(RSX, "NV0039_OFFSET_IN: pitch(in=0x%x, out=0x%x), line(len=0x%x, cnt=0x%x), fmt(in=0x%x, out=0x%x), notify=0x%x",
in_pitch, out_pitch, line_length, line_count, in_format, out_format, notify); in_pitch, out_pitch, line_length, line_count, in_format, out_format, notify);
if (!in_pitch) if (!in_pitch)
@@ -1028,7 +1026,7 @@ namespace rsx
} }
} }
} }
rsx->int_flip_index++; rsx->int_flip_index++;
rsx->current_display_buffer = arg; rsx->current_display_buffer = arg;
rsx->flip(arg); rsx->flip(arg);
@@ -1190,11 +1188,6 @@ namespace rsx
registers[reg] = value; registers[reg] = value;
} }
bool rsx_state::test(u32 reg, u32 value) const
{
return registers[reg] == value;
}
namespace method_detail namespace method_detail
{ {
template<int Id, int Step, int Count, template<u32> class T, int Index = 0> template<int Id, int Step, int Count, template<u32> class T, int Index = 0>
@@ -1567,7 +1560,7 @@ namespace rsx
//Some custom GCM methods //Some custom GCM methods
methods[GCM_SET_DRIVER_OBJECT] = nullptr; methods[GCM_SET_DRIVER_OBJECT] = nullptr;
bind_array<GCM_FLIP_HEAD, 1, 2, nullptr>(); bind_array<GCM_FLIP_HEAD, 1, 2, nullptr>();
bind_array<GCM_DRIVER_QUEUE, 1, 8, nullptr>(); bind_array<GCM_DRIVER_QUEUE, 1, 8, nullptr>();
@@ -1684,8 +1677,8 @@ namespace rsx
// custom methods // custom methods
bind<GCM_FLIP_COMMAND, flip_command>(); bind<GCM_FLIP_COMMAND, flip_command>();
return true;
return true;
}(); }();
} }