diff --git a/src/xenia/core/memory.cc b/src/xenia/core/memory.cc index 2b8283deb..6ca33f8b4 100644 --- a/src/xenia/core/memory.cc +++ b/src/xenia/core/memory.cc @@ -29,12 +29,14 @@ /** * Memory map: - * 0x00000000 - 0x40000000 (1024mb) - virtual 4k pages - * 0x40000000 - 0x80000000 (1024mb) - virtual 64k pages - * 0x80000000 - 0x8C000000 ( 192mb) - xex 64k pages - * 0x8C000000 - 0x90000000 ( 64mb) - xex 64k pages (encrypted) - * 0x90000000 - 0xA0000000 ( 256mb) - xex 4k pages - * 0xA0000000 - 0xC0000000 ( 512mb) - physical 64k pages + * 0x00000000 - 0x3FFFFFFF (1024mb) - virtual 4k pages + * 0x40000000 - 0x7FFFFFFF (1024mb) - virtual 64k pages + * 0x80000000 - 0x8BFFFFFF ( 192mb) - xex 64k pages + * 0x8C000000 - 0x8FFFFFFF ( 64mb) - xex 64k pages (encrypted) + * 0x90000000 - 0x9FFFFFFF ( 256mb) - xex 4k pages + * 0xA0000000 - 0xBFFFFFFF ( 512mb) - physical 64k pages + * 0xC0000000 - 0xDFFFFFFF - physical 16mb pages + * 0xE0000000 - 0xFFFFFFFF - physical 4k pages * * We use the host OS to create an entire addressable range for this. That way * we don't have to emulate a TLB. It'd be really cool to pass through page diff --git a/src/xenia/gpu/graphics_system.cc b/src/xenia/gpu/graphics_system.cc index 907861c8b..f42f4feae 100644 --- a/src/xenia/gpu/graphics_system.cc +++ b/src/xenia/gpu/graphics_system.cc @@ -37,6 +37,11 @@ void GraphicsSystem::InitializeRingBuffer(uint32_t ptr, uint32_t page_count) { worker_->Initialize(ptr, page_count); } +void GraphicsSystem::EnableReadPointerWriteBack(uint32_t ptr, + uint32_t block_size) { + worker_->EnableReadPointerWriteBack(ptr, block_size); +} + uint64_t GraphicsSystem::ReadRegister(uint32_t r) { XELOGGPU("ReadRegister(%.4X)", r); return 0; diff --git a/src/xenia/gpu/graphics_system.h b/src/xenia/gpu/graphics_system.h index 24749184c..0e1739f6c 100644 --- a/src/xenia/gpu/graphics_system.h +++ b/src/xenia/gpu/graphics_system.h @@ -35,6 +35,7 @@ public: virtual void Initialize() = 0; 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); diff --git a/src/xenia/gpu/ring_buffer_worker.cc b/src/xenia/gpu/ring_buffer_worker.cc index 6546cbcff..57d160cec 100644 --- a/src/xenia/gpu/ring_buffer_worker.cc +++ b/src/xenia/gpu/ring_buffer_worker.cc @@ -43,6 +43,17 @@ void RingBufferWorker::Initialize(uint32_t ptr, uint32_t page_count) { xe_thread_start(thread_); } +void RingBufferWorker::EnableReadPointerWriteBack(uint32_t ptr, + uint32_t block_size) { + // CP_RB_RPTR_ADDR Ring Buffer Read Pointer Address 0x70C + // ptr = RB_RPTR_ADDR, pointer to write back the address to. + read_ptr_writeback_ptr_ = (primary_buffer_ptr_ & ~0x1FFFFFFF) + ptr; + // CP_RB_CNTL Ring Buffer Control 0x704 + // block_size = RB_BLKSZ, number of quadwords read between updates of the + // read pointer. + read_ptr_update_freq_ = (uint32_t)pow(2.0, (double)block_size) / 4; +} + void RingBufferWorker::UpdateWritePointer(uint32_t value) { write_ptr_index_ = value; SetEvent(write_ptr_index_event_); @@ -74,22 +85,30 @@ void RingBufferWorker::ThreadStart() { while (true) { uint32_t command = READ_UINT32(); - XELOGGPU("Command(%.8X)", command); switch (command) { case 0xC0114800: - // Init packet. - // Will have 18-19 ops after it. Maybe. - for (int n = 0; n < 18; n++) { - READ_UINT32(); + { + // Init packet. + // Will have 18-19 ops after it. Maybe. + XELOGGPU("Command(%.8X): init packet", command); + for (int n = 0; n < 18; n++) { + READ_UINT32(); + } } break; case 0xC0013F00: - // Kick segment. - uint32_t segment_ptr = READ_UINT32(); - uint32_t length = READ_UINT32(); - XELOGGPU("Command(%.8X): kick segment %.8X (%db)", - command, segment_ptr, length); + { + // Kick segment. + uint32_t segment_ptr = READ_UINT32(); + uint32_t length = READ_UINT32(); + XELOGGPU("Command(%.8X): kick segment %.8X (%db)", + command, segment_ptr, length * 4); + ExecuteSegment(segment_ptr, length); + } + break; + default: + XELOGGPU("Command(%.8X): unknown primary buffer command", command); break; } @@ -98,6 +117,26 @@ void RingBufferWorker::ThreadStart() { } } + // TODO(benvanik): use read_ptr_update_freq_ and only issue after moving + // that many indices. + if (read_ptr_writeback_ptr_) { + XESETUINT32BE(p + read_ptr_writeback_ptr_, read_ptr_index_); + } SetEvent(read_ptr_index_event_); } } + +void RingBufferWorker::ExecuteSegment(uint32_t ptr, uint32_t length) { + uint8_t* p = xe_memory_addr(memory_); + + // Adjust pointer base. + ptr += (primary_buffer_ptr_ & ~0x1FFFFFFF); + + XELOGGPU("CommandList(%.8X): executing %d commands", ptr, length); + + // Execute commands! + for (uint32_t n = 0; n < length; n++) { + uint32_t command = XEGETUINT32BE(p + ptr + n * 4); + XELOGGPU(" Command(%.8X)", command); + } +} \ No newline at end of file diff --git a/src/xenia/gpu/ring_buffer_worker.h b/src/xenia/gpu/ring_buffer_worker.h index d65b9cffb..d9c3e8c93 100644 --- a/src/xenia/gpu/ring_buffer_worker.h +++ b/src/xenia/gpu/ring_buffer_worker.h @@ -25,6 +25,7 @@ public: xe_memory_ref memory(); void Initialize(uint32_t ptr, uint32_t page_count); + void EnableReadPointerWriteBack(uint32_t ptr, uint32_t block_size); void UpdateWritePointer(uint32_t value); @@ -33,19 +34,22 @@ protected: this_ptr->ThreadStart(); } void ThreadStart(); + void ExecuteSegment(uint32_t ptr, uint32_t length); protected: xe_memory_ref memory_; xe_thread_ref thread_; bool running_; - HANDLE read_ptr_index_event_; - HANDLE write_ptr_index_event_; - + uint32_t primary_buffer_ptr_; uint32_t primary_buffer_size_; - uint32_t secondary_buffer_ptr_; - uint32_t secondary_buffer_size_; + + HANDLE read_ptr_index_event_; uint32_t read_ptr_index_; + uint32_t read_ptr_update_freq_; + uint32_t read_ptr_writeback_ptr_; + + HANDLE write_ptr_index_event_; uint32_t write_ptr_index_; }; diff --git a/src/xenia/kernel/modules/xboxkrnl/xboxkrnl_video.cc b/src/xenia/kernel/modules/xboxkrnl/xboxkrnl_video.cc index 3114ea0dd..5a8f36995 100644 --- a/src/xenia/kernel/modules/xboxkrnl/xboxkrnl_video.cc +++ b/src/xenia/kernel/modules/xboxkrnl/xboxkrnl_video.cc @@ -178,21 +178,45 @@ SHIM_CALL VdInitializeRingBuffer_shim( } -// void VdEnableRingBufferRPtrWriteBack -// r3 = ? pointer? doesn't look like a valid one -// r4 = 6, usually --- <=19 -// Same value used to calculate the pointer is later written to -// Maybe GPU-memory relative? +void xeVdEnableRingBufferRPtrWriteBack(uint32_t ptr, uint32_t block_size) { + KernelState* state = shared_kernel_state_; + XEASSERTNOTNULL(state); + GraphicsSystem* gs = state->processor()->graphics_system().get(); + if (!gs) { + return; + } + + // r4 = 6, usually --- <=19 + gs->EnableReadPointerWriteBack(ptr, block_size); + + ptr += 0x20000000; + printf("%.8X", ptr); + // 0x0110343c + + //((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) +//(1:17:38 AM) Rick: .text:8201B34C addi r11, r11, 0x3C +//(1:17:38 AM) Rick: .text:8201B350 srwi r10, r11, 20 # r10 = r11 >> 20 +//(1:17:38 AM) Rick: .text:8201B354 clrlwi r11, r11, 3 # r11 = r11 & 0x1FFFFFFF +//(1:17:38 AM) Rick: .text:8201B358 addi r10, r10, 0x200 +//(1:17:39 AM) Rick: .text:8201B35C rlwinm r10, r10, 0,19,19 # r10 = r10 & 0x1000 +//(1:17:39 AM) Rick: .text:8201B360 add r3, r10, r11 +//(1:17:39 AM) Rick: .text:8201B364 bl VdEnableRingBufferRPtrWriteBack + // TODO(benvanik): something? +} + + SHIM_CALL VdEnableRingBufferRPtrWriteBack_shim( xe_ppc_state_t* ppc_state, KernelState* state) { uint32_t ptr = SHIM_GET_ARG_32(0); - uint32_t unk1 = SHIM_GET_ARG_32(1); + uint32_t block_size = SHIM_GET_ARG_32(1); XELOGD( "VdEnableRingBufferRPtrWriteBack(%.8X, %.8X)", - ptr, unk1); + ptr, block_size); - // TODO(benvanik): something? + xeVdEnableRingBufferRPtrWriteBack(ptr, block_size); } diff --git a/src/xenia/kernel/modules/xboxkrnl/xboxkrnl_video.h b/src/xenia/kernel/modules/xboxkrnl/xboxkrnl_video.h index a5d6c5ef8..e6a207262 100644 --- a/src/xenia/kernel/modules/xboxkrnl/xboxkrnl_video.h +++ b/src/xenia/kernel/modules/xboxkrnl/xboxkrnl_video.h @@ -42,6 +42,7 @@ void xeVdQueryVideoMode(X_VIDEO_MODE *video_mode, bool swap); void xeVdInitializeEngines(uint32_t unk0, uint32_t callback, uint32_t unk1, uint32_t unk2_ptr, uint32_t unk3_ptr); void xeVdSetGraphicsInterruptCallback(uint32_t callback, uint32_t user_data); +void xeVdEnableRingBufferRPtrWriteBack(uint32_t ptr, uint32_t block_size); } // namespace xboxkrnl