mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-04-11 08:39:48 +12:00
[GPU] Implement initial support for multi-texturing
This commit is contained in:
parent
170fe9a4b2
commit
9b1ed2084f
3 changed files with 72 additions and 19 deletions
|
@ -2,6 +2,7 @@
|
|||
#include <array>
|
||||
#include <span>
|
||||
|
||||
#include "PICA/float_types.hpp"
|
||||
#include "helpers.hpp"
|
||||
#include "logger.hpp"
|
||||
#include "opengl.hpp"
|
||||
|
@ -14,7 +15,11 @@ class GPU;
|
|||
struct Vertex {
|
||||
OpenGL::vec4 position;
|
||||
OpenGL::vec4 colour;
|
||||
OpenGL::vec2 UVs;
|
||||
OpenGL::vec2 texcoord0;
|
||||
OpenGL::vec2 texcoord1;
|
||||
Floats::f24 texcoord0_w;
|
||||
u32 padding; // pad so that texcoord2 is 64-bit aligned
|
||||
OpenGL::vec2 texcoord2;
|
||||
};
|
||||
|
||||
class Renderer {
|
||||
|
|
|
@ -247,7 +247,10 @@ void GPU::drawArrays() {
|
|||
|
||||
std::memcpy(&vertices[i].position, &out.s.positions, sizeof(vec4f));
|
||||
std::memcpy(&vertices[i].colour, &out.s.colour, sizeof(vec4f));
|
||||
std::memcpy(&vertices[i].UVs, &out.s.texcoord0, 2 * sizeof(f24));
|
||||
std::memcpy(&vertices[i].texcoord0, &out.s.texcoord0, 2 * sizeof(f24));
|
||||
std::memcpy(&vertices[i].texcoord1, &out.s.texcoord1, 2 * sizeof(f24));
|
||||
std::memcpy(&vertices[i].texcoord0_w, &out.s.texcoord0_w, sizeof(f24));
|
||||
std::memcpy(&vertices[i].texcoord2, &out.s.texcoord2, 2 * sizeof(f24));
|
||||
|
||||
//printf("(x, y, z, w) = (%f, %f, %f, %f)\n", (double)vertices[i].position.x(), (double)vertices[i].position.y(), (double)vertices[i].position.z(), (double)vertices[i].position.w());
|
||||
//printf("(r, g, b, a) = (%f, %f, %f, %f)\n", (double)vertices[i].colour.r(), (double)vertices[i].colour.g(), (double)vertices[i].colour.b(), (double)vertices[i].colour.a());
|
||||
|
@ -275,11 +278,11 @@ Vertex GPU::getImmediateModeVertex() {
|
|||
shaderUnit.vs.run();
|
||||
std::memcpy(&v.position, &shaderUnit.vs.outputs[0], sizeof(vec4f));
|
||||
std::memcpy(&v.colour, &shaderUnit.vs.outputs[1], sizeof(vec4f));
|
||||
std::memcpy(&v.UVs, &shaderUnit.vs.outputs[2], 2 * sizeof(f24));
|
||||
std::memcpy(&v.texcoord0, &shaderUnit.vs.outputs[2], 2 * sizeof(f24));
|
||||
|
||||
printf("(x, y, z, w) = (%f, %f, %f, %f)\n", (double)v.position.x(), (double)v.position.y(), (double)v.position.z(), (double)v.position.w());
|
||||
printf("(r, g, b, a) = (%f, %f, %f, %f)\n", (double)v.colour.r(), (double)v.colour.g(), (double)v.colour.b(), (double)v.colour.a());
|
||||
printf("(u, v ) = (%f, %f)\n", v.UVs.u(), v.UVs.v());
|
||||
printf("(u, v ) = (%f, %f)\n", v.texcoord0.u(), v.texcoord0.v());
|
||||
|
||||
return v;
|
||||
}
|
||||
|
|
|
@ -13,17 +13,24 @@ const char* vertexShader = R"(
|
|||
|
||||
layout (location = 0) in vec4 coords;
|
||||
layout (location = 1) in vec4 vertexColour;
|
||||
layout (location = 2) in vec2 inUVs_texture0;
|
||||
layout (location = 2) in vec2 in_texcoord0;
|
||||
layout (location = 3) in vec2 in_texcoord1;
|
||||
layout (location = 4) in float in_texcoord0_w;
|
||||
layout (location = 5) in vec2 in_texcoord2;
|
||||
|
||||
out vec4 colour;
|
||||
out vec2 tex0_UVs;
|
||||
out vec3 texcoord0;
|
||||
out vec2 texcoord1;
|
||||
out vec2 texcoord2;
|
||||
|
||||
void main() {
|
||||
gl_Position = coords;
|
||||
colour = vertexColour;
|
||||
|
||||
// Flip y axis of UVs because OpenGL uses an inverted y for texture sampling compared to the PICA
|
||||
tex0_UVs = vec2(inUVs_texture0.x, 1.0 - inUVs_texture0.y);
|
||||
texcoord0 = vec3(in_texcoord0.x, 1.0 - in_texcoord0.y, in_texcoord0_w);
|
||||
texcoord1 = vec2(in_texcoord1.x, 1.0 - in_texcoord1.y);
|
||||
texcoord2 = vec2(in_texcoord2.x, 1.0 - in_texcoord2.y);
|
||||
}
|
||||
)";
|
||||
|
||||
|
@ -31,7 +38,9 @@ const char* fragmentShader = R"(
|
|||
#version 410 core
|
||||
|
||||
in vec4 colour;
|
||||
in vec2 tex0_UVs;
|
||||
in vec3 texcoord0;
|
||||
in vec2 texcoord1;
|
||||
in vec2 texcoord2;
|
||||
|
||||
out vec4 fragColour;
|
||||
|
||||
|
@ -53,6 +62,8 @@ const char* fragmentShader = R"(
|
|||
uniform bool u_depthmapEnable;
|
||||
|
||||
uniform sampler2D u_tex0;
|
||||
uniform sampler2D u_tex1;
|
||||
uniform sampler2D u_tex2;
|
||||
|
||||
// TODO: figure out the color that is returned to the TEVs when reading from a disabled texture slot.
|
||||
vec4 tev_texture_sources[4] = vec4[](vec4(0.0), vec4(0.0), vec4(0.0), vec4(0.0));
|
||||
|
@ -76,6 +87,8 @@ const char* fragmentShader = R"(
|
|||
switch (rgb_source) {
|
||||
case 0u: source.rgb = colour.rgb; break; // Primary color, TODO: confirm that this is correct
|
||||
case 3u: source.rgb = tev_texture_sources[0].rgb; break; // Texture 0
|
||||
case 4u: source.rgb = tev_texture_sources[1].rgb; break; // Texture 1
|
||||
case 5u: source.rgb = tev_texture_sources[2].rgb; break; // Texture 2
|
||||
case 13u: source.rgb = tev_previous_buffer[0].rgb; break; // Previous buffer
|
||||
case 14u: source.rgb = u_textureEnvColor[tev_id].rgb; break; // Constant (GPUREG_TEXENVi_COLOR)
|
||||
case 15u: source.rgb = tev_previous.rgb; break; // Previous (output from TEV #n-1)
|
||||
|
@ -85,6 +98,8 @@ const char* fragmentShader = R"(
|
|||
switch (alpha_source) {
|
||||
case 0u: source.a = colour.a; break; // Primary color, TODO: confirm that this is correct
|
||||
case 3u: source.a = tev_texture_sources[0].a; break; // Texture 0
|
||||
case 4u: source.a = tev_texture_sources[1].a; break; // Texture 1
|
||||
case 5u: source.a = tev_texture_sources[2].a; break; // Texture 2
|
||||
case 13u: source.a = tev_previous_buffer[0].a; break; // Previous buffer
|
||||
case 14u: source.a = u_textureEnvColor[tev_id].a; break; // Constant (GPUREG_TEXENVi_COLOR)
|
||||
case 15u: source.a = tev_previous.a; break; // Previous (output from TEV #n-1)
|
||||
|
@ -172,7 +187,11 @@ const char* fragmentShader = R"(
|
|||
}
|
||||
|
||||
void main() {
|
||||
if ((u_textureConfig & 1u) != 0u) tev_texture_sources[0] = texture(u_tex0, tex0_UVs);
|
||||
vec2 tex2_uv = (u_textureConfig & (1 << 13)) != 0u ? texcoord1 : texcoord2;
|
||||
|
||||
if ((u_textureConfig & 1u) != 0u) tev_texture_sources[0] = texture(u_tex0, texcoord0.xy);
|
||||
if ((u_textureConfig & 2u) != 0u) tev_texture_sources[1] = texture(u_tex1, texcoord1);
|
||||
if ((u_textureConfig & 4u) != 0u) tev_texture_sources[2] = texture(u_tex2, tex2_uv);
|
||||
|
||||
tev_previous_buffer[0] = vec4(0.0);
|
||||
tev_previous_buffer[1] = u_textureEnvBufferColor;
|
||||
|
@ -196,7 +215,7 @@ const char* fragmentShader = R"(
|
|||
fragColour = tev_previous;
|
||||
|
||||
if (tev_unimplemented_source) {
|
||||
// fragColour = vec4(1.0, 0.0, 1.0, 1.0);
|
||||
// fragColour = vec4(1.0, 0.0, 1.0, 1.0);
|
||||
}
|
||||
|
||||
// Get original depth value by converting from [near, far] = [0, 1] to [-1, 1]
|
||||
|
@ -337,7 +356,11 @@ void Renderer::initGraphicsContext() {
|
|||
depthScaleLoc = OpenGL::uniformLocation(triangleProgram, "u_depthScale");
|
||||
depthOffsetLoc = OpenGL::uniformLocation(triangleProgram, "u_depthOffset");
|
||||
depthmapEnableLoc = OpenGL::uniformLocation(triangleProgram, "u_depthmapEnable");
|
||||
glUniform1i(OpenGL::uniformLocation(triangleProgram, "u_tex0"), 0); // Init sampler object
|
||||
|
||||
// Init sampler objects
|
||||
glUniform1i(OpenGL::uniformLocation(triangleProgram, "u_tex0"), 0);
|
||||
glUniform1i(OpenGL::uniformLocation(triangleProgram, "u_tex1"), 1);
|
||||
glUniform1i(OpenGL::uniformLocation(triangleProgram, "u_tex2"), 2);
|
||||
|
||||
OpenGL::Shader vertDisplay(displayVertexShader, OpenGL::Vertex);
|
||||
OpenGL::Shader fragDisplay(displayFragmentShader, OpenGL::Fragment);
|
||||
|
@ -357,9 +380,18 @@ void Renderer::initGraphicsContext() {
|
|||
// Colour attribute
|
||||
vao.setAttributeFloat<float>(1, 4, sizeof(Vertex), offsetof(Vertex, colour));
|
||||
vao.enableAttribute(1);
|
||||
// UV attribute
|
||||
vao.setAttributeFloat<float>(2, 2, sizeof(Vertex), offsetof(Vertex, UVs));
|
||||
// UV 0 attribute
|
||||
vao.setAttributeFloat<float>(2, 2, sizeof(Vertex), offsetof(Vertex, texcoord0));
|
||||
vao.enableAttribute(2);
|
||||
// UV 1 attribute
|
||||
vao.setAttributeFloat<float>(3, 2, sizeof(Vertex), offsetof(Vertex, texcoord1));
|
||||
vao.enableAttribute(3);
|
||||
// UV 0 W-component attribute
|
||||
vao.setAttributeFloat<float>(4, 1, sizeof(Vertex), offsetof(Vertex, texcoord0_w));
|
||||
vao.enableAttribute(4);
|
||||
// UV 2 attribute
|
||||
vao.setAttributeFloat<float>(5, 2, sizeof(Vertex), offsetof(Vertex, texcoord2));
|
||||
vao.enableAttribute(5);
|
||||
|
||||
dummyVBO.create();
|
||||
dummyVAO.create();
|
||||
|
@ -535,20 +567,33 @@ void Renderer::drawVertices(OpenGL::Primitives primType, std::span<const Vertex>
|
|||
|
||||
setupTextureEnvState();
|
||||
|
||||
// Hack for rendering texture 1
|
||||
if (regs[0x80] & 1) {
|
||||
const u32 dim = regs[0x82];
|
||||
const u32 config = regs[0x83];
|
||||
// Bind textures 0 to 2
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if ((regs[0x80] & (1 << i)) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
static constexpr std::array<u32, 3> ioBases = {
|
||||
0x80, 0x90, 0x98
|
||||
};
|
||||
|
||||
const size_t ioBase = ioBases[i];
|
||||
|
||||
const u32 dim = regs[ioBase + 2];
|
||||
const u32 config = regs[ioBase + 3];
|
||||
const u32 height = dim & 0x7ff;
|
||||
const u32 width = getBits<16, 11>(dim);
|
||||
const u32 addr = (regs[0x85] & 0x0FFFFFFF) << 3;
|
||||
const u32 format = regs[0x8E] & 0xF;
|
||||
const u32 addr = (regs[ioBase + 5] & 0x0FFFFFFF) << 3;
|
||||
u32 format = regs[ioBase + (i == 0 ? 14 : 6)] & 0xF;
|
||||
|
||||
glActiveTexture(GL_TEXTURE0 + i);
|
||||
Texture targetTex(addr, static_cast<Texture::Formats>(format), width, height, config);
|
||||
OpenGL::Texture tex = getTexture(targetTex);
|
||||
tex.bind();
|
||||
}
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
// Update the texture unit configuration uniform if it changed
|
||||
const u32 texUnitConfig = regs[PICAInternalRegs::TexUnitCfg];
|
||||
if (oldTexUnitConfig != texUnitConfig) {
|
||||
|
|
Loading…
Add table
Reference in a new issue