mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-04-11 08:39:48 +12:00
Add PICA texel-format and topology types
Slowly stepping the codebase towards having renderer-agnostic types and keeping the translation of PICA-types to OpenGL/VK/DX/Software/etc to the renderer-backend.
This commit is contained in:
parent
d0ae5f0546
commit
78a3f9fa23
6 changed files with 85 additions and 76 deletions
|
@ -127,4 +127,51 @@ namespace PICAInternalRegs {
|
|||
VertexShaderOpDescriptorData6 = 0x2DC,
|
||||
VertexShaderOpDescriptorData7 = 0x2DD,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
enum class PICAColorFmt : u32 {
|
||||
RGBA8 = 0,
|
||||
BGR8 = 1,
|
||||
RGB5A1 = 2,
|
||||
RGB565 = 3,
|
||||
RGBA4 = 4,
|
||||
|
||||
// Technically selectable, but their function is unknown
|
||||
Unknown5 = 5,
|
||||
Unknown6 = 6,
|
||||
Unknown7 = 7,
|
||||
};
|
||||
|
||||
enum class PICADepthFmt : u32 {
|
||||
Depth16 = 0,
|
||||
Unknown1 = 1, // Technically selectable, but function is unknown
|
||||
Depth24 = 2,
|
||||
Depth24Stencil8 = 3,
|
||||
};
|
||||
|
||||
// Size occupied by each pixel in bytes
|
||||
|
||||
// All formats are 16BPP except for RGBA8 (32BPP) and BGR8 (24BPP)
|
||||
inline constexpr usize sizePerPixel(PICAColorFmt format) {
|
||||
switch (format) {
|
||||
case PICAColorFmt::BGR8: return 3;
|
||||
case PICAColorFmt::RGBA8: return 4;
|
||||
default: return 2;
|
||||
}
|
||||
}
|
||||
|
||||
inline constexpr usize sizePerPixel(PICADepthFmt format) {
|
||||
switch (format) {
|
||||
case PICADepthFmt::Depth16: return 2;
|
||||
case PICADepthFmt::Depth24: return 3;
|
||||
case PICADepthFmt::Depth24Stencil8: return 4;
|
||||
default: return 1; // Invalid format
|
||||
}
|
||||
}
|
||||
|
||||
enum class PICAPrimType : u32 {
|
||||
TriangleList = 0,
|
||||
TriangleStrip = 1,
|
||||
TriangleFan = 2,
|
||||
GeometryPrimitive = 3,
|
||||
};
|
|
@ -7,6 +7,7 @@
|
|||
#include "opengl.hpp"
|
||||
#include "surface_cache.hpp"
|
||||
#include "textures.hpp"
|
||||
#include "PICA/regs.hpp"
|
||||
|
||||
// More circular dependencies!
|
||||
class GPU;
|
||||
|
@ -46,11 +47,11 @@ class Renderer {
|
|||
OpenGL::uvec2 fbSize; // The size of the framebuffer (ie both the colour and depth buffer)'
|
||||
|
||||
u32 colourBufferLoc; // Location in 3DS VRAM for the colour buffer
|
||||
ColourBuffer::Formats colourBufferFormat; // Format of the colours stored in the colour buffer
|
||||
PICAColorFmt colourBufferFormat; // Format of the colours stored in the colour buffer
|
||||
|
||||
// Same for the depth/stencil buffer
|
||||
u32 depthBufferLoc;
|
||||
DepthBuffer::Formats depthBufferFormat;
|
||||
PICADepthFmt depthBufferFormat;
|
||||
|
||||
// Dummy VAO/VBO for blitting the final output
|
||||
OpenGL::VertexArray dummyVAO;
|
||||
|
@ -75,23 +76,19 @@ class Renderer {
|
|||
void getGraphicsContext(); // Set up graphics context for rendering
|
||||
void clearBuffer(u32 startAddress, u32 endAddress, u32 value, u32 control); // Clear a GPU buffer in VRAM
|
||||
void displayTransfer(u32 inputAddr, u32 outputAddr, u32 inputSize, u32 outputSize, u32 flags); // Perform display transfer
|
||||
void drawVertices(OpenGL::Primitives primType, std::span<const Vertex> vertices); // Draw the given vertices
|
||||
void drawVertices(PICAPrimType primType, std::span<const Vertex> vertices); // Draw the given vertices
|
||||
|
||||
void setFBSize(u32 width, u32 height) {
|
||||
fbSize.x() = width;
|
||||
fbSize.y() = height;
|
||||
}
|
||||
|
||||
void setColourFormat(ColourBuffer::Formats format) { colourBufferFormat = format; }
|
||||
void setColourFormat(u32 format) { colourBufferFormat = static_cast<ColourBuffer::Formats>(format); }
|
||||
|
||||
void setDepthFormat(DepthBuffer::Formats format) { depthBufferFormat = format; }
|
||||
void setDepthFormat(u32 format) {
|
||||
if (format == 1) {
|
||||
void setColourFormat(PICAColorFmt format) { colourBufferFormat = format; }
|
||||
void setDepthFormat(PICADepthFmt format) {
|
||||
if (format == PICADepthFmt::Unknown1) {
|
||||
Helpers::panic("[PICA] Undocumented depth-stencil mode!");
|
||||
}
|
||||
|
||||
depthBufferFormat = static_cast<DepthBuffer::Formats>(format);
|
||||
depthBufferFormat = format;
|
||||
}
|
||||
|
||||
void setColourBufferLoc(u32 loc) { colourBufferLoc = loc; }
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#pragma once
|
||||
#include "PICA/regs.hpp"
|
||||
#include "boost/icl/interval.hpp"
|
||||
#include "helpers.hpp"
|
||||
#include "opengl.hpp"
|
||||
|
@ -7,18 +8,8 @@ template <typename T>
|
|||
using Interval = boost::icl::right_open_interval<T>;
|
||||
|
||||
struct ColourBuffer {
|
||||
enum class Formats : u32 {
|
||||
RGBA8 = 0,
|
||||
BGR8 = 1,
|
||||
RGB5A1 = 2,
|
||||
RGB565 = 3,
|
||||
RGBA4 = 4,
|
||||
|
||||
Trash1 = 5, Trash2 = 6, Trash3 = 7 // Technically selectable, but their function is unknown
|
||||
};
|
||||
|
||||
u32 location;
|
||||
Formats format;
|
||||
PICAColorFmt format;
|
||||
OpenGL::uvec2 size;
|
||||
bool valid;
|
||||
|
||||
|
@ -30,7 +21,7 @@ struct ColourBuffer {
|
|||
|
||||
ColourBuffer() : valid(false) {}
|
||||
|
||||
ColourBuffer(u32 loc, Formats format, u32 x, u32 y, bool valid = true)
|
||||
ColourBuffer(u32 loc, PICAColorFmt format, u32 x, u32 y, bool valid = true)
|
||||
: location(loc), format(format), size({x, y}), valid(valid) {
|
||||
|
||||
u64 endLoc = (u64)loc + sizeInBytes();
|
||||
|
@ -78,31 +69,14 @@ struct ColourBuffer {
|
|||
size.x() == other.size.x() && size.y() == other.size.y();
|
||||
}
|
||||
|
||||
// Size occupied by each pixel in bytes
|
||||
// All formats are 16BPP except for RGBA8 (32BPP) and BGR8 (24BPP)
|
||||
size_t sizePerPixel() {
|
||||
switch (format) {
|
||||
case Formats::BGR8: return 3;
|
||||
case Formats::RGBA8: return 4;
|
||||
default: return 2;
|
||||
}
|
||||
}
|
||||
|
||||
size_t sizeInBytes() {
|
||||
return (size_t)size.x() * (size_t)size.y() * sizePerPixel();
|
||||
return (size_t)size.x() * (size_t)size.y() * sizePerPixel(format);
|
||||
}
|
||||
};
|
||||
|
||||
struct DepthBuffer {
|
||||
enum class Formats : u32 {
|
||||
Depth16 = 0,
|
||||
Garbage = 1,
|
||||
Depth24 = 2,
|
||||
Depth24Stencil8 = 3
|
||||
};
|
||||
|
||||
u32 location;
|
||||
Formats format;
|
||||
PICADepthFmt format;
|
||||
OpenGL::uvec2 size; // Implicitly set to the size of the framebuffer
|
||||
bool valid;
|
||||
|
||||
|
@ -113,7 +87,7 @@ struct DepthBuffer {
|
|||
|
||||
DepthBuffer() : valid(false) {}
|
||||
|
||||
DepthBuffer(u32 loc, Formats format, u32 x, u32 y, bool valid = true) :
|
||||
DepthBuffer(u32 loc, PICADepthFmt format, u32 x, u32 y, bool valid = true) :
|
||||
location(loc), format(format), size({x, y}), valid(valid) {
|
||||
|
||||
u64 endLoc = (u64)loc + sizeInBytes();
|
||||
|
@ -122,7 +96,7 @@ struct DepthBuffer {
|
|||
}
|
||||
|
||||
bool hasStencil() {
|
||||
return format == Formats::Depth24Stencil8;
|
||||
return format == PICADepthFmt::Depth24Stencil8;
|
||||
}
|
||||
|
||||
void allocate() {
|
||||
|
@ -167,18 +141,7 @@ struct DepthBuffer {
|
|||
size.x() == other.size.x() && size.y() == other.size.y();
|
||||
}
|
||||
|
||||
// Size occupied by each pixel in bytes
|
||||
size_t sizePerPixel() {
|
||||
switch (format) {
|
||||
case Formats::Depth16: return 2;
|
||||
case Formats::Depth24: return 3;
|
||||
case Formats::Depth24Stencil8: return 4;
|
||||
|
||||
default: return 1; // Invalid format
|
||||
}
|
||||
}
|
||||
|
||||
size_t sizeInBytes() {
|
||||
return (size_t)size.x() * (size_t)size.y() * sizePerPixel();
|
||||
return (size_t)size.x() * (size_t)size.y() * sizePerPixel(format);
|
||||
}
|
||||
};
|
|
@ -55,11 +55,12 @@ void GPU::drawArrays() {
|
|||
|
||||
// Configures the type of primitive and the number of vertex shader outputs
|
||||
const u32 primConfig = regs[PICAInternalRegs::PrimitiveConfig];
|
||||
const u32 primType = Helpers::getBits<8, 2>(primConfig);
|
||||
if (primType != 0 && primType != 1 && primType != 3) Helpers::panic("[PICA] Tried to draw unimplemented shape %d\n", primType);
|
||||
const PICAPrimType primType = static_cast<PICAPrimType>(Helpers::getBits<8, 2>(primConfig));
|
||||
if (primType == PICAPrimType::TriangleFan) Helpers::panic("[PICA] Tried to draw unimplemented shape %d\n", primType);
|
||||
if (vertexCount > Renderer::vertexBufferSize) Helpers::panic("[PICA] vertexCount > vertexBufferSize");
|
||||
|
||||
if ((primType == 0 && vertexCount % 3) || (primType == 1 && vertexCount < 3)) {
|
||||
if ((primType == PICAPrimType::TriangleList && vertexCount % 3) ||
|
||||
(primType == PICAPrimType::TriangleStrip && vertexCount < 3)) {
|
||||
Helpers::panic("Invalid vertex count for primitive. Type: %d, vert count: %d\n", primType, vertexCount);
|
||||
}
|
||||
|
||||
|
@ -203,12 +204,7 @@ void GPU::drawArrays() {
|
|||
//printf("(u, v ) = (%f, %f)\n", vertices[i].UVs.u(), vertices[i].UVs.v());
|
||||
}
|
||||
|
||||
// The fourth type is meant to be "Geometry primitive". TODO: Find out what that is
|
||||
static constexpr std::array<OpenGL::Primitives, 4> primTypes = {
|
||||
OpenGL::Triangle, OpenGL::TriangleStrip, OpenGL::TriangleFan, OpenGL::Triangle
|
||||
};
|
||||
const auto shape = primTypes[primType];
|
||||
renderer.drawVertices(shape, std::span(vertices).first(vertexCount));
|
||||
renderer.drawVertices(primType, std::span(vertices).first(vertexCount));
|
||||
}
|
||||
|
||||
Vertex GPU::getImmediateModeVertex() {
|
||||
|
|
|
@ -68,7 +68,7 @@ void GPU::writeInternalReg(u32 index, u32 value, u32 mask) {
|
|||
|
||||
case ColourBufferFormat: {
|
||||
u32 format = getBits<16, 3>(value);
|
||||
renderer.setColourFormat(format);
|
||||
renderer.setColourFormat(static_cast<PICAColorFmt>(format));
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -79,8 +79,8 @@ void GPU::writeInternalReg(u32 index, u32 value, u32 mask) {
|
|||
}
|
||||
|
||||
case DepthBufferFormat: {
|
||||
u32 fmt = value & 0x3;
|
||||
renderer.setDepthFormat(fmt);
|
||||
u32 format = value & 0x3;
|
||||
renderer.setDepthFormat(static_cast<PICADepthFmt>(format));
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -157,7 +157,7 @@ void GPU::writeInternalReg(u32 index, u32 value, u32 mask) {
|
|||
// If we've reached 3 verts, issue a draw call
|
||||
// Handle rendering depending on the primitive type
|
||||
if (immediateModeVertIndex == 3) {
|
||||
renderer.drawVertices(OpenGL::Triangle, immediateModeVertices);
|
||||
renderer.drawVertices(PICAPrimType::TriangleList, immediateModeVertices);
|
||||
|
||||
switch (primType) {
|
||||
// Triangle or geometry primitive. Draw a triangle and discard all vertices
|
||||
|
|
|
@ -144,10 +144,10 @@ void Renderer::reset() {
|
|||
|
||||
// Init the colour/depth buffer settings to some random defaults on reset
|
||||
colourBufferLoc = 0;
|
||||
colourBufferFormat = ColourBuffer::Formats::RGBA8;
|
||||
colourBufferFormat = PICAColorFmt::RGBA8;
|
||||
|
||||
depthBufferLoc = 0;
|
||||
depthBufferFormat = DepthBuffer::Formats::Depth16;
|
||||
depthBufferFormat = PICADepthFmt::Depth16;
|
||||
|
||||
if (triangleProgram.exists()) {
|
||||
const auto oldProgram = OpenGL::getProgram();
|
||||
|
@ -264,7 +264,13 @@ void Renderer::setupBlending() {
|
|||
}
|
||||
}
|
||||
|
||||
void Renderer::drawVertices(OpenGL::Primitives primType, std::span<const Vertex> vertices) {
|
||||
void Renderer::drawVertices(PICAPrimType primType, std::span<const Vertex> vertices) {
|
||||
// The fourth type is meant to be "Geometry primitive". TODO: Find out what that is
|
||||
static constexpr std::array<OpenGL::Primitives, 4> primTypes = {
|
||||
OpenGL::Triangle, OpenGL::TriangleStrip, OpenGL::TriangleFan, OpenGL::Triangle
|
||||
};
|
||||
const auto primitiveTopology = primTypes[static_cast<usize>(primType)];
|
||||
|
||||
// Adjust alpha test if necessary
|
||||
const u32 alphaControl = regs[PICAInternalRegs::AlphaTestConfig];
|
||||
if (alphaControl != oldAlphaControl) {
|
||||
|
@ -352,7 +358,7 @@ void Renderer::drawVertices(OpenGL::Primitives primType, std::span<const Vertex>
|
|||
}
|
||||
|
||||
vbo.bufferVertsSub(vertices);
|
||||
OpenGL::draw(primType, vertices.size());
|
||||
OpenGL::draw(primitiveTopology, vertices.size());
|
||||
}
|
||||
|
||||
constexpr u32 topScreenBuffer = 0x1f000000;
|
||||
|
@ -423,8 +429,8 @@ void Renderer::bindDepthBuffer() {
|
|||
tex = depthBufferCache.add(sampleBuffer).texture.m_handle;
|
||||
}
|
||||
|
||||
if (DepthBuffer::Formats::Depth24Stencil8 != depthBufferFormat) Helpers::panic("TODO: Should we remove stencil attachment?");
|
||||
auto attachment = depthBufferFormat == DepthBuffer::Formats::Depth24Stencil8 ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT;
|
||||
if (PICADepthFmt::Depth24Stencil8 != depthBufferFormat) Helpers::panic("TODO: Should we remove stencil attachment?");
|
||||
auto attachment = depthBufferFormat == PICADepthFmt::Depth24Stencil8 ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT;
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, tex, 0);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue