diff --git a/src/xenia/cpu/processor.cc b/src/xenia/cpu/processor.cc index 6a214c1db..d8c2c16bc 100644 --- a/src/xenia/cpu/processor.cc +++ b/src/xenia/cpu/processor.cc @@ -45,7 +45,8 @@ namespace { Processor::Processor(xe_memory_ref memory, shared_ptr backend) : - sym_table_(NULL), jit_(NULL) { + sym_table_(NULL), jit_(NULL), + interrupt_thread_lock_(NULL), interrupt_thread_state_(NULL) { memory_ = xe_memory_retain(memory); backend_ = backend; @@ -64,6 +65,9 @@ Processor::~Processor() { } modules_.clear(); + DeallocThread(interrupt_thread_state_); + xe_mutex_free(interrupt_thread_lock_); + delete jit_; delete sym_table_; @@ -98,6 +102,9 @@ void Processor::set_export_resolver( int Processor::Setup() { XEASSERTNULL(jit_); + interrupt_thread_lock_ = xe_mutex_alloc(10000); + interrupt_thread_state_ = AllocThread(16 * 1024, 0, 0); + sym_table_ = new SymbolTable(); jit_ = backend_->CreateJIT(memory_, sym_table_); @@ -245,6 +252,15 @@ uint64_t Processor::Execute(ThreadState* thread_state, uint32_t address, return ppc_state->r[3]; } +uint64_t Processor::ExecuteInterrupt(uint32_t address, + uint64_t arg0, uint64_t arg1) { + // Acquire lock on interrupt thread (we can only dispatch one at a time). + xe_mutex_lock(interrupt_thread_lock_); + uint64_t result = Execute(interrupt_thread_state_, address, arg0, arg1); + xe_mutex_unlock(interrupt_thread_lock_); + return result; +} + FunctionSymbol* Processor::GetFunction(uint32_t address) { // Attempt to grab the function symbol from the global lookup table. FunctionSymbol* fn_symbol = sym_table_->GetFunction(address); diff --git a/src/xenia/cpu/processor.h b/src/xenia/cpu/processor.h index a1bc2159a..72f11eabb 100644 --- a/src/xenia/cpu/processor.h +++ b/src/xenia/cpu/processor.h @@ -56,10 +56,14 @@ public: ThreadState* AllocThread(uint32_t stack_size, uint32_t thread_state_address, uint32_t thread_id); void DeallocThread(ThreadState* thread_state); + int Execute(ThreadState* thread_state, uint32_t address); uint64_t Execute(ThreadState* thread_state, uint32_t address, uint64_t arg0); uint64_t Execute(ThreadState* thread_state, uint32_t address, uint64_t arg0, uint64_t arg1); + + uint64_t ExecuteInterrupt(uint32_t address, uint64_t arg0, uint64_t arg1); + sdb::FunctionSymbol* GetFunction(uint32_t address); void* GetFunctionPointer(uint32_t address); @@ -72,6 +76,9 @@ private: sdb::SymbolTable* sym_table_; JIT* jit_; std::vector modules_; + + xe_mutex_t* interrupt_thread_lock_; + ThreadState* interrupt_thread_state_; }; diff --git a/src/xenia/gpu/graphics_system.cc b/src/xenia/gpu/graphics_system.cc index f42f4feae..72b3e2d5c 100644 --- a/src/xenia/gpu/graphics_system.cc +++ b/src/xenia/gpu/graphics_system.cc @@ -8,7 +8,8 @@ */ #include - + +#include #include @@ -16,7 +17,8 @@ using namespace xe; using namespace xe::gpu; -GraphicsSystem::GraphicsSystem(const CreationParams* params) { +GraphicsSystem::GraphicsSystem(const CreationParams* params) : + interrupt_callback_(0), interrupt_callback_data_(0) { memory_ = xe_memory_retain(params->memory); worker_ = new RingBufferWorker(memory_); @@ -33,6 +35,21 @@ xe_memory_ref GraphicsSystem::memory() { return xe_memory_retain(memory_); } +shared_ptr GraphicsSystem::processor() { + return processor_; +} + +void GraphicsSystem::set_processor(shared_ptr processor) { + processor_ = processor; +} + +void GraphicsSystem::SetInterruptCallback(uint32_t callback, + uint32_t user_data) { + interrupt_callback_ = callback; + interrupt_callback_data_ = user_data; + XELOGGPU("SetInterruptCallback(%.4X, %.4X)", callback, user_data); +} + void GraphicsSystem::InitializeRingBuffer(uint32_t ptr, uint32_t page_count) { worker_->Initialize(ptr, page_count); } @@ -44,6 +61,12 @@ void GraphicsSystem::EnableReadPointerWriteBack(uint32_t ptr, uint64_t GraphicsSystem::ReadRegister(uint32_t r) { XELOGGPU("ReadRegister(%.4X)", r); + + switch (r) { + case 0x6544: // ? vblank pending? + return 1; + } + return 0; } @@ -60,3 +83,12 @@ void GraphicsSystem::WriteRegister(uint32_t r, uint64_t value) { break; } } + +void GraphicsSystem::DispatchInterruptCallback() { + // NOTE: we may be executing in some random thread. + if (!interrupt_callback_) { + return; + } + processor_->ExecuteInterrupt( + interrupt_callback_, 0, interrupt_callback_data_); +} diff --git a/src/xenia/gpu/graphics_system.h b/src/xenia/gpu/graphics_system.h index 0e1739f6c..06122ac78 100644 --- a/src/xenia/gpu/graphics_system.h +++ b/src/xenia/gpu/graphics_system.h @@ -13,6 +13,13 @@ #include +namespace xe { +namespace cpu { +class Processor; +} // namespace cpu +} // namespace xe + + namespace xe { namespace gpu { @@ -32,19 +39,25 @@ public: virtual ~GraphicsSystem(); xe_memory_ref memory(); + shared_ptr processor(); + void set_processor(shared_ptr processor); virtual void Initialize() = 0; + void SetInterruptCallback(uint32_t callback, uint32_t user_data); void InitializeRingBuffer(uint32_t ptr, uint32_t page_count); void EnableReadPointerWriteBack(uint32_t ptr, uint32_t block_size); virtual uint64_t ReadRegister(uint32_t r); virtual void WriteRegister(uint32_t r, uint64_t value); + void DispatchInterruptCallback(); + public: static uint64_t ReadRegisterThunk(GraphicsSystem* this_ptr, uint32_t r) { return this_ptr->ReadRegister(r); } - static void WriteRegisterThunk(GraphicsSystem* this_ptr, uint32_t r, uint64_t value) { + static void WriteRegisterThunk(GraphicsSystem* this_ptr, uint32_t r, + uint64_t value) { this_ptr->WriteRegister(r, value); } @@ -52,8 +65,12 @@ protected: GraphicsSystem(const CreationParams* params); xe_memory_ref memory_; + shared_ptr processor_; RingBufferWorker* worker_; + + uint32_t interrupt_callback_; + uint32_t interrupt_callback_data_; }; diff --git a/src/xenia/gpu/nop/nop_graphics_system.cc b/src/xenia/gpu/nop/nop_graphics_system.cc index 47cbe677e..aa03902d5 100644 --- a/src/xenia/gpu/nop/nop_graphics_system.cc +++ b/src/xenia/gpu/nop/nop_graphics_system.cc @@ -17,12 +17,41 @@ using namespace xe::gpu; using namespace xe::gpu::nop; +namespace { + +void __stdcall NopGraphicsSystemVsyncCallback(NopGraphicsSystem* gs, BOOLEAN) { + gs->DispatchInterruptCallback(); +} + +} + + NopGraphicsSystem::NopGraphicsSystem(const CreationParams* params) : - GraphicsSystem(params) { + GraphicsSystem(params), + timer_queue_(NULL), + vsync_timer_(NULL) { } NopGraphicsSystem::~NopGraphicsSystem() { + if (vsync_timer_) { + DeleteTimerQueueTimer(timer_queue_, vsync_timer_, NULL); + } + if (timer_queue_) { + DeleteTimerQueueEx(timer_queue_, NULL); + } } void NopGraphicsSystem::Initialize() { + XEASSERTNULL(timer_queue_); + XEASSERTNULL(vsync_timer_); + + timer_queue_ = CreateTimerQueue(); + CreateTimerQueueTimer( + &vsync_timer_, + timer_queue_, + (WAITORTIMERCALLBACK)NopGraphicsSystemVsyncCallback, + this, + 16, + 100, + WT_EXECUTEINTIMERTHREAD); } diff --git a/src/xenia/gpu/nop/nop_graphics_system.h b/src/xenia/gpu/nop/nop_graphics_system.h index 2ce91976b..45dd05b7e 100644 --- a/src/xenia/gpu/nop/nop_graphics_system.h +++ b/src/xenia/gpu/nop/nop_graphics_system.h @@ -27,6 +27,10 @@ public: virtual ~NopGraphicsSystem(); virtual void Initialize(); + +private: + HANDLE timer_queue_; + HANDLE vsync_timer_; }; diff --git a/src/xenia/kernel/modules/xboxkrnl/xboxkrnl_video.cc b/src/xenia/kernel/modules/xboxkrnl/xboxkrnl_video.cc index 9d9e6561a..4534ad8d0 100644 --- a/src/xenia/kernel/modules/xboxkrnl/xboxkrnl_video.cc +++ b/src/xenia/kernel/modules/xboxkrnl/xboxkrnl_video.cc @@ -130,7 +130,7 @@ void xeVdInitializeEngines(uint32_t unk0, uint32_t callback, uint32_t unk1, } // r3 = 0x4F810000 - // r4 = function ptr (ready callback?) + // r4 = function ptr (cleanup callback?) // r5 = 0 // r6/r7 = some binary data in .data @@ -166,7 +166,7 @@ void xeVdSetGraphicsInterruptCallback(uint32_t callback, uint32_t user_data) { // r3 = bool 0/1 - 0 is normal interrupt, 1 is some acquire/lock mumble // r4 = user_data (r4 of VdSetGraphicsInterruptCallback) - //gs->SetupInterruptCallback(callback, user_data); + gs->SetInterruptCallback(callback, user_data); } @@ -230,6 +230,8 @@ void xeVdEnableRingBufferRPtrWriteBack(uint32_t ptr, uint32_t block_size) { printf("%.8X", ptr); // 0x0110343c + // r3 = 0x2B10(d3d?) + 0x3C + //((p + 0x3C) & 0x1FFFFFFF) + ((((p + 0x3C) >> 20) + 0x200) & 0x1000) //also 0x3C offset into WriteBacks is PrimaryRingBufferReadIndex //(1:17:38 AM) Rick: .text:8201B348 lwz r11, 0x2B10(r31) diff --git a/tools/xenia-run/xenia-run.cc b/tools/xenia-run/xenia-run.cc index ce4016999..b3a67139a 100644 --- a/tools/xenia-run/xenia-run.cc +++ b/tools/xenia-run/xenia-run.cc @@ -68,6 +68,8 @@ int Run::Setup() { processor_ = shared_ptr(new Processor(memory_, backend_)); processor_->set_graphics_system(graphics_system_); + graphics_system_->set_processor(processor_); + XEEXPECTZERO(processor_->Setup()); runtime_ = shared_ptr(new Runtime(processor_, XT("")));