mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-04-07 22:55:40 +12:00
[GPU] Start implementing commands
This commit is contained in:
parent
fef585ebb3
commit
8692e7fc6b
11 changed files with 132 additions and 21 deletions
|
@ -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
|
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
|
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
|
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
|
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/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/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/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
|
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" FILES ${SOURCE_FILES})
|
||||||
source_group("Source Files\\Core\\Kernel" FILES ${KERNEL_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\\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})
|
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)
|
target_link_libraries(Alber PRIVATE sfml-system sfml-network sfml-graphics sfml-window dynarmic)
|
|
@ -4,7 +4,8 @@
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
#include "cpu.hpp"
|
#include "cpu.hpp"
|
||||||
#include "helpers.hpp"
|
#include "gpu.hpp"
|
||||||
|
#include "memory.hpp"
|
||||||
#include "opengl.hpp"
|
#include "opengl.hpp"
|
||||||
#include "SFML/Window.hpp"
|
#include "SFML/Window.hpp"
|
||||||
#include "SFML/Graphics.hpp"
|
#include "SFML/Graphics.hpp"
|
||||||
|
@ -15,6 +16,7 @@ enum class ROMType {
|
||||||
|
|
||||||
class Emulator {
|
class Emulator {
|
||||||
CPU cpu;
|
CPU cpu;
|
||||||
|
GPU gpu;
|
||||||
Memory memory;
|
Memory memory;
|
||||||
Kernel kernel;
|
Kernel kernel;
|
||||||
|
|
||||||
|
@ -28,7 +30,7 @@ class Emulator {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Emulator() : window(sf::VideoMode(width, height), "Alber", sf::Style::Default, sf::ContextSettings(0, 0, 0, 4, 3)),
|
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();
|
reset();
|
||||||
window.setActive(true);
|
window.setActive(true);
|
||||||
}
|
}
|
||||||
|
|
10
include/gpu.hpp
Normal file
10
include/gpu.hpp
Normal 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();
|
||||||
|
};
|
|
@ -100,7 +100,7 @@ class Kernel {
|
||||||
void waitSynchronization1();
|
void waitSynchronization1();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Kernel(CPU& cpu, Memory& mem);
|
Kernel(CPU& cpu, Memory& mem, GPU& gpu);
|
||||||
void serviceSVC(u32 svc);
|
void serviceSVC(u32 svc);
|
||||||
void reset();
|
void reset();
|
||||||
};
|
};
|
|
@ -1,8 +1,9 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include <cstring>
|
||||||
|
#include "gpu.hpp"
|
||||||
#include "helpers.hpp"
|
#include "helpers.hpp"
|
||||||
#include "kernel_types.hpp"
|
#include "kernel_types.hpp"
|
||||||
#include "memory.hpp"
|
#include "memory.hpp"
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
enum class GPUInterrupt : u8 {
|
enum class GPUInterrupt : u8 {
|
||||||
PSC0 = 0, // Memory fill completed
|
PSC0 = 0, // Memory fill completed
|
||||||
|
@ -17,6 +18,7 @@ enum class GPUInterrupt : u8 {
|
||||||
class GPUService {
|
class GPUService {
|
||||||
Handle handle = KernelHandles::GPU;
|
Handle handle = KernelHandles::GPU;
|
||||||
Memory& mem;
|
Memory& mem;
|
||||||
|
GPU& gpu;
|
||||||
u32& currentPID; // Process ID of the current process
|
u32& currentPID; // Process ID of the current process
|
||||||
u8* sharedMem; // Pointer to GSP shared memory
|
u8* sharedMem; // Pointer to GSP shared memory
|
||||||
|
|
||||||
|
@ -24,16 +26,22 @@ class GPUService {
|
||||||
// This is the PID of that process
|
// This is the PID of that process
|
||||||
u32 privilegedProcess;
|
u32 privilegedProcess;
|
||||||
|
|
||||||
|
void processCommands();
|
||||||
|
|
||||||
// Service commands
|
// Service commands
|
||||||
void acquireRight(u32 messagePointer);
|
void acquireRight(u32 messagePointer);
|
||||||
void flushDataCache(u32 messagePointer);
|
void flushDataCache(u32 messagePointer);
|
||||||
void registerInterruptRelayQueue(u32 messagePointer);
|
void registerInterruptRelayQueue(u32 messagePointer);
|
||||||
void setLCDForceBlack(u32 messagePointer);
|
void setLCDForceBlack(u32 messagePointer);
|
||||||
|
void triggerCmdReqQueue(u32 messagePointer);
|
||||||
void writeHwRegs(u32 messagePointer);
|
void writeHwRegs(u32 messagePointer);
|
||||||
void writeHwRegsWithMask(u32 messagePointer);
|
void writeHwRegsWithMask(u32 messagePointer);
|
||||||
|
|
||||||
|
// GPU commands processed via TriggerCmdReqQueue
|
||||||
|
void memoryFill(u32* cmd);
|
||||||
|
|
||||||
public:
|
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 reset();
|
||||||
void handleSyncRequest(u32 messagePointer);
|
void handleSyncRequest(u32 messagePointer);
|
||||||
void requestInterrupt(GPUInterrupt type);
|
void requestInterrupt(GPUInterrupt type);
|
||||||
|
|
|
@ -23,7 +23,7 @@ class ServiceManager {
|
||||||
void registerClient(u32 messagePointer);
|
void registerClient(u32 messagePointer);
|
||||||
|
|
||||||
public:
|
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 reset();
|
||||||
void handleSyncRequest(u32 messagePointer);
|
void handleSyncRequest(u32 messagePointer);
|
||||||
|
|
||||||
|
|
10
src/core/PICA/gpu.cpp
Normal file
10
src/core/PICA/gpu.cpp
Normal 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);
|
||||||
|
}
|
|
@ -3,8 +3,8 @@
|
||||||
#include "kernel_types.hpp"
|
#include "kernel_types.hpp"
|
||||||
#include "cpu.hpp"
|
#include "cpu.hpp"
|
||||||
|
|
||||||
Kernel::Kernel(CPU& cpu, Memory& mem)
|
Kernel::Kernel(CPU& cpu, Memory& mem, GPU& gpu)
|
||||||
: cpu(cpu), regs(cpu.regs()), mem(mem), handleCounter(0), serviceManager(regs, mem, currentProcess) {
|
: 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
|
objects.reserve(512); // Make room for a few objects to avoid further memory allocs later
|
||||||
portHandles.reserve(32);
|
portHandles.reserve(32);
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,22 @@
|
||||||
#include "services/gsp_gpu.hpp"
|
#include "services/gsp_gpu.hpp"
|
||||||
|
|
||||||
namespace GPUCommands {
|
// Commands used with SendSyncRequest targetted to the GSP::GPU service
|
||||||
|
namespace ServiceCommands {
|
||||||
enum : u32 {
|
enum : u32 {
|
||||||
AcquireRight = 0x00160042,
|
AcquireRight = 0x00160042,
|
||||||
RegisterInterruptRelayQueue = 0x00130042,
|
RegisterInterruptRelayQueue = 0x00130042,
|
||||||
WriteHwRegs = 0x00010082,
|
WriteHwRegs = 0x00010082,
|
||||||
WriteHwRegsWithMask = 0x00020084,
|
WriteHwRegsWithMask = 0x00020084,
|
||||||
FlushDataCache = 0x00080082,
|
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) {
|
void GPUService::handleSyncRequest(u32 messagePointer) {
|
||||||
const u32 command = mem.read32(messagePointer);
|
const u32 command = mem.read32(messagePointer);
|
||||||
switch (command) {
|
switch (command) {
|
||||||
case GPUCommands::AcquireRight: acquireRight(messagePointer); break;
|
case ServiceCommands::AcquireRight: acquireRight(messagePointer); break;
|
||||||
case GPUCommands::FlushDataCache: flushDataCache(messagePointer); break;
|
case ServiceCommands::FlushDataCache: flushDataCache(messagePointer); break;
|
||||||
case GPUCommands::RegisterInterruptRelayQueue: registerInterruptRelayQueue(messagePointer); break;
|
case ServiceCommands::RegisterInterruptRelayQueue: registerInterruptRelayQueue(messagePointer); break;
|
||||||
case GPUCommands::SetLCDForceBlack: setLCDForceBlack(messagePointer); break;
|
case ServiceCommands::SetLCDForceBlack: setLCDForceBlack(messagePointer); break;
|
||||||
case GPUCommands::WriteHwRegs: writeHwRegs(messagePointer); break;
|
case ServiceCommands::TriggerCmdReqQueue: triggerCmdReqQueue(messagePointer); break;
|
||||||
case GPUCommands::WriteHwRegsWithMask: writeHwRegsWithMask(messagePointer); break;
|
case ServiceCommands::WriteHwRegs: writeHwRegs(messagePointer); break;
|
||||||
|
case ServiceCommands::WriteHwRegsWithMask: writeHwRegsWithMask(messagePointer); break;
|
||||||
; default: Helpers::panic("GPU service requested. Command: %08X\n", command);
|
; 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?
|
// What is the "GSP module thread index" meant to be?
|
||||||
// How does the shared memory handle thing work?
|
// How does the shared memory handle thing work?
|
||||||
void GPUService::registerInterruptRelayQueue(u32 messagePointer) {
|
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 flags = mem.read32(messagePointer + 4);
|
||||||
const u32 eventHandle = mem.read32(messagePointer + 12);
|
const u32 eventHandle = mem.read32(messagePointer + 12);
|
||||||
printf("GSP::GPU::RegisterInterruptRelayQueue (flags = %X, event handle = %X)\n", flags, eventHandle);
|
printf("GSP::GPU::RegisterInterruptRelayQueue (flags = %X, event handle = %X)\n", flags, eventHandle);
|
||||||
|
@ -73,7 +88,7 @@ void GPUService::requestInterrupt(GPUInterrupt type) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 index = sharedMem[0];
|
u8 index = sharedMem[0]; // The interrupt block is normally located at sharedMem + processGSPIndex*0x40
|
||||||
u8& interruptCount = sharedMem[1];
|
u8& interruptCount = sharedMem[1];
|
||||||
u8 flagIndex = (index + interruptCount) % 0x34;
|
u8 flagIndex = (index + interruptCount) % 0x34;
|
||||||
interruptCount++;
|
interruptCount++;
|
||||||
|
@ -168,4 +183,64 @@ void GPUService::setLCDForceBlack(u32 messagePointer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
mem.write32(messagePointer + 4, Result::Success);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
#include "services/service_manager.hpp"
|
#include "services/service_manager.hpp"
|
||||||
|
|
||||||
ServiceManager::ServiceManager(std::array<u32, 16>& regs, Memory& mem, u32& currentPID)
|
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, currentPID), gsp_lcd(mem) {}
|
: regs(regs), mem(mem), apt(mem), hid(mem), fs(mem), gsp_gpu(mem, gpu, currentPID), gsp_lcd(mem) {}
|
||||||
|
|
||||||
void ServiceManager::reset() {
|
void ServiceManager::reset() {
|
||||||
apt.reset();
|
apt.reset();
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
#include "emulator.hpp"
|
#include "emulator.hpp"
|
||||||
|
|
||||||
void Emulator::reset() {
|
void Emulator::reset() {
|
||||||
memory.reset();
|
|
||||||
cpu.reset();
|
cpu.reset();
|
||||||
|
gpu.reset();
|
||||||
|
memory.reset();
|
||||||
|
// Kernel must be reset last because it depends on CPU/Memory state
|
||||||
kernel.reset();
|
kernel.reset();
|
||||||
|
|
||||||
// Reloading r13 and r15 needs to happen after everything has been reset
|
// Reloading r13 and r15 needs to happen after everything has been reset
|
||||||
|
|
Loading…
Add table
Reference in a new issue