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

@ -30,10 +30,6 @@ void GPU::reset() {
// 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) {
if (indexed)
drawArrays<true>();
@ -48,13 +44,22 @@ void GPU::drawArrays() {
const u32 vertexBase = ((regs[PICAInternalRegs::VertexAttribLoc] >> 1) & 0xfffffff) * 16;
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
// TODO: Cache this when the vertex attribute format registers are written to
u64 vertexCfg = u64(regs[PICAInternalRegs::AttribFormatLow]) | (u64(regs[PICAInternalRegs::AttribFormatHigh]) << 32);
if constexpr (!indexed) {
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 {
Helpers::panic("[PICA] Indexed drawing");
}
@ -96,7 +101,6 @@ void GPU::drawArrays() {
for (component = 0; component < componentCount; component++) {
float val = *ptr++;
attribute[component] = f24::fromFloat32(val);
printf("Component %d: %f\n", component, (double)val);
}
break;
}
@ -111,11 +115,13 @@ void GPU::drawArrays() {
attribute[component] = (component == 3) ? f24::fromFloat32(1.0) : f24::fromFloat32(0.0);
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;
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;
}
@ -13,13 +13,13 @@ void GPU::writeReg(u32 address, u32 value) {
const u32 index = (address - 0x1EF01000) / sizeof(u32);
writeInternalReg(index, value, 0xffffffff);
} 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) {
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;
}
@ -131,7 +131,7 @@ void GPU::writeInternalReg(u32 index, u32 value, u32 mask) {
break;
}
} 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;
}

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