[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

@ -53,6 +53,7 @@ set(KERNEL_SOURCE_FILES src/core/kernel/kernel.cpp src/core/kernel/resource_limi
set(SERVICE_SOURCE_FILES src/core/services/service_manager.cpp src/core/services/apt.cpp src/core/services/hid.cpp
src/core/services/fs.cpp src/core/services/gsp_gpu.cpp src/core/services/gsp_lcd.cpp
)
set(PICA_SOURCE_FILES src/core/PICA/gpu.cpp)
set(HEADER_FILES include/emulator.hpp include/helpers.hpp include/opengl.hpp include/termcolor.hpp
include/cpu.hpp include/cpu_dynarmic.hpp include/memory.hpp include/kernel/kernel.hpp
@ -60,6 +61,7 @@ set(HEADER_FILES include/emulator.hpp include/helpers.hpp include/opengl.hpp inc
include/kernel/config_mem.hpp include/services/service_manager.hpp include/services/apt.hpp
include/kernel/handles.hpp include/services/hid.hpp include/services/fs.hpp
include/services/gsp_gpu.hpp include/services/gsp_lcd.hpp include/arm_defs.hpp
include/gpu.hpp
)
set(THIRD_PARTY_SOURCE_FILES third_party/imgui/imgui.cpp
@ -75,7 +77,9 @@ source_group("Header Files\\Core" FILES ${HEADER_FILES})
source_group("Source Files\\Core" FILES ${SOURCE_FILES})
source_group("Source Files\\Core\\Kernel" FILES ${KERNEL_SOURCE_FILES})
source_group("Source Files\\Core\\Services" FILES ${SERVICE_SOURCE_FILES})
source_group("Source Files\\Core\\PICA" FILES ${PICA_SOURCE_FILES})
source_group("Source Files\\Third Party" FILES ${THIRD_PARTY_SOURCE_FILES})
add_executable(Alber ${SOURCE_FILES} ${KERNEL_SOURCE_FILES} ${SERVICE_SOURCE_FILES} ${THIRD_PARTY_SOURCE_FILES} ${HEADER_FILES})
add_executable(Alber ${SOURCE_FILES} ${KERNEL_SOURCE_FILES} ${SERVICE_SOURCE_FILES} ${PICA_SOURCE_FILES}
${THIRD_PARTY_SOURCE_FILES} ${HEADER_FILES})
target_link_libraries(Alber PRIVATE sfml-system sfml-network sfml-graphics sfml-window dynarmic)

View file

@ -4,7 +4,8 @@
#include <fstream>
#include "cpu.hpp"
#include "helpers.hpp"
#include "gpu.hpp"
#include "memory.hpp"
#include "opengl.hpp"
#include "SFML/Window.hpp"
#include "SFML/Graphics.hpp"
@ -15,6 +16,7 @@ enum class ROMType {
class Emulator {
CPU cpu;
GPU gpu;
Memory memory;
Kernel kernel;
@ -28,7 +30,7 @@ class Emulator {
public:
Emulator() : window(sf::VideoMode(width, height), "Alber", sf::Style::Default, sf::ContextSettings(0, 0, 0, 4, 3)),
kernel(cpu, memory), cpu(memory, kernel) {
kernel(cpu, memory, gpu), cpu(memory, kernel) {
reset();
window.setActive(true);
}

10
include/gpu.hpp Normal file
View file

@ -0,0 +1,10 @@
#pragma once
#include "helpers.hpp"
class GPU {
public:
GPU() {}
void clearBuffer(u32 startAddress, u32 endAddress, u32 value, u32 control);
void reset();
};

View file

@ -100,7 +100,7 @@ class Kernel {
void waitSynchronization1();
public:
Kernel(CPU& cpu, Memory& mem);
Kernel(CPU& cpu, Memory& mem, GPU& gpu);
void serviceSVC(u32 svc);
void reset();
};

View file

@ -1,8 +1,9 @@
#pragma once
#include <cstring>
#include "gpu.hpp"
#include "helpers.hpp"
#include "kernel_types.hpp"
#include "memory.hpp"
#include <cstring>
enum class GPUInterrupt : u8 {
PSC0 = 0, // Memory fill completed
@ -17,6 +18,7 @@ enum class GPUInterrupt : u8 {
class GPUService {
Handle handle = KernelHandles::GPU;
Memory& mem;
GPU& gpu;
u32& currentPID; // Process ID of the current process
u8* sharedMem; // Pointer to GSP shared memory
@ -24,16 +26,22 @@ class GPUService {
// This is the PID of that process
u32 privilegedProcess;
void processCommands();
// Service commands
void acquireRight(u32 messagePointer);
void flushDataCache(u32 messagePointer);
void registerInterruptRelayQueue(u32 messagePointer);
void setLCDForceBlack(u32 messagePointer);
void triggerCmdReqQueue(u32 messagePointer);
void writeHwRegs(u32 messagePointer);
void writeHwRegsWithMask(u32 messagePointer);
// GPU commands processed via TriggerCmdReqQueue
void memoryFill(u32* cmd);
public:
GPUService(Memory& mem, u32& currentPID) : mem(mem), currentPID(currentPID) {}
GPUService(Memory& mem, GPU& gpu, u32& currentPID) : mem(mem), gpu(gpu), currentPID(currentPID) {}
void reset();
void handleSyncRequest(u32 messagePointer);
void requestInterrupt(GPUInterrupt type);

View file

@ -23,7 +23,7 @@ class ServiceManager {
void registerClient(u32 messagePointer);
public:
ServiceManager(std::array<u32, 16>& regs, Memory& mem, u32& currentPID);
ServiceManager(std::array<u32, 16>& regs, Memory& mem, GPU& gpu, u32& currentPID);
void reset();
void handleSyncRequest(u32 messagePointer);

10
src/core/PICA/gpu.cpp Normal file
View file

@ -0,0 +1,10 @@
#include "gpu.hpp"
#include <cstdio>
void GPU::reset() {
}
void GPU::clearBuffer(u32 startAddress, u32 endAddress, u32 value, u32 control) {
printf("GPU: Clear buffer\nStart: %08X End: %08X\nValue: %08X Control: %08X\n", startAddress, endAddress, value, control);
}

View file

@ -3,8 +3,8 @@
#include "kernel_types.hpp"
#include "cpu.hpp"
Kernel::Kernel(CPU& cpu, Memory& mem)
: cpu(cpu), regs(cpu.regs()), mem(mem), handleCounter(0), serviceManager(regs, mem, currentProcess) {
Kernel::Kernel(CPU& cpu, Memory& mem, GPU& gpu)
: cpu(cpu), regs(cpu.regs()), mem(mem), handleCounter(0), serviceManager(regs, mem, gpu, currentProcess) {
objects.reserve(512); // Make room for a few objects to avoid further memory allocs later
portHandles.reserve(32);

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);
}
}

View file

@ -1,7 +1,7 @@
#include "services/service_manager.hpp"
ServiceManager::ServiceManager(std::array<u32, 16>& regs, Memory& mem, u32& currentPID)
: regs(regs), mem(mem), apt(mem), hid(mem), fs(mem), gsp_gpu(mem, currentPID), gsp_lcd(mem) {}
ServiceManager::ServiceManager(std::array<u32, 16>& regs, Memory& mem, GPU& gpu, u32& currentPID)
: regs(regs), mem(mem), apt(mem), hid(mem), fs(mem), gsp_gpu(mem, gpu, currentPID), gsp_lcd(mem) {}
void ServiceManager::reset() {
apt.reset();

View file

@ -1,8 +1,10 @@
#include "emulator.hpp"
void Emulator::reset() {
memory.reset();
cpu.reset();
gpu.reset();
memory.reset();
// Kernel must be reset last because it depends on CPU/Memory state
kernel.reset();
// Reloading r13 and r15 needs to happen after everything has been reset