diff --git a/src/xenia/gpu/graphics_driver.cc b/src/xenia/gpu/graphics_driver.cc new file mode 100644 index 000000000..e94eff241 --- /dev/null +++ b/src/xenia/gpu/graphics_driver.cc @@ -0,0 +1,29 @@ +/** + ****************************************************************************** + * 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; + + +GraphicsDriver::GraphicsDriver(xe_memory_ref memory) { + memory_ = xe_memory_retain(memory); + + memset(®ister_file_, 0, sizeof(register_file_)); +} + +GraphicsDriver::~GraphicsDriver() { + xe_memory_release(memory_); +} + +xe_memory_ref GraphicsDriver::memory() { + return xe_memory_retain(memory_); +} diff --git a/src/xenia/gpu/graphics_driver.h b/src/xenia/gpu/graphics_driver.h new file mode 100644 index 000000000..2122b9cea --- /dev/null +++ b/src/xenia/gpu/graphics_driver.h @@ -0,0 +1,79 @@ +/** + ****************************************************************************** + * 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_GRAPHICS_DRIVER_H_ +#define XENIA_GPU_GRAPHICS_DRIVER_H_ + +#include +#include + + +namespace xe { +namespace gpu { + + +typedef enum { + XE_GPU_SHADER_TYPE_VERTEX = 0x00, + XE_GPU_SHADER_TYPE_PIXEL = 0x01, +} XE_GPU_SHADER_TYPE; + +typedef enum { + XE_GPU_INVALIDATE_MASK_VERTEX_SHADER = 1 << 8, + XE_GPU_INVALIDATE_MASK_PIXEL_SHADER = 1 << 9, + + XE_GPU_INVALIDATE_MASK_ALL = 0x7FFF, +} XE_GPU_INVALIDATE_MASK; + +typedef enum { + XE_GPU_PRIMITIVE_TYPE_POINT_LIST = 0x01, + XE_GPU_PRIMITIVE_TYPE_LINE_LIST = 0x02, + XE_GPU_PRIMITIVE_TYPE_LINE_STRIP = 0x03, + XE_GPU_PRIMITIVE_TYPE_TRIANGLE_LIST = 0x04, + XE_GPU_PRIMITIVE_TYPE_TRIANGLE_FAN = 0x05, + XE_GPU_PRIMITIVE_TYPE_TRIANGLE_STRIP = 0x06, + XE_GPU_PRIMITIVE_TYPE_UNKNOWN_07 = 0x07, + XE_GPU_PRIMITIVE_TYPE_RECTANGLE_LIST = 0x08, + XE_GPU_PRIMITIVE_TYPE_LINE_LOOP = 0x0C, +} XE_GPU_PRIMITIVE_TYPE; + + +class GraphicsDriver { +public: + virtual ~GraphicsDriver(); + + xe_memory_ref memory(); + xenos::RegisterFile* register_file() { return ®ister_file_; }; + + virtual void Initialize() = 0; + + virtual void InvalidateState( + uint32_t mask) = 0; + virtual void SetShader( + XE_GPU_SHADER_TYPE type, + uint32_t address, + uint32_t start, + uint32_t size_dwords) = 0; + virtual void DrawIndexed( + XE_GPU_PRIMITIVE_TYPE prim_type, + uint32_t index_count) = 0; + +protected: + GraphicsDriver(xe_memory_ref memory); + + xe_memory_ref memory_; + + xenos::RegisterFile register_file_; +}; + + +} // namespace gpu +} // namespace xe + + +#endif // XENIA_GPU_GRAPHICS_DRIVER_H_ diff --git a/src/xenia/gpu/graphics_system.cc b/src/xenia/gpu/graphics_system.cc index 72b3e2d5c..4ee216da4 100644 --- a/src/xenia/gpu/graphics_system.cc +++ b/src/xenia/gpu/graphics_system.cc @@ -8,13 +8,16 @@ */ #include - + #include +#include #include +#include using namespace xe; using namespace xe::gpu; +using namespace xe::gpu::xenos; GraphicsSystem::GraphicsSystem(const CreationParams* params) : @@ -22,6 +25,9 @@ GraphicsSystem::GraphicsSystem(const CreationParams* params) : memory_ = xe_memory_retain(params->memory); worker_ = new RingBufferWorker(memory_); + + // Set during Initialize(); + driver_ = 0; } GraphicsSystem::~GraphicsSystem() { @@ -51,7 +57,8 @@ void GraphicsSystem::SetInterruptCallback(uint32_t callback, } void GraphicsSystem::InitializeRingBuffer(uint32_t ptr, uint32_t page_count) { - worker_->Initialize(ptr, page_count); + XEASSERTNOTNULL(driver_); + worker_->Initialize(driver_, ptr, page_count); } void GraphicsSystem::EnableReadPointerWriteBack(uint32_t ptr, @@ -62,26 +69,31 @@ void GraphicsSystem::EnableReadPointerWriteBack(uint32_t ptr, uint64_t GraphicsSystem::ReadRegister(uint32_t r) { XELOGGPU("ReadRegister(%.4X)", r); + RegisterFile* regs = driver_->register_file(); + switch (r) { case 0x6544: // ? vblank pending? return 1; } - return 0; + XEASSERT(r >= 0 && r < kXEGpuRegisterCount); + return regs->values[r].u32; } void GraphicsSystem::WriteRegister(uint32_t r, uint64_t value) { XELOGGPU("WriteRegister(%.4X, %.8X)", r, value); + RegisterFile* regs = driver_->register_file(); + switch (r) { case 0x0714: // CP_RB_WPTR worker_->UpdateWritePointer((uint32_t)value); break; - - default: - XELOGW("Unknown GPU register %.4X write: %.8X", r, value); - break; } + + XEASSERT(r >= 0 && r < kXEGpuRegisterCount); + XELOGW("Unknown GPU register %.4X write: %.8X", r, value); + regs->values[r].u32 = (uint32_t)value; } void GraphicsSystem::DispatchInterruptCallback() { diff --git a/src/xenia/gpu/graphics_system.h b/src/xenia/gpu/graphics_system.h index 06122ac78..3c3bf58be 100644 --- a/src/xenia/gpu/graphics_system.h +++ b/src/xenia/gpu/graphics_system.h @@ -13,16 +13,17 @@ #include -namespace xe { -namespace cpu { -class Processor; -} // namespace cpu -} // namespace xe +namespace xe { +namespace cpu { +class Processor; +} // namespace cpu +} // namespace xe namespace xe { namespace gpu { +class GraphicsDriver; class RingBufferWorker; @@ -53,6 +54,8 @@ public: void DispatchInterruptCallback(); public: + // TODO(benvanik): have an HasRegisterHandler() so that the JIT can + // just poke the register file directly. static uint64_t ReadRegisterThunk(GraphicsSystem* this_ptr, uint32_t r) { return this_ptr->ReadRegister(r); } @@ -67,6 +70,7 @@ protected: xe_memory_ref memory_; shared_ptr processor_; + GraphicsDriver* driver_; RingBufferWorker* worker_; uint32_t interrupt_callback_; diff --git a/src/xenia/gpu/nop/nop_graphics_driver.cc b/src/xenia/gpu/nop/nop_graphics_driver.cc new file mode 100644 index 000000000..f706c25f3 --- /dev/null +++ b/src/xenia/gpu/nop/nop_graphics_driver.cc @@ -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. * + ****************************************************************************** + */ + +#include + +#include + + +using namespace xe; +using namespace xe::gpu; +using namespace xe::gpu::nop; + + +NopGraphicsDriver::NopGraphicsDriver(xe_memory_ref memory) : + GraphicsDriver(memory) { +} + +NopGraphicsDriver::~NopGraphicsDriver() { +} + +void NopGraphicsDriver::Initialize() { +} + +void NopGraphicsDriver::InvalidateState( + uint32_t mask) { + if (mask == XE_GPU_INVALIDATE_MASK_ALL) { + XELOGGPU("NOP: (invalidate all)"); + } + if (mask & XE_GPU_INVALIDATE_MASK_VERTEX_SHADER) { + XELOGGPU("NOP: invalidate vertex shader"); + } + if (mask & XE_GPU_INVALIDATE_MASK_PIXEL_SHADER) { + XELOGGPU("NOP: invalidate pixel shader"); + } +} + +void NopGraphicsDriver::SetShader( + XE_GPU_SHADER_TYPE type, + uint32_t address, + uint32_t start, + uint32_t size_dwords) { + XELOGGPU("NOP: set shader %d at %0.8X (%db)", + type, address, size_dwords * 4); +} + +void NopGraphicsDriver::DrawIndexed( + XE_GPU_PRIMITIVE_TYPE prim_type, + uint32_t index_count) { + XELOGGPU("NOP: draw indexed %d (%d indicies)", + prim_type, index_count); +} \ No newline at end of file diff --git a/src/xenia/gpu/nop/nop_graphics_driver.h b/src/xenia/gpu/nop/nop_graphics_driver.h new file mode 100644 index 000000000..7aaa32018 --- /dev/null +++ b/src/xenia/gpu/nop/nop_graphics_driver.h @@ -0,0 +1,51 @@ +/** + ****************************************************************************** + * 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_NOP_NOP_GRAPHICS_DRIVER_H_ +#define XENIA_GPU_NOP_NOP_GRAPHICS_DRIVER_H_ + +#include + +#include +#include + + +namespace xe { +namespace gpu { +namespace nop { + + +class NopGraphicsDriver : public GraphicsDriver { +public: + NopGraphicsDriver(xe_memory_ref memory); + virtual ~NopGraphicsDriver(); + + virtual void Initialize(); + + virtual void InvalidateState( + uint32_t mask); + virtual void SetShader( + XE_GPU_SHADER_TYPE type, + uint32_t address, + uint32_t start, + uint32_t size_dwords); + virtual void DrawIndexed( + XE_GPU_PRIMITIVE_TYPE prim_type, + uint32_t index_count); + +protected: +}; + + +} // namespace nop +} // namespace gpu +} // namespace xe + + +#endif // XENIA_GPU_NOP_NOP_GRAPHICS_DRIVER_H_ diff --git a/src/xenia/gpu/nop/nop_graphics_system.cc b/src/xenia/gpu/nop/nop_graphics_system.cc index aa03902d5..010e04067 100644 --- a/src/xenia/gpu/nop/nop_graphics_system.cc +++ b/src/xenia/gpu/nop/nop_graphics_system.cc @@ -10,6 +10,7 @@ #include #include +#include using namespace xe; @@ -42,6 +43,9 @@ NopGraphicsSystem::~NopGraphicsSystem() { } void NopGraphicsSystem::Initialize() { + XEASSERTNULL(driver_); + driver_ = new NopGraphicsDriver(memory_); + XEASSERTNULL(timer_queue_); XEASSERTNULL(vsync_timer_); diff --git a/src/xenia/gpu/nop/sources.gypi b/src/xenia/gpu/nop/sources.gypi index 1cea30b42..1d167f9a4 100644 --- a/src/xenia/gpu/nop/sources.gypi +++ b/src/xenia/gpu/nop/sources.gypi @@ -4,6 +4,8 @@ 'nop-private.h', 'nop.cc', 'nop.h', + 'nop_graphics_driver.cc', + 'nop_graphics_driver.h', 'nop_graphics_system.cc', 'nop_graphics_system.h', ], diff --git a/src/xenia/gpu/ring_buffer_worker.cc b/src/xenia/gpu/ring_buffer_worker.cc index b447a8431..650841350 100644 --- a/src/xenia/gpu/ring_buffer_worker.cc +++ b/src/xenia/gpu/ring_buffer_worker.cc @@ -9,6 +9,7 @@ #include +#include #include #include @@ -19,7 +20,7 @@ using namespace xe::gpu::xenos; RingBufferWorker::RingBufferWorker(xe_memory_ref memory) : - memory_(memory) { + memory_(memory), driver_(0) { running_ = true; write_ptr_index_event_ = CreateEvent( NULL, FALSE, FALSE, NULL); @@ -37,7 +38,9 @@ RingBufferWorker::~RingBufferWorker() { CloseHandle(write_ptr_index_event_); } -void RingBufferWorker::Initialize(uint32_t ptr, uint32_t page_count) { +void RingBufferWorker::Initialize(GraphicsDriver* driver, + uint32_t ptr, uint32_t page_count) { + driver_ = driver; primary_buffer_ptr_ = ptr; primary_buffer_size_ = page_count * 4 * 1024; read_ptr_index_ = 0; @@ -100,6 +103,7 @@ void RingBufferWorker::ThreadStart() { void RingBufferWorker::ExecuteSegment(uint32_t ptr, uint32_t length) { uint8_t* p = xe_memory_addr(memory_); + RegisterFile* regs = driver_->register_file(); // Adjust pointer base. ptr = (primary_buffer_ptr_ & ~0x1FFFFFFF) | (ptr & 0x1FFFFFFF); @@ -138,7 +142,10 @@ void RingBufferWorker::ExecuteSegment(uint32_t ptr, uint32_t length) { const char* reg_name = xenos::GetRegisterName(base_index + m); XELOGGPU(" %.8X -> %.4X %s", reg_data, base_index + m, reg_name ? reg_name : ""); - // TODO(benvanik): process register writes. + // TODO(benvanik): exec write handler (if special). + if (base_index + m < kXEGpuRegisterCount) { + regs->values[base_index + m].u32 = reg_data; + } } n += 1 + count; } @@ -158,7 +165,14 @@ void RingBufferWorker::ExecuteSegment(uint32_t ptr, uint32_t length) { reg_name_1 ? reg_name_1 : ""); XELOGGPU(" %.8X -> %.4X %s", reg_data_2, reg_index_2, reg_name_2 ? reg_name_2 : ""); - // TODO(benvanik): process register writes. + // TODO(benvanik): exec write handler (if special). + if (reg_index_1 < kXEGpuRegisterCount) { + regs->values[reg_index_1].u32 = reg_data_1; + } + if (reg_index_2 < kXEGpuRegisterCount) { + regs->values[reg_index_2].u32 = reg_data_2; + } + n += 1 + 2; } break; @@ -242,56 +256,31 @@ void RingBufferWorker::ExecuteSegment(uint32_t ptr, uint32_t length) { // initiate fetch of index buffer and draw { XELOGGPU("Packet(%.8X): PM4_DRAW_INDX", packet); + LOG_DATA(count); // d0 = viz query info uint32_t d0 = XEGETUINT32BE(packet_base + 1 * 4); uint32_t d1 = XEGETUINT32BE(packet_base + 2 * 4); uint32_t index_count = d1 >> 16; uint32_t prim_type = d1 & 0x3F; // Not sure what the other bits mean - 'SrcSel=AutoIndex'? - const char* prim_type_name = "UNKNOWN"; - switch (prim_type) { - case 1: - prim_type_name = "pointlist"; - break; - case 4: - prim_type_name = "trilist"; - break; - case 8: - prim_type_name = "rectlist"; - break; - default: - XEASSERTALWAYS(); - break; - } - XELOGGPU(" %d indices of %s", index_count, prim_type_name); - LOG_DATA(count); + driver_->DrawIndexed( + (XE_GPU_PRIMITIVE_TYPE)prim_type, + index_count); } break; case PM4_DRAW_INDX_2: // draw using supplied indices in packet { XELOGGPU("Packet(%.8X): PM4_DRAW_INDX_2", packet); + LOG_DATA(count); uint32_t d0 = XEGETUINT32BE(packet_base + 1 * 4); uint32_t index_count = d0 >> 16; uint32_t prim_type = d0 & 0x3F; // Not sure what the other bits mean - 'SrcSel=AutoIndex'? - const char* prim_type_name = "UNKNOWN"; - switch (prim_type) { - case 1: - prim_type_name = "pointlist"; - break; - case 4: - prim_type_name = "trilist"; - break; - case 8: - prim_type_name = "rectlist"; - break; - default: - XEASSERTALWAYS(); - break; - } - XELOGGPU(" %d indices of %s", index_count, prim_type_name); - LOG_DATA(count); + // TODO(benvanik): verify this matches DRAW_INDX + driver_->DrawIndexed( + (XE_GPU_PRIMITIVE_TYPE)prim_type, + index_count); } break; @@ -299,6 +288,7 @@ void RingBufferWorker::ExecuteSegment(uint32_t ptr, uint32_t length) { // load sequencer instruction memory (pointer-based) { XELOGGPU("Packet(%.8X): PM4_IM_LOAD", packet); + LOG_DATA(count); uint32_t addr_type = XEGETUINT32BE(packet_base + 1 * 4); uint32_t type = addr_type & 0x3; uint32_t addr = addr_type & ~0x3; @@ -306,20 +296,11 @@ void RingBufferWorker::ExecuteSegment(uint32_t ptr, uint32_t length) { uint32_t start = start_size >> 16; uint32_t size = start_size & 0xFFFF; // dwords XEASSERT(start == 0); - switch (type) { - case 0: - XELOGGPU(" vertex shader"); - break; - case 1: - XELOGGPU(" pixel shader"); - break; - default: - XEASSERTALWAYS(); - break; - } - XELOGGPU(" %0.8X, %db / %dw", - TRANSLATE_ADDR(addr), size * 4, size); - LOG_DATA(count); + driver_->SetShader( + (XE_GPU_SHADER_TYPE)type, + TRANSLATE_ADDR(addr), + start, + size); } break; case PM4_IM_LOAD_IMMEDIATE: @@ -331,27 +312,23 @@ void RingBufferWorker::ExecuteSegment(uint32_t ptr, uint32_t length) { uint32_t start = start_size >> 16; uint32_t size = start_size & 0xFFFF; // dwords XEASSERT(start == 0); - switch (type) { - case 0: - XELOGGPU(" vertex shader"); - break; - case 1: - XELOGGPU(" pixel shader"); - break; - default: - XEASSERTALWAYS(); - break; - } - XELOGGPU(" %db / %dw", size * 4, size); LOG_DATA(count); + driver_->SetShader( + (XE_GPU_SHADER_TYPE)type, + ptr + n * 4 + 3 * 4, + start, + size); } break; case PM4_INVALIDATE_STATE: // selective invalidation of state pointers - XELOGGPU("Packet(%.8X): PM4_INVALIDATE_STATE", packet); - LOG_DATA(count); - //*cmd++ = 0x00000300; /* 0x100 = Vertex, 0x200 = Pixel */ + { + XELOGGPU("Packet(%.8X): PM4_INVALIDATE_STATE", packet); + LOG_DATA(count); + uint32_t mask = XEGETUINT32BE(packet_base + 1 * 4); + driver_->InvalidateState(mask); + } break; default: diff --git a/src/xenia/gpu/ring_buffer_worker.h b/src/xenia/gpu/ring_buffer_worker.h index 34b3d7a66..d4d19c5a1 100644 --- a/src/xenia/gpu/ring_buffer_worker.h +++ b/src/xenia/gpu/ring_buffer_worker.h @@ -12,10 +12,13 @@ #include +#include + namespace xe { namespace gpu { +class GraphicsDriver; class RingBufferWorker { public: @@ -24,7 +27,8 @@ public: xe_memory_ref memory(); - void Initialize(uint32_t ptr, uint32_t page_count); + void Initialize(GraphicsDriver* driver, + uint32_t ptr, uint32_t page_count); void EnableReadPointerWriteBack(uint32_t ptr, uint32_t block_size); void UpdateWritePointer(uint32_t value); @@ -41,6 +45,8 @@ protected: xe_thread_ref thread_; bool running_; + GraphicsDriver* driver_; + uint32_t primary_buffer_ptr_; uint32_t primary_buffer_size_; diff --git a/src/xenia/gpu/sources.gypi b/src/xenia/gpu/sources.gypi index 323e0b447..554316a0a 100644 --- a/src/xenia/gpu/sources.gypi +++ b/src/xenia/gpu/sources.gypi @@ -5,6 +5,8 @@ 'gpu-private.h', 'gpu.cc', 'gpu.h', + 'graphics_driver.cc', + 'graphics_driver.h', 'graphics_system.cc', 'graphics_system.h', 'ring_buffer_worker.cc', diff --git a/src/xenia/gpu/xenos/registers.h b/src/xenia/gpu/xenos/registers.h index 84d1e0706..39a0d43db 100644 --- a/src/xenia/gpu/xenos/registers.h +++ b/src/xenia/gpu/xenos/registers.h @@ -18,7 +18,7 @@ namespace gpu { namespace xenos { -static const uint32_t kXEGpuRegisterCount = 0x3000; +static const uint32_t kXEGpuRegisterCount = 0x5003; enum Registers { @@ -33,13 +33,13 @@ const char* GetRegisterName(uint32_t index); union RegisterValue { - uint32_t dword_value; - float float_value; + uint32_t u32; + float f32; }; struct RegisterFile { - RegisterValue registers[kXEGpuRegisterCount]; + RegisterValue values[kXEGpuRegisterCount]; };