[GPU] Start implementing commands

This commit is contained in:
wheremyfoodat 2022-09-21 03:15:43 +03:00
parent fef585ebb3
commit 8692e7fc6b
11 changed files with 132 additions and 21 deletions

View file

@ -1,13 +1,22 @@
#include "services/gsp_gpu.hpp"
namespace GPUCommands {
// Commands used with SendSyncRequest targetted to the GSP::GPU service
namespace ServiceCommands {
enum : u32 {
AcquireRight = 0x00160042,
RegisterInterruptRelayQueue = 0x00130042,
WriteHwRegs = 0x00010082,
WriteHwRegsWithMask = 0x00020084,
FlushDataCache = 0x00080082,
SetLCDForceBlack = 0x000B0040
SetLCDForceBlack = 0x000B0040,
TriggerCmdReqQueue = 0x000C0000
};
}
// Commands written to shared memory and processed by TriggerCmdReqQueue
namespace GPUCommands {
enum : u32 {
MemoryFill = 2
};
}
@ -26,12 +35,13 @@ void GPUService::reset() {
void GPUService::handleSyncRequest(u32 messagePointer) {
const u32 command = mem.read32(messagePointer);
switch (command) {
case GPUCommands::AcquireRight: acquireRight(messagePointer); break;
case GPUCommands::FlushDataCache: flushDataCache(messagePointer); break;
case GPUCommands::RegisterInterruptRelayQueue: registerInterruptRelayQueue(messagePointer); break;
case GPUCommands::SetLCDForceBlack: setLCDForceBlack(messagePointer); break;
case GPUCommands::WriteHwRegs: writeHwRegs(messagePointer); break;
case GPUCommands::WriteHwRegsWithMask: writeHwRegsWithMask(messagePointer); break;
case ServiceCommands::AcquireRight: acquireRight(messagePointer); break;
case ServiceCommands::FlushDataCache: flushDataCache(messagePointer); break;
case ServiceCommands::RegisterInterruptRelayQueue: registerInterruptRelayQueue(messagePointer); break;
case ServiceCommands::SetLCDForceBlack: setLCDForceBlack(messagePointer); break;
case ServiceCommands::TriggerCmdReqQueue: triggerCmdReqQueue(messagePointer); break;
case ServiceCommands::WriteHwRegs: writeHwRegs(messagePointer); break;
case ServiceCommands::WriteHwRegsWithMask: writeHwRegsWithMask(messagePointer); break;
; default: Helpers::panic("GPU service requested. Command: %08X\n", command);
}
}
@ -58,6 +68,11 @@ void GPUService::acquireRight(u32 messagePointer) {
// What is the "GSP module thread index" meant to be?
// How does the shared memory handle thing work?
void GPUService::registerInterruptRelayQueue(u32 messagePointer) {
// Detect if this function is called a 2nd time because we'll likely need to impl threads properly for the GSP
static bool beenHere = false;
if (beenHere) Helpers::panic("RegisterInterruptRelayQueue called a second time. Need to implement GSP threads properly");
beenHere = true;
const u32 flags = mem.read32(messagePointer + 4);
const u32 eventHandle = mem.read32(messagePointer + 12);
printf("GSP::GPU::RegisterInterruptRelayQueue (flags = %X, event handle = %X)\n", flags, eventHandle);
@ -73,7 +88,7 @@ void GPUService::requestInterrupt(GPUInterrupt type) {
return;
}
u8 index = sharedMem[0];
u8 index = sharedMem[0]; // The interrupt block is normally located at sharedMem + processGSPIndex*0x40
u8& interruptCount = sharedMem[1];
u8 flagIndex = (index + interruptCount) % 0x34;
interruptCount++;
@ -168,4 +183,64 @@ void GPUService::setLCDForceBlack(u32 messagePointer) {
}
mem.write32(messagePointer + 4, Result::Success);
}
void GPUService::triggerCmdReqQueue(u32 messagePointer) {
processCommands();
mem.write32(messagePointer + 4, Result::Success);
}
#include <chrono>
#include <thread>
using namespace std::chrono_literals;
void GPUService::processCommands() {
if (sharedMem == nullptr) [[unlikely]] { // Shared memory hasn't been set up yet
return;
}
constexpr int threadCount = 1; // TODO: More than 1 thread can have GSP commands at a time
for (int t = 0; t < threadCount; t++) {
u8* cmdBuffer = &sharedMem[0x800 + t * 0x200];
u8& commandsLeft = cmdBuffer[1];
// Commands start at byte 0x20 of the command buffer, each being 0x20 bytes long
u32* cmd = reinterpret_cast<u32*>(&cmdBuffer[0x20]);
printf("Processing %d GPU commands\n", commandsLeft);
std::this_thread::sleep_for(1000ms);
while (commandsLeft != 0) {
u32 cmdID = cmd[0] & 0xff;
switch (cmdID) {
case GPUCommands::MemoryFill: memoryFill(cmd); break;
default: Helpers::panic("GSP::GPU::ProcessCommands: Unknown cmd ID %d", cmdID);
}
commandsLeft--;
}
}
}
// Fill 2 GPU framebuffers, buf0 and buf1, using a specific word value
void GPUService::memoryFill(u32* cmd) {
u32 control = cmd[7];
// buf0 parameters
u32 start0 = cmd[1]; // Start address for the fill. If 0, don't fill anything
u32 value0 = cmd[2]; // Value to fill the framebuffer with
u32 end0 = cmd[3]; // End address for the fill
u32 control0 = control & 0xffff;
// buf1 parameters
u32 start1 = cmd[4];
u32 value1 = cmd[5];
u32 end1 = cmd[6];
u32 control1 = control >> 16;
if (start0 != 0) {
gpu.clearBuffer(start0, end0, value0, control0);
}
if (start1 != 0) {
gpu.clearBuffer(start1, end1, value1, control1);
}
}