diff --git a/src/core/PICA/gpu.cpp b/src/core/PICA/gpu.cpp index adec82da..10d6b80b 100644 --- a/src/core/PICA/gpu.cpp +++ b/src/core/PICA/gpu.cpp @@ -224,21 +224,34 @@ Vertex GPU::getImmediateModeVertex() { return v; } void GPU::fireDMA(u32 dest, u32 source, u32 size) { + log("[GPU] DMA of %08X bytes from %08X to %08X\n", size, source, dest); constexpr u32 vramStart = VirtualAddrs::VramStart; constexpr u32 vramSize = VirtualAddrs::VramSize; const u32 fcramStart = mem.getLinearHeapVaddr(); constexpr u32 fcramSize = VirtualAddrs::FcramTotalSize; + // Shows whether this transfer is an FCRAM->VRAM transfer that's trivially optimizable + bool cpuToVRAM = true; + if (dest - vramStart >= vramSize || size > (vramSize - (dest - vramStart))) [[unlikely]] { Helpers::panic("GPU DMA does not target VRAM"); } - if (source - fcramStart >= fcramSize || size > (fcramSize - (dest - fcramStart))) { - Helpers::panic("GPU DMA does not have FCRAM as its source"); + if (source - fcramStart >= fcramSize || size > (fcramSize - (dest - fcramStart))) [[unlikely]] { + cpuToVRAM = false; + // Helpers::panic("GPU DMA does not have FCRAM as its source"); } - // Valid, optimized FCRAM->VRAM DMA. TODO: Is VRAM->VRAM DMA allowed? - u8* fcram = mem.getFCRAM(); - std::memcpy(&vram[dest - vramStart], &fcram[source - fcramStart], size); + if (cpuToVRAM) [[likely]] { + // Valid, optimized FCRAM->VRAM DMA. TODO: Is VRAM->VRAM DMA allowed? + u8* fcram = mem.getFCRAM(); + std::memcpy(&vram[dest - vramStart], &fcram[source - fcramStart], size); + } else { + printf("Non-trivially optimizable GPU DMA. Falling back to byte-by-byte transfer"); + + for (u32 i = 0; i < size; i++) { + mem.write8(dest + i, mem.read8(source + i)); + } + } }