This commit is contained in:
wheremyfoodat 2022-09-24 02:45:57 +03:00
parent 75070ca6ef
commit be4fae5104
33 changed files with 341 additions and 70 deletions

View file

@ -55,7 +55,7 @@ set(SERVICE_SOURCE_FILES src/core/services/service_manager.cpp src/core/services
src/core/services/ndm.cpp src/core/services/ndm.cpp
) )
set(PICA_SOURCE_FILES src/core/PICA/gpu.cpp src/core/PICA/regs.cpp src/core/PICA/shader_unit.cpp set(PICA_SOURCE_FILES src/core/PICA/gpu.cpp src/core/PICA/regs.cpp src/core/PICA/shader_unit.cpp
src/core/PICA/shader_interpreter.cpp src/core/PICA/shader_interpreter.cpp src/core/PICA/renderer_opengl.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
@ -66,6 +66,7 @@ set(HEADER_FILES include/emulator.hpp include/helpers.hpp include/opengl.hpp inc
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/PICA/gpu.hpp include/PICA/regs.hpp include/services/ndm.hpp include/PICA/gpu.hpp include/PICA/regs.hpp include/services/ndm.hpp
include/PICA/shader.hpp include/PICA/shader_unit.hpp include/PICA/float_types.hpp include/PICA/shader.hpp include/PICA/shader_unit.hpp include/PICA/float_types.hpp
include/logger.hpp
) )
set(THIRD_PARTY_SOURCE_FILES third_party/imgui/imgui.cpp set(THIRD_PARTY_SOURCE_FILES third_party/imgui/imgui.cpp

View file

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <array> #include <array>
#include "helpers.hpp" #include "helpers.hpp"
#include "logger.hpp"
#include "memory.hpp" #include "memory.hpp"
#include "opengl.hpp" #include "opengl.hpp"
#include "PICA/float_types.hpp" #include "PICA/float_types.hpp"
@ -12,12 +13,18 @@ class GPU {
Memory& mem; Memory& mem;
ShaderUnit shaderUnit; ShaderUnit shaderUnit;
u8* vram = nullptr; u8* vram = nullptr;
MAKE_LOG_FUNCTION(log, gpuLogger)
static constexpr u32 maxAttribCount = 12; // Up to 12 vertex attributes static constexpr u32 maxAttribCount = 12; // Up to 12 vertex attributes
static constexpr u32 regNum = 0x300; static constexpr u32 regNum = 0x300;
static constexpr u32 vramSize = 6_MB; static constexpr u32 vramSize = 6_MB;
std::array<u32, regNum> regs; // GPU internal registers std::array<u32, regNum> regs; // GPU internal registers
struct Vertex {
OpenGL::vec4 position;
OpenGL::vec4 colour;
};
// Read a value of type T from physical address paddr // Read a value of type T from physical address paddr
// This is necessary because vertex attribute fetching uses physical addresses // This is necessary because vertex attribute fetching uses physical addresses
template<typename T> template<typename T>
@ -71,8 +78,27 @@ class GPU {
u32 fixedAttribCount = 0; // How many attribute components have we written? When we get to 4 the attr will actually get submitted u32 fixedAttribCount = 0; // How many attribute components have we written? When we get to 4 the attr will actually get submitted
std::array<u32, 3> fixedAttrBuff; // Buffer to hold fixed attributes in until they get submitted std::array<u32, 3> fixedAttrBuff; // Buffer to hold fixed attributes in until they get submitted
OpenGL::Framebuffer fbo;
OpenGL::Texture fboTexture;
OpenGL::Program triangleProgram;
OpenGL::Program displayProgram;
OpenGL::VertexArray vao;
OpenGL::VertexBuffer vbo;
// Dummy VAO/VBO for blitting the final output
OpenGL::VertexArray dummyVAO;
OpenGL::VertexBuffer dummyVBO;
static constexpr u32 vertexBufferSize = 0x1000;
void drawVertices(OpenGL::Primitives primType, Vertex* vertices, u32 count);
public: public:
GPU(Memory& mem); GPU(Memory& mem);
void initGraphicsContext(); // Initialize graphics context
void getGraphicsContext(); // Set up the graphics context for rendering
void display(); // Display the screen contents onto our window
void clearBuffer(u32 startAddress, u32 endAddress, u32 value, u32 control); void clearBuffer(u32 startAddress, u32 endAddress, u32 value, u32 control);
void reset(); void reset();

View file

@ -47,6 +47,8 @@ namespace PICAInternalRegs {
FixedAttribData1 = 0x234, FixedAttribData1 = 0x234,
FixedAttribData2 = 0x235, FixedAttribData2 = 0x235,
PrimitiveConfig = 0x25E,
// Vertex shader registers // Vertex shader registers
VertexShaderTransferEnd = 0x2BF, VertexShaderTransferEnd = 0x2BF,
VertexFloatUniformIndex = 0x2C0, VertexFloatUniformIndex = 0x2C0,

View file

@ -158,6 +158,8 @@ public:
void runFrame() { void runFrame() {
env.ticksLeft = 268111856 / 60; env.ticksLeft = 268111856 / 60;
const auto exitReason = jit->Run(); const auto exitReason = jit->Run();
Helpers::panic("Exit reason: %d\nPC: %08X", (u32)exitReason, getReg(15)); if (static_cast<u32>(exitReason) != 0) [[unlikely]] {
Helpers::panic("Exit reason: %d\nPC: %08X", static_cast<u32>(exitReason), getReg(15));
}
} }
}; };

View file

@ -43,4 +43,5 @@ public:
bool loadELF(std::filesystem::path& path); bool loadELF(std::filesystem::path& path);
bool loadELF(std::ifstream& file); bool loadELF(std::ifstream& file);
void initGraphicsContext() { gpu.initGraphicsContext(); }
}; };

View file

@ -5,6 +5,7 @@
#include <vector> #include <vector>
#include "kernel_types.hpp" #include "kernel_types.hpp"
#include "helpers.hpp" #include "helpers.hpp"
#include "logger.hpp"
#include "memory.hpp" #include "memory.hpp"
#include "resource_limits.hpp" #include "resource_limits.hpp"
#include "services/service_manager.hpp" #include "services/service_manager.hpp"
@ -58,7 +59,7 @@ class Kernel {
} }
objects.push_back(KernelObject(handleCounter, type)); objects.push_back(KernelObject(handleCounter, type));
printf("Created %s object with handle %d\n", kernelObjectTypeToString(type), handleCounter); log("Created %s object with handle %d\n", kernelObjectTypeToString(type), handleCounter);
return handleCounter++; return handleCounter++;
} }
@ -83,6 +84,9 @@ class Kernel {
std::string getProcessName(u32 pid); std::string getProcessName(u32 pid);
const char* resetTypeToString(u32 type); const char* resetTypeToString(u32 type);
MAKE_LOG_FUNCTION(log, kernelLogger)
MAKE_LOG_FUNCTION(logSVC, svcLogger)
// SVC implementations // SVC implementations
void arbitrateAddress(); void arbitrateAddress();
void clearEvent(); void clearEvent();
@ -110,4 +114,6 @@ public:
void setVersion(u8 major, u8 minor); void setVersion(u8 major, u8 minor);
void serviceSVC(u32 svc); void serviceSVC(u32 svc);
void reset(); void reset();
void sendGPUInterrupt(GPUInterrupt type) { serviceManager.requestGPUInterrupt(type); }
}; };

39
include/logger.hpp Normal file
View file

@ -0,0 +1,39 @@
#pragma once
#include <cstdarg>
#include <fstream>
namespace Log {
// Our logger class
template <bool enabled>
class Logger {
public:
void log(const char* fmt, ...) {
if constexpr (!enabled) return;
std::va_list args;
va_start(args, fmt);
std::vprintf(fmt, args);
va_end(args);
}
};
// Our loggers here. Enable/disable by toggling the template param
static Logger<false> kernelLogger;
static Logger<false> svcLogger;
static Logger<false> gpuLogger;
// Service loggers
static Logger<false> aptLogger;
static Logger<false> fsLogger;
static Logger<false> hidLogger;
static Logger<false> gspGPULogger;
static Logger<false> gspLCDLogger;
static Logger<false> ndmLogger;
static Logger<false> srvLogger;
#define MAKE_LOG_FUNCTION(functionName, logger) \
template <typename... Args> \
void functionName(const char* fmt, Args... args) { \
Log::logger.log(fmt, args...); \
}
}

View file

@ -57,7 +57,7 @@ namespace OpenGL {
void bind() { glBindVertexArray(m_handle); } void bind() { glBindVertexArray(m_handle); }
template <typename T> template <typename T>
void setAttributeFloat(GLuint index, GLint size, GLsizei stride, const void* offset, bool normalized = false) { void setAttributeFloat(GLuint index, GLint size, GLsizei stride, const void* offset, bool normalized = GL_FALSE) {
if constexpr (std::is_same<T, GLfloat>()) { if constexpr (std::is_same<T, GLfloat>()) {
glVertexAttribPointer(index, size, GL_FLOAT, normalized, stride, offset); glVertexAttribPointer(index, size, GL_FLOAT, normalized, stride, offset);
} }

View file

@ -1,11 +1,13 @@
#pragma once #pragma once
#include "helpers.hpp" #include "helpers.hpp"
#include "kernel_types.hpp" #include "kernel_types.hpp"
#include "logger.hpp"
#include "memory.hpp" #include "memory.hpp"
class APTService { class APTService {
Handle handle = KernelHandles::APT; Handle handle = KernelHandles::APT;
Memory& mem; Memory& mem;
MAKE_LOG_FUNCTION(log, aptLogger)
// Service commands // Service commands
void getLockHandle(u32 messagePointer); void getLockHandle(u32 messagePointer);

View file

@ -1,11 +1,13 @@
#pragma once #pragma once
#include "helpers.hpp" #include "helpers.hpp"
#include "kernel_types.hpp" #include "kernel_types.hpp"
#include "logger.hpp"
#include "memory.hpp" #include "memory.hpp"
class FSService { class FSService {
Handle handle = KernelHandles::FS; Handle handle = KernelHandles::FS;
Memory& mem; Memory& mem;
MAKE_LOG_FUNCTION(log, fsLogger)
// Service commands // Service commands
void initialize(u32 messagePointer); void initialize(u32 messagePointer);

View file

@ -3,6 +3,7 @@
#include "PICA/gpu.hpp" #include "PICA/gpu.hpp"
#include "helpers.hpp" #include "helpers.hpp"
#include "kernel_types.hpp" #include "kernel_types.hpp"
#include "logger.hpp"
#include "memory.hpp" #include "memory.hpp"
enum class GPUInterrupt : u8 { enum class GPUInterrupt : u8 {
@ -26,6 +27,7 @@ class GPUService {
// This is the PID of that process // This is the PID of that process
u32 privilegedProcess; u32 privilegedProcess;
MAKE_LOG_FUNCTION(log, gspGPULogger)
void processCommandBuffer(); void processCommandBuffer();
// Service commands // Service commands
@ -40,6 +42,7 @@ class GPUService {
// GSP commands processed via TriggerCmdReqQueue // GSP commands processed via TriggerCmdReqQueue
void processCommandList(u32* cmd); void processCommandList(u32* cmd);
void memoryFill(u32* cmd); void memoryFill(u32* cmd);
void triggerDisplayTransfer(u32* cmd);
public: public:
GPUService(Memory& mem, GPU& gpu, u32& currentPID) : mem(mem), gpu(gpu), currentPID(currentPID) {} GPUService(Memory& mem, GPU& gpu, u32& currentPID) : mem(mem), gpu(gpu), currentPID(currentPID) {}

View file

@ -1,11 +1,13 @@
#pragma once #pragma once
#include "helpers.hpp" #include "helpers.hpp"
#include "kernel_types.hpp" #include "kernel_types.hpp"
#include "logger.hpp"
#include "memory.hpp" #include "memory.hpp"
class LCDService { class LCDService {
Handle handle = KernelHandles::LCD; Handle handle = KernelHandles::LCD;
Memory& mem; Memory& mem;
MAKE_LOG_FUNCTION(log, gspLCDLogger)
// Service commands // Service commands

View file

@ -1,11 +1,13 @@
#pragma once #pragma once
#include "helpers.hpp" #include "helpers.hpp"
#include "kernel_types.hpp" #include "kernel_types.hpp"
#include "logger.hpp"
#include "memory.hpp" #include "memory.hpp"
class HIDService { class HIDService {
Handle handle = KernelHandles::HID; Handle handle = KernelHandles::HID;
Memory& mem; Memory& mem;
MAKE_LOG_FUNCTION(log, hidLogger)
// Service commands // Service commands
void getIPCHandles(u32 messagePointer); void getIPCHandles(u32 messagePointer);

View file

@ -1,11 +1,13 @@
#pragma once #pragma once
#include "helpers.hpp" #include "helpers.hpp"
#include "kernel_types.hpp" #include "kernel_types.hpp"
#include "logger.hpp"
#include "memory.hpp" #include "memory.hpp"
class NDMService { class NDMService {
Handle handle = KernelHandles::NDM; Handle handle = KernelHandles::NDM;
Memory& mem; Memory& mem;
MAKE_LOG_FUNCTION(log, ndmLogger)
// Service commands // Service commands
void overrideDefaultDaemons(u32 messagePointer); void overrideDefaultDaemons(u32 messagePointer);

View file

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <array> #include <array>
#include "helpers.hpp" #include "helpers.hpp"
#include "logger.hpp"
#include "memory.hpp" #include "memory.hpp"
#include "services/apt.hpp" #include "services/apt.hpp"
#include "services/hid.hpp" #include "services/hid.hpp"
@ -12,6 +13,7 @@
class ServiceManager { class ServiceManager {
std::array<u32, 16>& regs; std::array<u32, 16>& regs;
Memory& mem; Memory& mem;
MAKE_LOG_FUNCTION(log, srvLogger)
APTService apt; APTService apt;
HIDService hid; HIDService hid;

View file

@ -30,10 +30,6 @@ void GPU::reset() {
// TODO: Reset blending, texturing, etc here // TODO: Reset blending, texturing, etc here
} }
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);
}
void GPU::drawArrays(bool indexed) { void GPU::drawArrays(bool indexed) {
if (indexed) if (indexed)
drawArrays<true>(); drawArrays<true>();
@ -48,13 +44,22 @@ void GPU::drawArrays() {
const u32 vertexBase = ((regs[PICAInternalRegs::VertexAttribLoc] >> 1) & 0xfffffff) * 16; const u32 vertexBase = ((regs[PICAInternalRegs::VertexAttribLoc] >> 1) & 0xfffffff) * 16;
const u32 vertexCount = regs[PICAInternalRegs::VertexCountReg]; // Total # of vertices to transfer const u32 vertexCount = regs[PICAInternalRegs::VertexCountReg]; // Total # of vertices to transfer
// Configures the type of primitive and the number of vertex shader outputs
const u32 primConfig = regs[PICAInternalRegs::PrimitiveConfig];
const u32 primType = (primConfig >> 8) & 3;
if (primType != 0) Helpers::panic("[PICA] Tried to draw non-triangle shape %d\n", primType);
if (vertexCount % 3) Helpers::panic("[PICA] Vertex count not a multiple of 3");
if (vertexCount > vertexBufferSize) Helpers::panic("[PICA] vertexCount > vertexBufferSize");
Vertex vertices[vertexBufferSize];
// Stuff the global attribute config registers in one u64 to make attr parsing easier // Stuff the global attribute config registers in one u64 to make attr parsing easier
// TODO: Cache this when the vertex attribute format registers are written to // TODO: Cache this when the vertex attribute format registers are written to
u64 vertexCfg = u64(regs[PICAInternalRegs::AttribFormatLow]) | (u64(regs[PICAInternalRegs::AttribFormatHigh]) << 32); u64 vertexCfg = u64(regs[PICAInternalRegs::AttribFormatLow]) | (u64(regs[PICAInternalRegs::AttribFormatHigh]) << 32);
if constexpr (!indexed) { if constexpr (!indexed) {
u32 offset = regs[PICAInternalRegs::VertexOffsetReg]; u32 offset = regs[PICAInternalRegs::VertexOffsetReg];
printf("PICA::DrawArrays(vertex count = %d, vertexOffset = %d)\n", vertexCount, offset); log("PICA::DrawArrays(vertex count = %d, vertexOffset = %d)\n", vertexCount, offset);
} else { } else {
Helpers::panic("[PICA] Indexed drawing"); Helpers::panic("[PICA] Indexed drawing");
} }
@ -96,7 +101,6 @@ void GPU::drawArrays() {
for (component = 0; component < componentCount; component++) { for (component = 0; component < componentCount; component++) {
float val = *ptr++; float val = *ptr++;
attribute[component] = f24::fromFloat32(val); attribute[component] = f24::fromFloat32(val);
printf("Component %d: %f\n", component, (double)val);
} }
break; break;
} }
@ -111,11 +115,13 @@ void GPU::drawArrays() {
attribute[component] = (component == 3) ? f24::fromFloat32(1.0) : f24::fromFloat32(0.0); attribute[component] = (component == 3) ? f24::fromFloat32(1.0) : f24::fromFloat32(0.0);
component++; component++;
} }
printf("Attribute %d, type: %d, component count: %d\n", attrCount, attribType, componentCount);
} }
} }
shaderUnit.vs.run(); // Run vertex shader for vertex shaderUnit.vs.run();
std::memcpy(&vertices[i].position, &shaderUnit.vs.outputs[0], sizeof(vec4f));
std::memcpy(&vertices[i].colour, &shaderUnit.vs.outputs[1], sizeof(vec4f));
} }
drawVertices(OpenGL::Triangle, vertices, vertexCount);
} }

View file

@ -4,7 +4,7 @@
using namespace Floats; using namespace Floats;
u32 GPU::readReg(u32 address) { u32 GPU::readReg(u32 address) {
printf("Ignoring read from GPU register %08X\n", address); log("Ignoring read from GPU register %08X\n", address);
return 0; return 0;
} }
@ -13,13 +13,13 @@ void GPU::writeReg(u32 address, u32 value) {
const u32 index = (address - 0x1EF01000) / sizeof(u32); const u32 index = (address - 0x1EF01000) / sizeof(u32);
writeInternalReg(index, value, 0xffffffff); writeInternalReg(index, value, 0xffffffff);
} else { } else {
printf("Ignoring write to external GPU register %08X. Value: %08X\n", address, value); log("Ignoring write to external GPU register %08X. Value: %08X\n", address, value);
} }
} }
u32 GPU::readInternalReg(u32 index) { u32 GPU::readInternalReg(u32 index) {
if (index > regNum) { if (index > regNum) {
printf("Tried to read invalid GPU register. Index: %X\n", index); Helpers::panic("Tried to read invalid GPU register. Index: %X\n", index);
return 0; return 0;
} }
@ -131,7 +131,7 @@ void GPU::writeInternalReg(u32 index, u32 value, u32 mask) {
break; break;
} }
} else { } else {
printf("GPU: Wrote to unimplemented internal reg: %X, value: %08X\n", index, newValue); log("GPU: Wrote to unimplemented internal reg: %X, value: %08X\n", index, newValue);
} }
break; break;
} }

View file

@ -0,0 +1,160 @@
#include "PICA/gpu.hpp"
#include "opengl.hpp"
// This is all hacked up to display our first triangle
const char* vertexShader = R"(
#version 420 core
layout (location = 0) in vec4 coords;
layout (location = 1) in vec4 vertexColour;
out vec4 colour;
void main() {
gl_Position = coords;
colour = vertexColour;
}
)";
const char* fragmentShader = R"(
#version 420 core
in vec4 colour;
out vec4 fragColour;
void main() {
fragColour = colour;
}
)";
const char* displayVertexShader = R"(
#version 420 core
out vec2 UV;
void main() {
const vec4 positions[4] = vec4[](
vec4(-1.0, 1.0, 1.0, 1.0), // Top-left
vec4(1.0, 1.0, 1.0, 1.0), // Top-right
vec4(-1.0, -1.0, 1.0, 1.0), // Bottom-left
vec4(1.0, -1.0, 1.0, 1.0) // Bottom-right
);
// The 3DS displays both screens' framebuffer rotated 90 deg counter clockwise
// So we adjust our texcoords accordingly
const vec2 texcoords[4] = vec2[](
vec2(1.0, 1.0), // Top-right
vec2(1.0, 0.0), // Bottom-right
vec2(0.0, 1.0), // Top-left
vec2(0.0, 0.0) // Bottom-left
);
gl_Position = positions[gl_VertexID];
UV = texcoords[gl_VertexID];
}
)";
const char* displayFragmentShader = R"(
#version 420 core
in vec2 UV;
out vec4 FragColor;
uniform sampler2D u_texture; // TODO: Properly init this to 0 when I'm not lazy
void main() {
FragColor = texture(u_texture, UV);
}
)";
void GPU::initGraphicsContext() {
// Set up texture for top screen
fboTexture.create(400, 240, GL_RGBA8);
fboTexture.bind();
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
fbo.createWithDrawTexture(fboTexture);
fbo.bind(OpenGL::DrawFramebuffer);
OpenGL::setViewport(400, 240);
OpenGL::setClearColor(0.0, 0.0, 0.0, 1.0);
OpenGL::clearColor();
OpenGL::Shader vert(vertexShader, OpenGL::Vertex);
OpenGL::Shader frag(fragmentShader, OpenGL::Fragment);
triangleProgram.create({ vert, frag });
OpenGL::Shader vertDisplay(displayVertexShader, OpenGL::Vertex);
OpenGL::Shader fragDisplay(displayFragmentShader, OpenGL::Fragment);
displayProgram.create({ vertDisplay, fragDisplay });
vbo.createFixedSize(sizeof(Vertex) * vertexBufferSize, GL_STREAM_DRAW);
vbo.bind();
vao.create();
vao.bind();
// Position (x, y, z, w) attributes
vao.setAttributeFloat<float>(0, 4, sizeof(Vertex), offsetof(Vertex, position));
vao.enableAttribute(0);
// Colour attribute
vao.setAttributeFloat<float>(1, 4, sizeof(Vertex), offsetof(Vertex, colour));
vao.enableAttribute(1);
dummyVBO.create();
dummyVAO.create();
}
void GPU::getGraphicsContext() {
OpenGL::disableDepth();
OpenGL::disableScissor();
OpenGL::setViewport(400, 240);
fbo.bind(OpenGL::DrawAndReadFramebuffer);
vbo.bind();
vao.bind();
triangleProgram.use();
}
void GPU::drawVertices(OpenGL::Primitives primType, Vertex* vertices, u32 count) {
vbo.bufferVertsSub(vertices, count);
OpenGL::draw(primType, count);
}
constexpr u32 topScreenBuffer = 0x1f000000;
constexpr u32 bottomScreenBuffer = 0x1f300000;
// Quick hack to display top screen for now
void GPU::display() {
OpenGL::disableScissor();
OpenGL::bindScreenFramebuffer();
fboTexture.bind();
displayProgram.use();
dummyVBO.bind();
dummyVAO.bind();
OpenGL::setViewport(0, 240, 400, 240);
OpenGL::draw(OpenGL::TriangleStrip, 4);
}
void GPU::clearBuffer(u32 startAddress, u32 endAddress, u32 value, u32 control) {
log("GPU: Clear buffer\nStart: %08X End: %08X\nValue: %08X Control: %08X\n", startAddress, endAddress, value, control);
const float r = float((value >> 24) & 0xff) / 255.0;
const float g = float((value >> 16) & 0xff) / 255.0;
const float b = float((value >> 8) & 0xff) / 255.0;
const float a = float(value & 0xff) / 255.0;
if (startAddress == topScreenBuffer) {
log("GPU: Cleared top screen\n");
} else if (startAddress == bottomScreenBuffer) {
log("GPU: Tried to clear bottom screen\n");
return;
} else {
log("GPU: Clearing some unknown buffer\n");
}
OpenGL::setClearColor(r, g, b, a);
OpenGL::clearColor();
}

View file

@ -37,7 +37,7 @@ void Kernel::arbitrateAddress() {
const s32 value = s32(regs[3]); const s32 value = s32(regs[3]);
const s64 ns = s64(u64(regs[4]) | (u64(regs[5]) << 32)); const s64 ns = s64(u64(regs[4]) | (u64(regs[5]) << 32));
printf("ArbitrateAddress(Handle = %X, address = %08X, type = %s, value = %d, ns = %lld)\n", handle, address, logSVC("ArbitrateAddress(Handle = %X, address = %08X, type = %s, value = %d, ns = %lld)\n", handle, address,
arbitrationTypeToString(type), value, ns); arbitrationTypeToString(type), value, ns);
const auto arbiter = getObject(handle, KernelObjectType::AddressArbiter); const auto arbiter = getObject(handle, KernelObjectType::AddressArbiter);
@ -68,7 +68,7 @@ void Kernel::arbitrateAddress() {
} }
case ArbitrationType::Signal: case ArbitrationType::Signal:
printf("Broken ArbitrateAddress (type == SIGNAL)\n"); logSVC("Broken ArbitrateAddress (type == SIGNAL)\n");
switchThread(0); switchThread(0);
break; break;

View file

@ -23,7 +23,7 @@ void Kernel::createEvent() {
if (resetType > 2) if (resetType > 2)
Helpers::panic("Invalid reset type for event %d", resetType); Helpers::panic("Invalid reset type for event %d", resetType);
printf("CreateEvent(handle pointer = %08X, resetType = %s)\n", outPointer, resetTypeToString(resetType)); logSVC("CreateEvent(handle pointer = %08X, resetType = %s)\n", outPointer, resetTypeToString(resetType));
regs[0] = SVCResult::Success; regs[0] = SVCResult::Success;
regs[1] = makeEvent(static_cast<ResetType>(resetType)); regs[1] = makeEvent(static_cast<ResetType>(resetType));
@ -33,7 +33,7 @@ void Kernel::createEvent() {
void Kernel::clearEvent() { void Kernel::clearEvent() {
const Handle handle = regs[0]; const Handle handle = regs[0];
const auto event = getObject(handle, KernelObjectType::Event); const auto event = getObject(handle, KernelObjectType::Event);
printf("ClearEvent(event handle = %d)\n", handle); logSVC("ClearEvent(event handle = %d)\n", handle);
if (event == nullptr) [[unlikely]] { if (event == nullptr) [[unlikely]] {
regs[0] = SVCResult::BadHandle; regs[0] = SVCResult::BadHandle;
@ -56,8 +56,6 @@ void Kernel::waitSynchronization1() {
return; return;
} }
printf("WaitSynchronization1(handle = %X, ns = %lld) (STUBBED)\n", handle, ns); logSVC("WaitSynchronization1(handle = %X, ns = %lld) (STUBBED)\n", handle, ns);
serviceManager.requestGPUInterrupt(GPUInterrupt::VBlank0);
serviceManager.requestGPUInterrupt(GPUInterrupt::VBlank1);
regs[0] = SVCResult::Success; regs[0] = SVCResult::Success;
} }

View file

@ -118,13 +118,13 @@ u32 Kernel::getTLSPointer() {
// Result CloseHandle(Handle handle) // Result CloseHandle(Handle handle)
void Kernel::svcCloseHandle() { void Kernel::svcCloseHandle() {
printf("CloseHandle(handle = %d) (Unimplemented)\n", regs[0]); logSVC("CloseHandle(handle = %d) (Unimplemented)\n", regs[0]);
regs[0] = SVCResult::Success; regs[0] = SVCResult::Success;
} }
// u64 GetSystemTick() // u64 GetSystemTick()
void Kernel::getSystemTick() { void Kernel::getSystemTick() {
printf("GetSystemTick()\n"); logSVC("GetSystemTick()\n");
u64 ticks = cpu.getTicks(); u64 ticks = cpu.getTicks();
regs[0] = u32(ticks); regs[0] = u32(ticks);
@ -138,7 +138,7 @@ void Kernel::outputDebugString() {
const u32 size = regs[1]; const u32 size = regs[1];
std::string message = mem.readString(pointer, size); std::string message = mem.readString(pointer, size);
printf("[OutputDebugString] %s\n", message.c_str()); logSVC("[OutputDebugString] %s\n", message.c_str());
regs[0] = SVCResult::Success; regs[0] = SVCResult::Success;
} }
@ -147,7 +147,7 @@ void Kernel::getProcessInfo() {
const auto pid = regs[1]; const auto pid = regs[1];
const auto type = regs[2]; const auto type = regs[2];
const auto process = getProcessFromPID(pid); const auto process = getProcessFromPID(pid);
printf("GetProcessInfo(process: %s, type = %d)\n", getProcessName(pid).c_str(), type); logSVC("GetProcessInfo(process: %s, type = %d)\n", getProcessName(pid).c_str(), type);
if (process == nullptr) [[unlikely]] { if (process == nullptr) [[unlikely]] {
regs[0] = SVCResult::BadHandle; regs[0] = SVCResult::BadHandle;
@ -170,7 +170,7 @@ void Kernel::getProcessInfo() {
// Result GetThreadId(u32* threadId, Handle thread) // Result GetThreadId(u32* threadId, Handle thread)
void Kernel::duplicateHandle() { void Kernel::duplicateHandle() {
Handle original = regs[1]; Handle original = regs[1];
printf("DuplicateHandle(handle = %X)\n", original); logSVC("DuplicateHandle(handle = %X)\n", original);
if (original == KernelHandles::CurrentThread) { if (original == KernelHandles::CurrentThread) {
printf("[Warning] Duplicated current thread. This might be horribly broken!\n"); printf("[Warning] Duplicated current thread. This might be horribly broken!\n");

View file

@ -49,7 +49,7 @@ void Kernel::controlMemory() {
Helpers::panic("ControlMemory: Unaligned parameters\nAddr0: %08X\nAddr1: %08X\nSize: %08X", addr0, addr1, size); Helpers::panic("ControlMemory: Unaligned parameters\nAddr0: %08X\nAddr1: %08X\nSize: %08X", addr0, addr1, size);
} }
printf("ControlMemory(addr0 = %08X, addr1 = %08X, size = %08X, operation = %X (%c%c%c)%s\n", logSVC("ControlMemory(addr0 = %08X, addr1 = %08X, size = %08X, operation = %X (%c%c%c)%s\n",
addr0, addr1, size, operation, r ? 'r' : '-', w ? 'w' : '-', x ? 'x' : '-', linear ? ", linear" : "" addr0, addr1, size, operation, r ? 'r' : '-', w ? 'w' : '-', x ? 'x' : '-', linear ? ", linear" : ""
); );
@ -75,7 +75,7 @@ void Kernel::queryMemory() {
const u32 pageInfo = regs[1]; const u32 pageInfo = regs[1];
const u32 addr = regs[2]; const u32 addr = regs[2];
printf("QueryMemory(mem info pointer = %08X, page info pointer = %08X, addr = %08X)\n", memInfo, pageInfo, addr); logSVC("QueryMemory(mem info pointer = %08X, page info pointer = %08X, addr = %08X)\n", memInfo, pageInfo, addr);
const auto info = mem.queryMemory(addr); const auto info = mem.queryMemory(addr);
regs[0] = SVCResult::Success; regs[0] = SVCResult::Success;
@ -92,7 +92,7 @@ void Kernel::mapMemoryBlock() {
const u32 addr = regs[1]; const u32 addr = regs[1];
const u32 myPerms = regs[2]; const u32 myPerms = regs[2];
const u32 otherPerms = regs[3]; const u32 otherPerms = regs[3];
printf("MapMemoryBlock(block = %d, addr = %08X, myPerms = %X, otherPerms = %X\n", block, addr, myPerms, otherPerms); logSVC("MapMemoryBlock(block = %d, addr = %08X, myPerms = %X, otherPerms = %X\n", block, addr, myPerms, otherPerms);
if (!isAligned(addr)) [[unlikely]] { if (!isAligned(addr)) [[unlikely]] {
Helpers::panic("MapMemoryBlock: Unaligned address"); Helpers::panic("MapMemoryBlock: Unaligned address");

View file

@ -56,7 +56,7 @@ void Kernel::connectToPort() {
} }
Handle portHandle = optionalHandle.value(); Handle portHandle = optionalHandle.value();
printf("ConnectToPort(handle pointer = %X, port = \"%s\")\n", handlePointer, port.c_str()); logSVC("ConnectToPort(handle pointer = %X, port = \"%s\")\n", handlePointer, port.c_str());
const auto portData = objects[portHandle].getData<Port>(); const auto portData = objects[portHandle].getData<Port>();
if (!portData->isPublic) { if (!portData->isPublic) {
@ -76,7 +76,7 @@ void Kernel::sendSyncRequest() {
const auto handle = regs[0]; const auto handle = regs[0];
u32 messagePointer = getTLSPointer() + 0x80; // The message is stored starting at TLS+0x80 u32 messagePointer = getTLSPointer() + 0x80; // The message is stored starting at TLS+0x80
printf("SendSyncRequest(session handle = %X)\n", handle); logSVC("SendSyncRequest(session handle = %X)\n", handle);
// The sync request is being sent at a service rather than whatever port, so have the service manager intercept it // The sync request is being sent at a service rather than whatever port, so have the service manager intercept it
if (KernelHandles::isServiceHandle(handle)) { if (KernelHandles::isServiceHandle(handle)) {

View file

@ -7,7 +7,7 @@ void Kernel::getResourceLimit() {
const auto handlePointer = regs[0]; const auto handlePointer = regs[0];
const auto pid = regs[1]; const auto pid = regs[1];
const auto process = getProcessFromPID(pid); const auto process = getProcessFromPID(pid);
printf("GetResourceLimit (handle pointer = %08X, process: %s)\n", handlePointer, getProcessName(pid).c_str()); logSVC("GetResourceLimit (handle pointer = %08X, process: %s)\n", handlePointer, getProcessName(pid).c_str());
if (process == nullptr) [[unlikely]] { if (process == nullptr) [[unlikely]] {
regs[0] = SVCResult::BadHandle; regs[0] = SVCResult::BadHandle;
@ -33,7 +33,7 @@ void Kernel::getResourceLimitLimitValues() {
return; return;
} }
printf("GetResourceLimitLimitValues(values = %08X, handle = %X, names = %08X, count = %d)\n", values, resourceLimit, names, count); logSVC("GetResourceLimitLimitValues(values = %08X, handle = %X, names = %08X, count = %d)\n", values, resourceLimit, names, count);
// printf("[Warning] We do not currently support any resource maximum aside from the application ones"); // printf("[Warning] We do not currently support any resource maximum aside from the application ones");
while (count != 0) { while (count != 0) {
const u32 name = mem.read32(names); const u32 name = mem.read32(names);
@ -62,7 +62,7 @@ void Kernel::getResourceLimitCurrentValues() {
return; return;
} }
printf("GetResourceLimitCurrentValues(values = %08X, handle = %X, names = %08X, count = %d)\n", values, resourceLimit, names, count); logSVC("GetResourceLimitCurrentValues(values = %08X, handle = %X, names = %08X, count = %d)\n", values, resourceLimit, names, count);
while (count != 0) { while (count != 0) {
const u32 name = mem.read32(names); const u32 name = mem.read32(names);
// TODO: Unsure if this is supposed to be s32 or u32. Shouldn't matter as the kernel can't create so many resources // TODO: Unsure if this is supposed to be s32 or u32. Shouldn't matter as the kernel can't create so many resources

View file

@ -75,7 +75,7 @@ void Kernel::createThread() {
u32 initialSP = regs[3] & ~7; // SP is force-aligned to 8 bytes u32 initialSP = regs[3] & ~7; // SP is force-aligned to 8 bytes
s32 id = static_cast<s32>(regs[4]); s32 id = static_cast<s32>(regs[4]);
printf("CreateThread(entry = %08X, stacktop = %08X, priority = %X, processor ID = %d)\n", entrypoint, logSVC("CreateThread(entry = %08X, stacktop = %08X, priority = %X, processor ID = %d)\n", entrypoint,
initialSP, priority, id); initialSP, priority, id);
if (priority > 0x3F) [[unlikely]] { if (priority > 0x3F) [[unlikely]] {
@ -99,7 +99,7 @@ void Kernel::sleepThreadOnArbiter(u32 waitingAddress) {
void Kernel::getThreadID() { void Kernel::getThreadID() {
Handle handle = regs[1]; Handle handle = regs[1];
printf("GetThreadID(handle = %X)\n", handle); logSVC("GetThreadID(handle = %X)\n", handle);
if (handle == KernelHandles::CurrentThread) { if (handle == KernelHandles::CurrentThread) {
regs[0] = SVCResult::Success; regs[0] = SVCResult::Success;

View file

@ -24,7 +24,7 @@ void APTService::handleSyncRequest(u32 messagePointer) {
} }
void APTService::getLockHandle(u32 messagePointer) { void APTService::getLockHandle(u32 messagePointer) {
printf("APT::GetLockHandle (Failure)\n"); log("APT::GetLockHandle (Failure)\n");
mem.write32(messagePointer + 4, Result::Failure); // Result code mem.write32(messagePointer + 4, Result::Failure); // Result code
mem.write32(messagePointer + 16, 0); // Translation descriptor mem.write32(messagePointer + 16, 0); // Translation descriptor
} }

View file

@ -26,11 +26,11 @@ void FSService::handleSyncRequest(u32 messagePointer) {
} }
void FSService::initialize(u32 messagePointer) { void FSService::initialize(u32 messagePointer) {
printf("FS::Initialize (failure)\n"); log("FS::Initialize (failure)\n");
mem.write32(messagePointer + 4, Result::Failure); mem.write32(messagePointer + 4, Result::Failure);
} }
void FSService::openArchive(u32 messagePointer) { void FSService::openArchive(u32 messagePointer) {
printf("FS::OpenArchive (failure)\n"); log("FS::OpenArchive (failure)\n");
mem.write32(messagePointer + 4, Result::Failure); mem.write32(messagePointer + 4, Result::Failure);
} }

View file

@ -14,10 +14,11 @@ namespace ServiceCommands {
} }
// Commands written to shared memory and processed by TriggerCmdReqQueue // Commands written to shared memory and processed by TriggerCmdReqQueue
namespace GPUCommands { namespace GXCommands {
enum : u32 { enum : u32 {
ProcessCommandList = 1, ProcessCommandList = 1,
MemoryFill = 2 MemoryFill = 2,
TriggerDisplayTransfer = 3
}; };
} }
@ -50,7 +51,7 @@ void GPUService::handleSyncRequest(u32 messagePointer) {
void GPUService::acquireRight(u32 messagePointer) { void GPUService::acquireRight(u32 messagePointer) {
const u32 flag = mem.read32(messagePointer + 4); const u32 flag = mem.read32(messagePointer + 4);
const u32 pid = mem.read32(messagePointer + 12); const u32 pid = mem.read32(messagePointer + 12);
printf("GSP::GPU::AcquireRight (flag = %X, pid = %X)\n", flag, pid); log("GSP::GPU::AcquireRight (flag = %X, pid = %X)\n", flag, pid);
if (flag != 0) { if (flag != 0) {
Helpers::panic("GSP::GPU::acquireRight with flag != 0 needs to perform additional initialization"); Helpers::panic("GSP::GPU::acquireRight with flag != 0 needs to perform additional initialization");
@ -76,7 +77,7 @@ void GPUService::registerInterruptRelayQueue(u32 messagePointer) {
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); log("GSP::GPU::RegisterInterruptRelayQueue (flags = %X, event handle = %X)\n", flags, eventHandle);
mem.write32(messagePointer + 4, Result::SuccessRegisterIRQ); mem.write32(messagePointer + 4, Result::SuccessRegisterIRQ);
mem.write32(messagePointer + 8, 0); // TODO: GSP module thread index mem.write32(messagePointer + 8, 0); // TODO: GSP module thread index
@ -101,7 +102,7 @@ void GPUService::writeHwRegs(u32 messagePointer) {
u32 ioAddr = mem.read32(messagePointer + 4); // GPU address based at 0x1EB00000, word aligned u32 ioAddr = mem.read32(messagePointer + 4); // GPU address based at 0x1EB00000, word aligned
const u32 size = mem.read32(messagePointer + 8); // Size in bytes const u32 size = mem.read32(messagePointer + 8); // Size in bytes
u32 dataPointer = mem.read32(messagePointer + 16); u32 dataPointer = mem.read32(messagePointer + 16);
printf("GSP::GPU::writeHwRegs (GPU address = %08X, size = %X, data address = %08X)\n", ioAddr, size, dataPointer); log("GSP::GPU::writeHwRegs (GPU address = %08X, size = %X, data address = %08X)\n", ioAddr, size, dataPointer);
// Check for alignment // Check for alignment
if ((size & 3) || (ioAddr & 3) || (dataPointer & 3)) { if ((size & 3) || (ioAddr & 3) || (dataPointer & 3)) {
@ -135,7 +136,7 @@ void GPUService::writeHwRegsWithMask(u32 messagePointer) {
u32 dataPointer = mem.read32(messagePointer + 16); // Data pointer u32 dataPointer = mem.read32(messagePointer + 16); // Data pointer
u32 maskPointer = mem.read32(messagePointer + 24); // Mask pointer u32 maskPointer = mem.read32(messagePointer + 24); // Mask pointer
printf("GSP::GPU::writeHwRegsWithMask (GPU address = %08X, size = %X, data address = %08X, mask address = %08X)\n", log("GSP::GPU::writeHwRegsWithMask (GPU address = %08X, size = %X, data address = %08X, mask address = %08X)\n",
ioAddr, size, dataPointer, maskPointer); ioAddr, size, dataPointer, maskPointer);
// Check for alignment // Check for alignment
@ -172,14 +173,14 @@ void GPUService::flushDataCache(u32 messagePointer) {
u32 address = mem.read32(messagePointer + 4); u32 address = mem.read32(messagePointer + 4);
u32 size = mem.read32(messagePointer + 8); u32 size = mem.read32(messagePointer + 8);
u32 processHandle = handle = mem.read32(messagePointer + 16); u32 processHandle = handle = mem.read32(messagePointer + 16);
printf("GSP::GPU::FlushDataCache(address = %08X, size = %X, process = %X\n", address, size, processHandle); log("GSP::GPU::FlushDataCache(address = %08X, size = %X, process = %X\n", address, size, processHandle);
mem.write32(messagePointer + 4, Result::Success); mem.write32(messagePointer + 4, Result::Success);
} }
void GPUService::setLCDForceBlack(u32 messagePointer) { void GPUService::setLCDForceBlack(u32 messagePointer) {
u32 flag = mem.read32(messagePointer + 4); u32 flag = mem.read32(messagePointer + 4);
printf("GSP::GPU::SetLCDForceBlank(flag = %d)\n", flag); log("GSP::GPU::SetLCDForceBlank(flag = %d)\n", flag);
if (flag != 0) { if (flag != 0) {
printf("Filled both LCDs with black\n"); printf("Filled both LCDs with black\n");
@ -193,9 +194,6 @@ void GPUService::triggerCmdReqQueue(u32 messagePointer) {
mem.write32(messagePointer + 4, Result::Success); mem.write32(messagePointer + 4, Result::Success);
} }
#include <chrono>
#include <thread>
using namespace std::chrono_literals;
void GPUService::processCommandBuffer() { void GPUService::processCommandBuffer() {
if (sharedMem == nullptr) [[unlikely]] { // Shared memory hasn't been set up yet if (sharedMem == nullptr) [[unlikely]] { // Shared memory hasn't been set up yet
return; return;
@ -208,14 +206,14 @@ void GPUService::processCommandBuffer() {
// Commands start at byte 0x20 of the command buffer, each being 0x20 bytes long // Commands start at byte 0x20 of the command buffer, each being 0x20 bytes long
u32* cmd = reinterpret_cast<u32*>(&cmdBuffer[0x20]); u32* cmd = reinterpret_cast<u32*>(&cmdBuffer[0x20]);
printf("Processing %d GPU commands\n", commandsLeft); log("Processing %d GPU commands\n", commandsLeft);
std::this_thread::sleep_for(1000ms);
while (commandsLeft != 0) { while (commandsLeft != 0) {
u32 cmdID = cmd[0] & 0xff; u32 cmdID = cmd[0] & 0xff;
switch (cmdID) { switch (cmdID) {
case GPUCommands::ProcessCommandList: processCommandList(cmd); break; case GXCommands::ProcessCommandList: processCommandList(cmd); break;
case GPUCommands::MemoryFill: memoryFill(cmd); break; case GXCommands::MemoryFill: memoryFill(cmd); break;
case GXCommands::TriggerDisplayTransfer: triggerDisplayTransfer(cmd); break;
default: Helpers::panic("GSP::GPU::ProcessCommands: Unknown cmd ID %d", cmdID); default: Helpers::panic("GSP::GPU::ProcessCommands: Unknown cmd ID %d", cmdID);
} }
@ -249,6 +247,11 @@ void GPUService::memoryFill(u32* cmd) {
} }
} }
void GPUService::triggerDisplayTransfer(u32* cmd) {
log("GSP::GPU::TriggerDisplayTransfer (Stubbed)\n");
requestInterrupt(GPUInterrupt::PPF); // Send "Display transfer finished" interrupt
}
// Actually send command list (aka display list) to GPU // Actually send command list (aka display list) to GPU
void GPUService::processCommandList(u32* cmd) { void GPUService::processCommandList(u32* cmd) {
u32 address = cmd[1] & ~7; // Buffer address u32 address = cmd[1] & ~7; // Buffer address
@ -305,5 +308,6 @@ void GPUService::processCommandList(u32* cmd) {
} }
} }
printf("GPU::GSP::processCommandList. Address: %08X, size in bytes: %08X\n", address, size); log("GPU::GSP::processCommandList. Address: %08X, size in bytes: %08X\n", address, size);
requestInterrupt(GPUInterrupt::P3D); // Send an IRQ when command list processing is over
} }

View file

@ -24,7 +24,7 @@ void HIDService::handleSyncRequest(u32 messagePointer) {
} }
void HIDService::getIPCHandles(u32 messagePointer) { void HIDService::getIPCHandles(u32 messagePointer) {
printf("HID::GetIPCHandles (Failure)\n"); log("HID::GetIPCHandles (Failure)\n");
mem.write32(messagePointer + 4, Result::Failure); // Result code mem.write32(messagePointer + 4, Result::Failure); // Result code
mem.write32(messagePointer + 8, 0x14000000); // Translation descriptor mem.write32(messagePointer + 8, 0x14000000); // Translation descriptor
} }

View file

@ -25,11 +25,11 @@ void NDMService::handleSyncRequest(u32 messagePointer) {
} }
void NDMService::overrideDefaultDaemons(u32 messagePointer) { void NDMService::overrideDefaultDaemons(u32 messagePointer) {
printf("NDM::OverrideDefaultDaemons(stubbed)\n"); log("NDM::OverrideDefaultDaemons(stubbed)\n");
mem.write32(messagePointer + 4, Result::Success); mem.write32(messagePointer + 4, Result::Success);
} }
void NDMService::suspendDaemons(u32 messagePointer) { void NDMService::suspendDaemons(u32 messagePointer) {
printf("NDM::SuspendDaemons(stubbed)\n"); log("NDM::SuspendDaemons(stubbed)\n");
mem.write32(messagePointer + 4, Result::Success); mem.write32(messagePointer + 4, Result::Success);
} }

View file

@ -54,7 +54,7 @@ void ServiceManager::handleSyncRequest(u32 messagePointer) {
// https://www.3dbrew.org/wiki/SRV:RegisterClient // https://www.3dbrew.org/wiki/SRV:RegisterClient
void ServiceManager::registerClient(u32 messagePointer) { void ServiceManager::registerClient(u32 messagePointer) {
printf("srv::registerClient (Stubbed)\n"); log("srv::registerClient (Stubbed)\n");
mem.write32(messagePointer + 4, Result::Success); mem.write32(messagePointer + 4, Result::Success);
} }
@ -65,7 +65,7 @@ void ServiceManager::getServiceHandle(u32 messagePointer) {
u32 handle = 0; u32 handle = 0;
std::string service = mem.readString(messagePointer + 4, 8); std::string service = mem.readString(messagePointer + 4, 8);
printf("srv::getServiceHandle (Service: %s, nameLength: %d, flags: %d)\n", service.c_str(), nameLength, flags); log("srv::getServiceHandle (Service: %s, nameLength: %d, flags: %d)\n", service.c_str(), nameLength, flags);
if (service == "APT:S") { if (service == "APT:S") {
handle = KernelHandles::APT; handle = KernelHandles::APT;
@ -90,7 +90,7 @@ void ServiceManager::getServiceHandle(u32 messagePointer) {
} }
void ServiceManager::enableNotification(u32 messagePointer) { void ServiceManager::enableNotification(u32 messagePointer) {
printf("srv::EnableNotification()\n"); log("srv::EnableNotification()\n");
mem.write32(messagePointer + 4, Result::Success); // Result code mem.write32(messagePointer + 4, Result::Success); // Result code
mem.write32(messagePointer + 8, 0); // Translation descriptor mem.write32(messagePointer + 8, 0); // Translation descriptor

View file

@ -23,20 +23,29 @@ void Emulator::render() {
void Emulator::run() { void Emulator::run() {
while (window.isOpen()) { while (window.isOpen()) {
runFrame(); // Clear window to black
OpenGL::setClearColor(1.0, 0.0, 0.0, 1.0); OpenGL::bindScreenFramebuffer();
OpenGL::setViewport(400, 240 * 2);
OpenGL::disableScissor(); OpenGL::disableScissor();
OpenGL::setClearColor(0.0, 0.0, 0.0, 1.0);
OpenGL::clearColor(); OpenGL::clearColor();
gpu.getGraphicsContext(); // Give the GPU a rendering context
runFrame(); // Run 1 frame of instructions
gpu.display();
// Send VBlank interrupts
kernel.sendGPUInterrupt(GPUInterrupt::VBlank0);
kernel.sendGPUInterrupt(GPUInterrupt::VBlank1);
window.display();
sf::Event event; sf::Event event;
while (window.pollEvent(event)) { while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed) { if (event.type == sf::Event::Closed) {
Helpers::panic("Bye :("); printf("Bye :(\n");
window.close();
return;
} }
} }
window.display();
} }
} }

View file

@ -7,6 +7,8 @@ int main (int argc, char *argv[]) {
Helpers::panic("Failed to initialize OpenGL"); Helpers::panic("Failed to initialize OpenGL");
} }
emu.initGraphicsContext();
auto elfPath = std::filesystem::current_path() / (argc > 1 ? argv[1] : "SimplerTri.elf"); auto elfPath = std::filesystem::current_path() / (argc > 1 ? argv[1] : "SimplerTri.elf");
if (!emu.loadELF(elfPath)) { if (!emu.loadELF(elfPath)) {
// For some reason just .c_str() doesn't show the proper path // For some reason just .c_str() doesn't show the proper path