From 5b0fa8f17edfba107db634df2984b95a470de7e7 Mon Sep 17 00:00:00 2001 From: Ben Vanik Date: Sat, 1 Jun 2013 01:13:30 -0700 Subject: [PATCH] Basic ringbuffer worker. Super hacky, not yet writing back to CPU. --- src/xenia/gpu/gpu.cc | 2 +- src/xenia/gpu/graphics_system.cc | 30 +++++ src/xenia/gpu/graphics_system.h | 14 ++- src/xenia/gpu/nop/nop_graphics_system.cc | 8 +- src/xenia/gpu/nop/nop_graphics_system.h | 3 +- src/xenia/gpu/ring_buffer_worker.cc | 103 ++++++++++++++++++ src/xenia/gpu/ring_buffer_worker.h | 57 ++++++++++ src/xenia/gpu/sources.gypi | 4 +- .../kernel/modules/xboxkrnl/xboxkrnl_video.cc | 78 ++++++++++--- 9 files changed, 270 insertions(+), 29 deletions(-) create mode 100644 src/xenia/gpu/ring_buffer_worker.cc create mode 100644 src/xenia/gpu/ring_buffer_worker.h diff --git a/src/xenia/gpu/gpu.cc b/src/xenia/gpu/gpu.cc index 14849c777..42b95a055 100644 --- a/src/xenia/gpu/gpu.cc +++ b/src/xenia/gpu/gpu.cc @@ -11,7 +11,7 @@ #include #if XE_PLATFORM(WIN32) -#include +//#include #endif // WIN32 #include diff --git a/src/xenia/gpu/graphics_system.cc b/src/xenia/gpu/graphics_system.cc index bd169e407..907861c8b 100644 --- a/src/xenia/gpu/graphics_system.cc +++ b/src/xenia/gpu/graphics_system.cc @@ -9,6 +9,8 @@ #include +#include + using namespace xe; using namespace xe::gpu; @@ -16,12 +18,40 @@ using namespace xe::gpu; GraphicsSystem::GraphicsSystem(const CreationParams* params) { memory_ = xe_memory_retain(params->memory); + + worker_ = new RingBufferWorker(memory_); } GraphicsSystem::~GraphicsSystem() { + // TODO(benvanik): worker join/etc. + delete worker_; + xe_memory_release(memory_); } xe_memory_ref GraphicsSystem::memory() { return xe_memory_retain(memory_); } + +void GraphicsSystem::InitializeRingBuffer(uint32_t ptr, uint32_t page_count) { + worker_->Initialize(ptr, page_count); +} + +uint64_t GraphicsSystem::ReadRegister(uint32_t r) { + XELOGGPU("ReadRegister(%.4X)", r); + return 0; +} + +void GraphicsSystem::WriteRegister(uint32_t r, uint64_t value) { + XELOGGPU("WriteRegister(%.4X, %.8X)", r, value); + + switch (r) { + case 0x0714: // CP_RB_WPTR + worker_->UpdateWritePointer((uint32_t)value); + break; + + default: + XELOGW("Unknown GPU register %.4X write: %.8X", r, value); + break; + } +} diff --git a/src/xenia/gpu/graphics_system.h b/src/xenia/gpu/graphics_system.h index 6b2f7ae38..24749184c 100644 --- a/src/xenia/gpu/graphics_system.h +++ b/src/xenia/gpu/graphics_system.h @@ -16,6 +16,8 @@ namespace xe { namespace gpu { +class RingBufferWorker; + class CreationParams { public: @@ -31,9 +33,13 @@ public: xe_memory_ref memory(); - virtual uint64_t ReadRegister(uint32_t r) = 0; - virtual void WriteRegister(uint32_t r, uint64_t value) = 0; + virtual void Initialize() = 0; + void InitializeRingBuffer(uint32_t ptr, uint32_t page_count); + virtual uint64_t ReadRegister(uint32_t r); + virtual void WriteRegister(uint32_t r, uint64_t value); + +public: static uint64_t ReadRegisterThunk(GraphicsSystem* this_ptr, uint32_t r) { return this_ptr->ReadRegister(r); } @@ -44,7 +50,9 @@ public: protected: GraphicsSystem(const CreationParams* params); - xe_memory_ref memory_; + xe_memory_ref memory_; + + RingBufferWorker* worker_; }; diff --git a/src/xenia/gpu/nop/nop_graphics_system.cc b/src/xenia/gpu/nop/nop_graphics_system.cc index c60d8d952..47cbe677e 100644 --- a/src/xenia/gpu/nop/nop_graphics_system.cc +++ b/src/xenia/gpu/nop/nop_graphics_system.cc @@ -24,11 +24,5 @@ NopGraphicsSystem::NopGraphicsSystem(const CreationParams* params) : NopGraphicsSystem::~NopGraphicsSystem() { } -uint64_t NopGraphicsSystem::ReadRegister(uint32_t r) { - XELOGGPU("ReadRegister(%.4X)", r); - return 0; -} - -void NopGraphicsSystem::WriteRegister(uint32_t r, uint64_t value) { - XELOGGPU("WriteRegister(%.4X, %.8X)", r, value); +void NopGraphicsSystem::Initialize() { } diff --git a/src/xenia/gpu/nop/nop_graphics_system.h b/src/xenia/gpu/nop/nop_graphics_system.h index a201555ee..2ce91976b 100644 --- a/src/xenia/gpu/nop/nop_graphics_system.h +++ b/src/xenia/gpu/nop/nop_graphics_system.h @@ -26,8 +26,7 @@ public: NopGraphicsSystem(const CreationParams* params); virtual ~NopGraphicsSystem(); - virtual uint64_t ReadRegister(uint32_t r); - virtual void WriteRegister(uint32_t r, uint64_t value); + virtual void Initialize(); }; diff --git a/src/xenia/gpu/ring_buffer_worker.cc b/src/xenia/gpu/ring_buffer_worker.cc new file mode 100644 index 000000000..6546cbcff --- /dev/null +++ b/src/xenia/gpu/ring_buffer_worker.cc @@ -0,0 +1,103 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include + + +using namespace xe; +using namespace xe::gpu; + + +RingBufferWorker::RingBufferWorker(xe_memory_ref memory) : + memory_(memory) { + running_ = true; + read_ptr_index_event_ = CreateEvent( + NULL, FALSE, FALSE, NULL); + write_ptr_index_event_ = CreateEvent( + NULL, FALSE, FALSE, NULL); + + thread_ = xe_thread_create( + "RingBufferWorker", + (xe_thread_callback)ThreadStartThunk, this); +} + +RingBufferWorker::~RingBufferWorker() { + // TODO(benvanik): thread join. + running_ = false; + SetEvent(write_ptr_index_event_); + xe_thread_release(thread_); + CloseHandle(write_ptr_index_event_); +} + +void RingBufferWorker::Initialize(uint32_t ptr, uint32_t page_count) { + primary_buffer_ptr_ = ptr; + primary_buffer_size_ = page_count * 4 * 1024; + read_ptr_index_ = 0; + + xe_thread_start(thread_); +} + +void RingBufferWorker::UpdateWritePointer(uint32_t value) { + write_ptr_index_ = value; + SetEvent(write_ptr_index_event_); +} + +void RingBufferWorker::ThreadStart() { + uint8_t* p = xe_memory_addr(memory_); + + while (running_) { + if (write_ptr_index_ == 0xBAADF00D || + read_ptr_index_ == write_ptr_index_) { + // Wait for the command buffer pointer to move. + // TODO(benvanik): only wait for a bit and check running_. + WaitForSingleObject(write_ptr_index_event_, INFINITE); + if (!running_) { + break; + } + } + if (read_ptr_index_ == write_ptr_index_) { + continue; + } + + // Process the new commands. + XELOGGPU("Ring buffer thread work"); + + #define READ_UINT32() \ + XEGETUINT32BE(p + primary_buffer_ptr_ + read_ptr_index_ * 4); \ + read_ptr_index_ = (read_ptr_index_ + 1) % (primary_buffer_size_ / 4); + + 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(); + } + 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); + break; + } + + if (read_ptr_index_ == write_ptr_index_) { + break; + } + } + + SetEvent(read_ptr_index_event_); + } +} diff --git a/src/xenia/gpu/ring_buffer_worker.h b/src/xenia/gpu/ring_buffer_worker.h new file mode 100644 index 000000000..d65b9cffb --- /dev/null +++ b/src/xenia/gpu/ring_buffer_worker.h @@ -0,0 +1,57 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef XENIA_GPU_RING_BUFFER_WORKER_H_ +#define XENIA_GPU_RING_BUFFER_WORKER_H_ + +#include + + +namespace xe { +namespace gpu { + + +class RingBufferWorker { +public: + RingBufferWorker(xe_memory_ref memory); + virtual ~RingBufferWorker(); + + xe_memory_ref memory(); + + void Initialize(uint32_t ptr, uint32_t page_count); + + void UpdateWritePointer(uint32_t value); + +protected: + static void ThreadStartThunk(RingBufferWorker* this_ptr) { + this_ptr->ThreadStart(); + } + void ThreadStart(); + +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_; + uint32_t read_ptr_index_; + uint32_t write_ptr_index_; +}; + + +} // namespace gpu +} // namespace xe + + +#endif // XENIA_GPU_RING_BUFFER_WORKER_H_ diff --git a/src/xenia/gpu/sources.gypi b/src/xenia/gpu/sources.gypi index 366bb049d..d1c157aeb 100644 --- a/src/xenia/gpu/sources.gypi +++ b/src/xenia/gpu/sources.gypi @@ -6,6 +6,8 @@ 'gpu.h', 'graphics_system.cc', 'graphics_system.h', + 'ring_buffer_worker.cc', + 'ring_buffer_worker.h', ], 'includes': [ @@ -15,7 +17,7 @@ 'conditions': [ ['OS == "win"', { 'includes': [ - 'd3d11/sources.gypi', + #'d3d11/sources.gypi', ], }], ], diff --git a/src/xenia/kernel/modules/xboxkrnl/xboxkrnl_video.cc b/src/xenia/kernel/modules/xboxkrnl/xboxkrnl_video.cc index 1938aab4d..3114ea0dd 100644 --- a/src/xenia/kernel/modules/xboxkrnl/xboxkrnl_video.cc +++ b/src/xenia/kernel/modules/xboxkrnl/xboxkrnl_video.cc @@ -9,6 +9,7 @@ #include +#include #include #include #include @@ -16,6 +17,7 @@ using namespace xe; +using namespace xe::gpu; using namespace xe::kernel; using namespace xe::kernel::xboxkrnl; @@ -83,10 +85,19 @@ SHIM_CALL VdQueryVideoMode_shim( void xeVdInitializeEngines(uint32_t unk0, uint32_t callback, uint32_t unk1, uint32_t unk2_ptr, uint32_t unk3_ptr) { + KernelState* state = shared_kernel_state_; + XEASSERTNOTNULL(state); + GraphicsSystem* gs = state->processor()->graphics_system().get(); + if (!gs) { + return; + } + // r3 = 0x4F810000 // r4 = function ptr (ready callback?) // r5 = 0 // r6/r7 = some binary data in .data + + gs->Initialize(); } @@ -107,9 +118,18 @@ SHIM_CALL VdInitializeEngines_shim( void xeVdSetGraphicsInterruptCallback(uint32_t callback, uint32_t user_data) { + KernelState* state = shared_kernel_state_; + XEASSERTNOTNULL(state); + GraphicsSystem* gs = state->processor()->graphics_system().get(); + if (!gs) { + return; + } + // callback takes 2 params // 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); } @@ -126,21 +146,36 @@ SHIM_CALL VdSetGraphicsInterruptCallback_shim( } -// VdInitializeRingBuffer -// r3 = result of MmGetPhysicalAddress -// r4 = number of pages? page size? -// 0x8000 -> cntlzw=16 -> 0x1C - 16 = 12 -// ring_buffer_t { -// uint 0 -// uint buffer_0_size -// uint buffer_0_ptr -// uint buffer_1_size -// uint buffer_1_ptr -// uint segment_count -- 32 common -// } -// Buffer pointers are from MmAllocatePhysicalMemory with WRITE_COMBINE. -// Sizes could be zero? XBLA games seem to do this. Default sizes? -// D3D does size / region_count - must be > 1024 +void xeVdInitializeRingBuffer(uint32_t ptr, uint32_t page_count) { + KernelState* state = shared_kernel_state_; + XEASSERTNOTNULL(state); + GraphicsSystem* gs = state->processor()->graphics_system().get(); + if (!gs) { + return; + } + + // r3 = result of MmGetPhysicalAddress + // r4 = number of pages? page size? + // 0x8000 -> cntlzw=16 -> 0x1C - 16 = 12 + // Buffer pointers are from MmAllocatePhysicalMemory with WRITE_COMBINE. + // Sizes could be zero? XBLA games seem to do this. Default sizes? + // D3D does size / region_count - must be > 1024 + + gs->InitializeRingBuffer(ptr, page_count); +} + + +SHIM_CALL VdInitializeRingBuffer_shim( + xe_ppc_state_t* ppc_state, KernelState* state) { + uint32_t ptr = SHIM_GET_ARG_32(0); + uint32_t page_count = SHIM_GET_ARG_32(1); + + XELOGD( + "VdInitializeRingBuffer(%.8X, %.8X)", + ptr, page_count); + + xeVdInitializeRingBuffer(ptr, page_count); +} // void VdEnableRingBufferRPtrWriteBack @@ -148,6 +183,17 @@ SHIM_CALL VdSetGraphicsInterruptCallback_shim( // r4 = 6, usually --- <=19 // Same value used to calculate the pointer is later written to // Maybe GPU-memory relative? +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); + + XELOGD( + "VdEnableRingBufferRPtrWriteBack(%.8X, %.8X)", + ptr, unk1); + + // TODO(benvanik): something? +} // VdSetSystemCommandBufferGpuIdentifierAddress @@ -176,6 +222,8 @@ void xe::kernel::xboxkrnl::RegisterVideoExports( SHIM_SET_MAPPING("xboxkrnl.exe", VdQueryVideoMode, state); SHIM_SET_MAPPING("xboxkrnl.exe", VdInitializeEngines, state); SHIM_SET_MAPPING("xboxkrnl.exe", VdSetGraphicsInterruptCallback, state); + SHIM_SET_MAPPING("xboxkrnl.exe", VdInitializeRingBuffer, state); + SHIM_SET_MAPPING("xboxkrnl.exe", VdEnableRingBufferRPtrWriteBack, state); xe_memory_ref memory = state->memory(); uint8_t* mem = xe_memory_addr(memory);