Merge branch 'master' into nyom
This commit is contained in:
@@ -74,6 +74,9 @@ void GPU::reset() {
|
||||
lightingLUT.fill(0);
|
||||
lightingLUTDirty = true;
|
||||
|
||||
fogLUT.fill(0);
|
||||
fogLUTDirty = true;
|
||||
|
||||
totalAttribCount = 0;
|
||||
fixedAttribMask = 0;
|
||||
fixedAttribIndex = 0;
|
||||
|
||||
@@ -135,6 +135,21 @@ void GPU::writeInternalReg(u32 index, u32 value, u32 mask) {
|
||||
break;
|
||||
}
|
||||
|
||||
case FogLUTData0:
|
||||
case FogLUTData1:
|
||||
case FogLUTData2:
|
||||
case FogLUTData3:
|
||||
case FogLUTData4:
|
||||
case FogLUTData5:
|
||||
case FogLUTData6:
|
||||
case FogLUTData7: {
|
||||
const uint32_t index = regs[FogLUTIndex] & 0x7F;
|
||||
fogLUT[index] = value;
|
||||
fogLUTDirty = true;
|
||||
regs[FogLUTIndex] = (index + 1) & 0x7F;
|
||||
break;
|
||||
}
|
||||
|
||||
case LightingLUTData0:
|
||||
case LightingLUTData1:
|
||||
case LightingLUTData2:
|
||||
@@ -314,9 +329,11 @@ void GPU::writeInternalReg(u32 index, u32 value, u32 mask) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* TODO: Find out if this actually does anything
|
||||
case VertexShaderTransferEnd:
|
||||
if (value != 0) shaderUnit.vs.finalize();
|
||||
break;
|
||||
*/
|
||||
|
||||
case VertexShaderTransferIndex: shaderUnit.vs.setBufferIndex(value); break;
|
||||
|
||||
|
||||
@@ -130,7 +130,7 @@ std::string FragmentGenerator::generate(const FragmentConfig& config) {
|
||||
uniform sampler2D u_tex0;
|
||||
uniform sampler2D u_tex1;
|
||||
uniform sampler2D u_tex2;
|
||||
uniform sampler2D u_tex_lighting_lut;
|
||||
uniform sampler2D u_tex_luts;
|
||||
)";
|
||||
|
||||
ret += uniformDefinition;
|
||||
@@ -144,7 +144,7 @@ std::string FragmentGenerator::generate(const FragmentConfig& config) {
|
||||
}
|
||||
|
||||
float lutLookup(uint lut, int index) {
|
||||
return texelFetch(u_tex_lighting_lut, ivec2(index, int(lut)), 0).r;
|
||||
return texelFetch(u_tex_luts, ivec2(index, int(lut)), 0).r;
|
||||
}
|
||||
|
||||
vec3 regToColor(uint reg) {
|
||||
@@ -194,6 +194,8 @@ std::string FragmentGenerator::generate(const FragmentConfig& config) {
|
||||
compileTEV(ret, i, config);
|
||||
}
|
||||
|
||||
compileFog(ret, config);
|
||||
|
||||
applyAlphaTest(ret, config);
|
||||
|
||||
ret += "fragColor = combinerOutput;\n}"; // End of main function
|
||||
@@ -652,4 +654,27 @@ void FragmentGenerator::compileLUTLookup(std::string& shader, const PICA::Fragme
|
||||
shader += "lut_lookup_result *= " + std::to_string(scales[scale]) + ";\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FragmentGenerator::compileFog(std::string& shader, const PICA::FragmentConfig& config) {
|
||||
if (config.fogConfig.mode != FogMode::Fog) {
|
||||
return;
|
||||
}
|
||||
|
||||
float r = config.fogConfig.fogColorR / 255.0f;
|
||||
float g = config.fogConfig.fogColorG / 255.0f;
|
||||
float b = config.fogConfig.fogColorB / 255.0f;
|
||||
|
||||
if (config.fogConfig.flipDepth) {
|
||||
shader += "float fog_index = (1.0 - depth) * 128.0;\n";
|
||||
} else {
|
||||
shader += "float fog_index = depth * 128.0;\n";
|
||||
}
|
||||
|
||||
shader += "float clamped_index = clamp(floor(fog_index), 0.0, 127.0);";
|
||||
shader += "float delta = fog_index - clamped_index;";
|
||||
shader += "vec3 fog_color = vec3(" + std::to_string(r) + ", " + std::to_string(g) + ", " + std::to_string(b) + ");";
|
||||
shader += "vec2 value = texelFetch(u_tex_luts, ivec2(int(clamped_index), 24), 0).rg;"; // fog LUT is past the light LUTs
|
||||
shader += "float fog_factor = clamp(value.r + value.g * delta, 0.0, 1.0);";
|
||||
shader += "combinerOutput.rgb = mix(fog_color, combinerOutput.rgb, fog_factor);";
|
||||
}
|
||||
@@ -9,7 +9,6 @@ void ShaderUnit::reset() {
|
||||
|
||||
void PICAShader::reset() {
|
||||
loadedShader.fill(0);
|
||||
bufferedShader.fill(0);
|
||||
operandDescriptors.fill(0);
|
||||
|
||||
boolUniform = 0;
|
||||
|
||||
@@ -25,7 +25,6 @@ bool NCCH::loadFromHeader(Crypto::AESEngine &aesEngine, IOFile& file, const FSIn
|
||||
}
|
||||
|
||||
codeFile.clear();
|
||||
saveData.clear();
|
||||
smdh.clear();
|
||||
partitionInfo = info;
|
||||
|
||||
@@ -155,8 +154,7 @@ bool NCCH::loadFromHeader(Crypto::AESEngine &aesEngine, IOFile& file, const FSIn
|
||||
}
|
||||
}
|
||||
|
||||
const u64 saveDataSize = *(u64*)&exheader[0x1C0 + 0x0]; // Size of save data in bytes
|
||||
saveData.resize(saveDataSize, 0xff);
|
||||
saveDataSize = *(u64*)&exheader[0x1C0 + 0x0]; // Size of save data in bytes
|
||||
|
||||
compressCode = (exheader[0xD] & 1) != 0;
|
||||
stackSize = *(u32*)&exheader[0x1C];
|
||||
|
||||
@@ -115,10 +115,11 @@ void RendererGL::initGraphicsContextInternal() {
|
||||
const u32 screenTextureWidth = 400; // Top screen is 400 pixels wide, bottom is 320
|
||||
const u32 screenTextureHeight = 2 * 240; // Both screens are 240 pixels tall
|
||||
|
||||
lightLUTTexture.create(256, Lights::LUT_Count, GL_R32F);
|
||||
lightLUTTexture.bind();
|
||||
lightLUTTexture.setMinFilter(OpenGL::Linear);
|
||||
lightLUTTexture.setMagFilter(OpenGL::Linear);
|
||||
// 24 rows for light, 1 for fog
|
||||
LUTTexture.create(256, Lights::LUT_Count + 1, GL_RG32F);
|
||||
LUTTexture.bind();
|
||||
LUTTexture.setMinFilter(OpenGL::Linear);
|
||||
LUTTexture.setMagFilter(OpenGL::Linear);
|
||||
|
||||
auto prevTexture = OpenGL::getTex2D();
|
||||
|
||||
@@ -353,22 +354,49 @@ void RendererGL::bindTexturesToSlots() {
|
||||
}
|
||||
|
||||
glActiveTexture(GL_TEXTURE0 + 3);
|
||||
lightLUTTexture.bind();
|
||||
LUTTexture.bind();
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
}
|
||||
|
||||
void RendererGL::updateLightingLUT() {
|
||||
gpu.lightingLUTDirty = false;
|
||||
std::array<float, GPU::LightingLutSize> lightingLut;
|
||||
std::array<float, GPU::LightingLutSize * 2> lightingLut;
|
||||
|
||||
for (int i = 0; i < gpu.lightingLUT.size(); i++) {
|
||||
uint64_t value = gpu.lightingLUT[i] & 0xFFF;
|
||||
for (int i = 0; i < lightingLut.size(); i += 2) {
|
||||
uint64_t value = gpu.lightingLUT[i >> 1] & 0xFFF;
|
||||
lightingLut[i] = (float)(value << 4) / 65535.0f;
|
||||
}
|
||||
|
||||
glActiveTexture(GL_TEXTURE0 + 3);
|
||||
lightLUTTexture.bind();
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 256, Lights::LUT_Count, GL_RED, GL_FLOAT, lightingLut.data());
|
||||
LUTTexture.bind();
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 256, Lights::LUT_Count, GL_RG, GL_FLOAT, lightingLut.data());
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
}
|
||||
|
||||
void RendererGL::updateFogLUT() {
|
||||
gpu.fogLUTDirty = false;
|
||||
|
||||
// Fog LUT elements are of this type:
|
||||
// 0-12 fixed1.1.11, Difference from next element
|
||||
// 13-23 fixed0.0.11, Value
|
||||
// We will store them as a 128x1 RG texture with R being the value and G being the difference
|
||||
std::array<float, 128 * 2> fogLut;
|
||||
|
||||
for (int i = 0; i < fogLut.size(); i += 2) {
|
||||
const uint32_t value = gpu.fogLUT[i >> 1];
|
||||
int32_t diff = value & 0x1fff;
|
||||
diff = (diff << 19) >> 19; // Sign extend the 13-bit value to 32 bits
|
||||
const float fogDifference = float(diff) / 2048.0f;
|
||||
const float fogValue = float((value >> 13) & 0x7ff) / 2048.0f;
|
||||
|
||||
fogLut[i] = fogValue;
|
||||
fogLut[i + 1] = fogDifference;
|
||||
}
|
||||
|
||||
glActiveTexture(GL_TEXTURE0 + 3);
|
||||
LUTTexture.bind();
|
||||
// The fog LUT exists at the end of the lighting LUT
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, Lights::LUT_Count, 128, 1, GL_RG, GL_FLOAT, fogLut.data());
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
}
|
||||
|
||||
@@ -453,6 +481,10 @@ void RendererGL::drawVertices(PICA::PrimType primType, std::span<const Vertex> v
|
||||
|
||||
bindTexturesToSlots();
|
||||
|
||||
if (gpu.fogLUTDirty) {
|
||||
updateFogLUT();
|
||||
}
|
||||
|
||||
if (gpu.lightingLUTDirty) {
|
||||
updateLightingLUT();
|
||||
}
|
||||
@@ -499,7 +531,6 @@ void RendererGL::display() {
|
||||
gl.disableScissor();
|
||||
gl.disableBlend();
|
||||
gl.disableDepth();
|
||||
gl.disableScissor();
|
||||
// This will work fine whether or not logic ops are enabled. We set logic op to copy instead of disabling to avoid state changes
|
||||
gl.setLogicOp(GL_COPY);
|
||||
gl.setColourMask(true, true, true, true);
|
||||
@@ -811,7 +842,7 @@ OpenGL::Program& RendererGL::getSpecializedShader() {
|
||||
glUniform1i(OpenGL::uniformLocation(program, "u_tex0"), 0);
|
||||
glUniform1i(OpenGL::uniformLocation(program, "u_tex1"), 1);
|
||||
glUniform1i(OpenGL::uniformLocation(program, "u_tex2"), 2);
|
||||
glUniform1i(OpenGL::uniformLocation(program, "u_tex_lighting_lut"), 3);
|
||||
glUniform1i(OpenGL::uniformLocation(program, "u_tex_luts"), 3);
|
||||
|
||||
// Allocate memory for the program UBO
|
||||
glGenBuffers(1, &programEntry.uboBinding);
|
||||
@@ -994,9 +1025,9 @@ void RendererGL::initUbershader(OpenGL::Program& program) {
|
||||
ubershaderData.depthmapEnableLoc = OpenGL::uniformLocation(program, "u_depthmapEnable");
|
||||
ubershaderData.picaRegLoc = OpenGL::uniformLocation(program, "u_picaRegs");
|
||||
|
||||
// Init sampler objects. Texture 0 goes in texture unit 0, texture 1 in TU 1, texture 2 in TU 2, and the light maps go in TU 3
|
||||
// Init sampler objects. Texture 0 goes in texture unit 0, texture 1 in TU 1, texture 2 in TU 2 and the LUTs go in TU 3
|
||||
glUniform1i(OpenGL::uniformLocation(program, "u_tex0"), 0);
|
||||
glUniform1i(OpenGL::uniformLocation(program, "u_tex1"), 1);
|
||||
glUniform1i(OpenGL::uniformLocation(program, "u_tex2"), 2);
|
||||
glUniform1i(OpenGL::uniformLocation(program, "u_tex_lighting_lut"), 3);
|
||||
glUniform1i(OpenGL::uniformLocation(program, "u_tex_luts"), 3);
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ uniform bool u_depthmapEnable;
|
||||
uniform sampler2D u_tex0;
|
||||
uniform sampler2D u_tex1;
|
||||
uniform sampler2D u_tex2;
|
||||
uniform sampler2D u_tex_lighting_lut;
|
||||
uniform sampler2D u_tex_luts;
|
||||
|
||||
uniform uint u_picaRegs[0x200 - 0x48];
|
||||
|
||||
@@ -152,6 +152,8 @@ vec4 tevCalculateCombiner(int tev_id) {
|
||||
#define RG_LUT 5u
|
||||
#define RR_LUT 6u
|
||||
|
||||
#define FOG_INDEX 24
|
||||
|
||||
uint GPUREG_LIGHTi_CONFIG;
|
||||
uint GPUREG_LIGHTING_CONFIG1;
|
||||
uint GPUREG_LIGHTING_LUTINPUT_SELECT;
|
||||
@@ -161,7 +163,7 @@ bool error_unimpl = false;
|
||||
vec4 unimpl_color = vec4(1.0, 0.0, 1.0, 1.0);
|
||||
|
||||
float lutLookup(uint lut, int index) {
|
||||
return texelFetch(u_tex_lighting_lut, ivec2(index, int(lut)), 0).r;
|
||||
return texelFetch(u_tex_luts, ivec2(index, int(lut)), 0).r;
|
||||
}
|
||||
|
||||
vec3 regToColor(uint reg) {
|
||||
@@ -494,7 +496,7 @@ void main() {
|
||||
if (tevUnimplementedSourceFlag) {
|
||||
// fragColour = vec4(1.0, 0.0, 1.0, 1.0);
|
||||
}
|
||||
// fragColour.rg = texture(u_tex_lighting_lut,vec2(gl_FragCoord.x/200.,float(int(gl_FragCoord.y/2)%24))).rr;
|
||||
// fragColour.rg = texture(u_tex_luts,vec2(gl_FragCoord.x/200.,float(int(gl_FragCoord.y/2)%24))).rr;
|
||||
|
||||
// Get original depth value by converting from [near, far] = [0, 1] to [-1, 1]
|
||||
// We do this by converting to [0, 2] first and subtracting 1 to go to [-1, 1]
|
||||
@@ -507,6 +509,28 @@ void main() {
|
||||
// Write final fragment depth
|
||||
gl_FragDepth = depth;
|
||||
|
||||
bool enable_fog = (textureEnvUpdateBuffer & 7u) == 5u;
|
||||
|
||||
if (enable_fog) {
|
||||
bool flip_depth = (textureEnvUpdateBuffer & (1u << 16)) != 0u;
|
||||
float fog_index = flip_depth ? 1.0 - depth : depth;
|
||||
fog_index *= 128.0;
|
||||
float clamped_index = clamp(floor(fog_index), 0.0, 127.0);
|
||||
float delta = fog_index - clamped_index;
|
||||
vec2 value = texelFetch(u_tex_luts, ivec2(int(clamped_index), FOG_INDEX), 0).rg;
|
||||
float fog_factor = clamp(value.r + value.g * delta, 0.0, 1.0);
|
||||
|
||||
uint GPUREG_FOG_COLOR = readPicaReg(0x00E1u);
|
||||
|
||||
// Annoyingly color is not encoded in the same way as light color
|
||||
float r = (GPUREG_FOG_COLOR & 0xFFu) / 255.0;
|
||||
float g = ((GPUREG_FOG_COLOR >> 8) & 0xFFu) / 255.0;
|
||||
float b = ((GPUREG_FOG_COLOR >> 16) & 0xFFu) / 255.0;
|
||||
vec3 fog_color = vec3(r, g, b);
|
||||
|
||||
fragColour.rgb = mix(fog_color, fragColour.rgb, fog_factor);
|
||||
}
|
||||
|
||||
// Perform alpha test
|
||||
uint alphaControl = readPicaReg(0x104u);
|
||||
if ((alphaControl & 1u) != 0u) { // Check if alpha test is on
|
||||
|
||||
Reference in New Issue
Block a user