From 68d5f33cfa5a1fcd78e9531a5c370e3c7c465abd Mon Sep 17 00:00:00 2001 From: Ben Vanik Date: Sat, 19 Oct 2013 16:29:00 -0700 Subject: [PATCH] GPU byte swapping. A lot of other packets likely do this. --- src/xenia/byte_order.h | 8 ++++++++ src/xenia/gpu/graphics_system.cc | 2 +- src/xenia/gpu/ring_buffer_worker.cc | 11 ++++------- src/xenia/gpu/xenos/xenos.h | 16 ++++++++++++++++ 4 files changed, 29 insertions(+), 8 deletions(-) diff --git a/src/xenia/byte_order.h b/src/xenia/byte_order.h index cfd08a135..b84044762 100644 --- a/src/xenia/byte_order.h +++ b/src/xenia/byte_order.h @@ -97,6 +97,14 @@ XEFORCEINLINE double XESWAPF64BE(double value) { #define XESETUINT32BE(p, v) (*((uint32_t*)(p)) = XESWAP32BE((uint32_t)v)) #define XESETINT64BE(p, v) (*( (int64_t*)(p)) = XESWAP64BE( (int64_t)v)) #define XESETUINT64BE(p, v) (*((uint64_t*)(p)) = XESWAP64BE((uint64_t)v)) +#define XESETINT8LE(p, v) (*( (int8_t*)(p)) = (int8_t)v) +#define XESETUINT8LE(p, v) (*( (uint8_t*)(p)) = (uint8_t)v) +#define XESETINT16LE(p, v) (*( (int16_t*)(p)) = (int16_t)v) +#define XESETUINT16LE(p, v) (*((uint16_t*)(p)) = (uint16_t)v) +#define XESETINT32LE(p, v) (*( (int32_t*)(p)) = (int32_t)v) +#define XESETUINT32LE(p, v) (*((uint32_t*)(p)) = (uint32_t)v) +#define XESETINT64LE(p, v) (*( (int64_t*)(p)) = (int64_t)v) +#define XESETUINT64LE(p, v) (*((uint64_t*)(p)) = (uint64_t)v) #endif // XENIA_BYTE_ORDER_H_ diff --git a/src/xenia/gpu/graphics_system.cc b/src/xenia/gpu/graphics_system.cc index a3787eb31..95837681a 100644 --- a/src/xenia/gpu/graphics_system.cc +++ b/src/xenia/gpu/graphics_system.cc @@ -161,7 +161,7 @@ void GraphicsSystem::WriteRegister(uint32_t r, uint64_t value) { } void GraphicsSystem::DispatchInterruptCallback( - uint32_t source, uint32_t cpu) { + uint32_t source, uint32_t cpu) { // Pick a CPU, if needed. We're going to guess 2. Because. if (cpu == 0xFFFFFFFF) { cpu = 2; diff --git a/src/xenia/gpu/ring_buffer_worker.cc b/src/xenia/gpu/ring_buffer_worker.cc index 5f7c6e19a..052ed1492 100644 --- a/src/xenia/gpu/ring_buffer_worker.cc +++ b/src/xenia/gpu/ring_buffer_worker.cc @@ -483,13 +483,10 @@ uint32_t RingBufferWorker::ExecutePacket(PacketArgs& args) { // Write value. data_value = value; } - if (!(address & 0xC0000000)) { - XESETUINT32BE(p + TRANSLATE_ADDR(address), data_value); - } else { - // TODO(benvanik): read up on PM4_EVENT_WRITE_SHD. - // No clue. Maybe relative write based on a register base? - XELOGE("UNKNOWN FORM OF PM4_EVENT_WRITE_SHD"); - } + uint32_t endianness = address >> 29; + address &= ~0xC0000000; + data_value = GpuSwap(data_value, endianness); + XESETUINT32BE(p + TRANSLATE_ADDR(address), data_value); } break; diff --git a/src/xenia/gpu/xenos/xenos.h b/src/xenia/gpu/xenos/xenos.h index 0df141a03..dc3793754 100644 --- a/src/xenia/gpu/xenos/xenos.h +++ b/src/xenia/gpu/xenos/xenos.h @@ -42,6 +42,22 @@ typedef enum { XE_GPU_PRIMITIVE_TYPE_LINE_LOOP = 0x0C, } XE_GPU_PRIMITIVE_TYPE; +XEFORCEINLINE uint32_t GpuSwap(uint32_t value, uint32_t endianness) { + switch (endianness) { + default: + case 0x0: // No swap. + return value; + case 0x1: // Swap bytes in half words. + return ((value << 8) & 0xFF00FF00) | + ((value >> 8) & 0x00FF00FF); + case 0x2: // Swap bytes. + // NOTE: we are likely doing two swaps here. Wasteful. Oh well. + return XESWAP32(value); + case 0x3: // Swap half words. + return ((value >> 16) & 0xFFFF) | (value << 16); + } +} + // XE_GPU_REG_SQ_PROGRAM_CNTL typedef union { XEPACKEDSTRUCTANONYMOUS({