mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-04-07 22:55:40 +12:00
Merge branch 'master' into nyom
This commit is contained in:
commit
a5ea268826
17 changed files with 188 additions and 46 deletions
24
.github/gles.patch
vendored
24
.github/gles.patch
vendored
|
@ -21,7 +21,7 @@ index 990e2f80..2e7842ac 100644
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
diff --git a/src/host_shaders/opengl_fragment_shader.frag b/src/host_shaders/opengl_fragment_shader.frag
|
diff --git a/src/host_shaders/opengl_fragment_shader.frag b/src/host_shaders/opengl_fragment_shader.frag
|
||||||
index 9f369e39..b4bb19d3 100644
|
index b9f9fe4c..f1cf286f 100644
|
||||||
--- a/src/host_shaders/opengl_fragment_shader.frag
|
--- a/src/host_shaders/opengl_fragment_shader.frag
|
||||||
+++ b/src/host_shaders/opengl_fragment_shader.frag
|
+++ b/src/host_shaders/opengl_fragment_shader.frag
|
||||||
@@ -1,4 +1,5 @@
|
@@ -1,4 +1,5 @@
|
||||||
|
@ -31,8 +31,8 @@ index 9f369e39..b4bb19d3 100644
|
||||||
|
|
||||||
in vec4 v_quaternion;
|
in vec4 v_quaternion;
|
||||||
in vec4 v_colour;
|
in vec4 v_colour;
|
||||||
@@ -164,11 +165,17 @@ float lutLookup(uint lut, int index) {
|
@@ -166,11 +167,17 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
+// some gles versions have bitfieldExtractCompat and complain if you redefine it, some don't and compile error, using this instead
|
+// some gles versions have bitfieldExtractCompat and complain if you redefine it, some don't and compile error, using this instead
|
||||||
|
@ -50,7 +50,7 @@ index 9f369e39..b4bb19d3 100644
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert an arbitrary-width floating point literal to an f32
|
// Convert an arbitrary-width floating point literal to an f32
|
||||||
@@ -208,16 +215,16 @@ float lightLutLookup(uint environment_id, uint lut_id, uint light_id, vec3 light
|
@@ -210,16 +217,16 @@ float lightLutLookup(uint environment_id, uint lut_id, uint light_id, vec3 light
|
||||||
|
|
||||||
bool current_sampler_enabled = isSamplerEnabled(environment_id, lut_id); // 7 luts per environment
|
bool current_sampler_enabled = isSamplerEnabled(environment_id, lut_id); // 7 luts per environment
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ index 9f369e39..b4bb19d3 100644
|
||||||
switch (input_id) {
|
switch (input_id) {
|
||||||
case 0u: {
|
case 0u: {
|
||||||
delta = dot(normal, normalize(half_vector));
|
delta = dot(normal, normalize(half_vector));
|
||||||
@@ -239,11 +246,11 @@ float lightLutLookup(uint environment_id, uint lut_id, uint light_id, vec3 light
|
@@ -241,11 +248,11 @@ float lightLutLookup(uint environment_id, uint lut_id, uint light_id, vec3 light
|
||||||
int GPUREG_LIGHTi_SPOTDIR_LOW = int(readPicaReg(0x0146u + (light_id << 4u)));
|
int GPUREG_LIGHTi_SPOTDIR_LOW = int(readPicaReg(0x0146u + (light_id << 4u)));
|
||||||
int GPUREG_LIGHTi_SPOTDIR_HIGH = int(readPicaReg(0x0147u + (light_id << 4u)));
|
int GPUREG_LIGHTi_SPOTDIR_HIGH = int(readPicaReg(0x0147u + (light_id << 4u)));
|
||||||
|
|
||||||
|
@ -86,7 +86,7 @@ index 9f369e39..b4bb19d3 100644
|
||||||
|
|
||||||
if ((se_x & 0x1000) == 0x1000) se_x |= 0xffffe000;
|
if ((se_x & 0x1000) == 0x1000) se_x |= 0xffffe000;
|
||||||
if ((se_y & 0x1000) == 0x1000) se_y |= 0xffffe000;
|
if ((se_y & 0x1000) == 0x1000) se_y |= 0xffffe000;
|
||||||
@@ -270,9 +277,9 @@ float lightLutLookup(uint environment_id, uint lut_id, uint light_id, vec3 light
|
@@ -272,9 +279,9 @@ float lightLutLookup(uint environment_id, uint lut_id, uint light_id, vec3 light
|
||||||
}
|
}
|
||||||
|
|
||||||
// 0 = enabled
|
// 0 = enabled
|
||||||
|
@ -98,7 +98,7 @@ index 9f369e39..b4bb19d3 100644
|
||||||
delta = max(delta, 0.0);
|
delta = max(delta, 0.0);
|
||||||
} else {
|
} else {
|
||||||
delta = abs(delta);
|
delta = abs(delta);
|
||||||
@@ -296,7 +303,7 @@ vec3 rotateVec3ByQuaternion(vec3 v, vec4 q) {
|
@@ -298,7 +305,7 @@ vec3 rotateVec3ByQuaternion(vec3 v, vec4 q) {
|
||||||
// Implements the following algorthm: https://mathb.in/26766
|
// Implements the following algorthm: https://mathb.in/26766
|
||||||
void calcLighting(out vec4 primary_color, out vec4 secondary_color) {
|
void calcLighting(out vec4 primary_color, out vec4 secondary_color) {
|
||||||
uint GPUREG_LIGHTING_ENABLE = readPicaReg(0x008Fu);
|
uint GPUREG_LIGHTING_ENABLE = readPicaReg(0x008Fu);
|
||||||
|
@ -107,7 +107,7 @@ index 9f369e39..b4bb19d3 100644
|
||||||
primary_color = secondary_color = vec4(0.0);
|
primary_color = secondary_color = vec4(0.0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -313,7 +320,7 @@ void calcLighting(out vec4 primary_color, out vec4 secondary_color) {
|
@@ -315,7 +322,7 @@ void calcLighting(out vec4 primary_color, out vec4 secondary_color) {
|
||||||
GPUREG_LIGHTING_LUTINPUT_ABS = readPicaReg(0x01D0u);
|
GPUREG_LIGHTING_LUTINPUT_ABS = readPicaReg(0x01D0u);
|
||||||
GPUREG_LIGHTING_LUTINPUT_SELECT = readPicaReg(0x01D1u);
|
GPUREG_LIGHTING_LUTINPUT_SELECT = readPicaReg(0x01D1u);
|
||||||
|
|
||||||
|
@ -116,7 +116,7 @@ index 9f369e39..b4bb19d3 100644
|
||||||
|
|
||||||
// Bump mode is ignored for now because it breaks some games ie. Toad Treasure Tracker
|
// Bump mode is ignored for now because it breaks some games ie. Toad Treasure Tracker
|
||||||
switch (bump_mode) {
|
switch (bump_mode) {
|
||||||
@@ -326,15 +333,15 @@ void calcLighting(out vec4 primary_color, out vec4 secondary_color) {
|
@@ -328,15 +335,15 @@ void calcLighting(out vec4 primary_color, out vec4 secondary_color) {
|
||||||
vec4 diffuse_sum = vec4(0.0, 0.0, 0.0, 1.0);
|
vec4 diffuse_sum = vec4(0.0, 0.0, 0.0, 1.0);
|
||||||
vec4 specular_sum = vec4(0.0, 0.0, 0.0, 1.0);
|
vec4 specular_sum = vec4(0.0, 0.0, 0.0, 1.0);
|
||||||
|
|
||||||
|
@ -135,7 +135,7 @@ index 9f369e39..b4bb19d3 100644
|
||||||
|
|
||||||
uint GPUREG_LIGHTi_SPECULAR0 = readPicaReg(0x0140u + (light_id << 4u));
|
uint GPUREG_LIGHTi_SPECULAR0 = readPicaReg(0x0140u + (light_id << 4u));
|
||||||
uint GPUREG_LIGHTi_SPECULAR1 = readPicaReg(0x0141u + (light_id << 4u));
|
uint GPUREG_LIGHTi_SPECULAR1 = readPicaReg(0x0141u + (light_id << 4u));
|
||||||
@@ -346,12 +353,12 @@ void calcLighting(out vec4 primary_color, out vec4 secondary_color) {
|
@@ -348,12 +355,12 @@ void calcLighting(out vec4 primary_color, out vec4 secondary_color) {
|
||||||
|
|
||||||
float light_distance;
|
float light_distance;
|
||||||
vec3 light_position = vec3(
|
vec3 light_position = vec3(
|
||||||
|
@ -151,7 +151,7 @@ index 9f369e39..b4bb19d3 100644
|
||||||
light_vector = light_position + v_view;
|
light_vector = light_position + v_view;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -367,23 +374,23 @@ void calcLighting(out vec4 primary_color, out vec4 secondary_color) {
|
@@ -369,23 +376,23 @@ void calcLighting(out vec4 primary_color, out vec4 secondary_color) {
|
||||||
float NdotL = dot(normal, light_vector); // N dot Li
|
float NdotL = dot(normal, light_vector); // N dot Li
|
||||||
|
|
||||||
// Two sided diffuse
|
// Two sided diffuse
|
||||||
|
@ -181,7 +181,7 @@ index 9f369e39..b4bb19d3 100644
|
||||||
|
|
||||||
float distance_attenuation_bias = decodeFP(GPUREG_LIGHTi_ATTENUATION_BIAS, 7u, 12u);
|
float distance_attenuation_bias = decodeFP(GPUREG_LIGHTi_ATTENUATION_BIAS, 7u, 12u);
|
||||||
float distance_attenuation_scale = decodeFP(GPUREG_LIGHTi_ATTENUATION_SCALE, 7u, 12u);
|
float distance_attenuation_scale = decodeFP(GPUREG_LIGHTi_ATTENUATION_SCALE, 7u, 12u);
|
||||||
@@ -428,8 +435,8 @@ void calcLighting(out vec4 primary_color, out vec4 secondary_color) {
|
@@ -430,8 +437,8 @@ void calcLighting(out vec4 primary_color, out vec4 secondary_color) {
|
||||||
specular_sum.rgb += light_factor * clamp_factor * (specular0 + specular1);
|
specular_sum.rgb += light_factor * clamp_factor * (specular0 + specular1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,10 @@ if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-format-nonliteral -Wno-format-security")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-format-nonliteral -Wno-format-security")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-interference-size")
|
||||||
|
endif()
|
||||||
|
|
||||||
option(DISABLE_PANIC_DEV "Make a build with fewer and less intrusive asserts" ON)
|
option(DISABLE_PANIC_DEV "Make a build with fewer and less intrusive asserts" ON)
|
||||||
option(GPU_DEBUG_INFO "Enable additional GPU debugging info" OFF)
|
option(GPU_DEBUG_INFO "Enable additional GPU debugging info" OFF)
|
||||||
option(ENABLE_OPENGL "Enable OpenGL rendering backend" ON)
|
option(ENABLE_OPENGL "Enable OpenGL rendering backend" ON)
|
||||||
|
|
|
@ -56,7 +56,7 @@ lut_id is one of these values
|
||||||
6 RR
|
6 RR
|
||||||
|
|
||||||
lut_index on the other hand represents the actual index of the LUT in the texture
|
lut_index on the other hand represents the actual index of the LUT in the texture
|
||||||
u_tex_lighting_lut has 24 LUTs and they are used like so:
|
u_tex_luts has 24 LUTs for lighting and they are used like so:
|
||||||
0 D0
|
0 D0
|
||||||
1 D1
|
1 D1
|
||||||
2 is missing because SP uses LUTs 8-15
|
2 is missing because SP uses LUTs 8-15
|
||||||
|
|
|
@ -92,6 +92,9 @@ class GPU {
|
||||||
// Set to false by the renderer when the lighting_lut is uploaded ot the GPU
|
// Set to false by the renderer when the lighting_lut is uploaded ot the GPU
|
||||||
bool lightingLUTDirty = false;
|
bool lightingLUTDirty = false;
|
||||||
|
|
||||||
|
bool fogLUTDirty = false;
|
||||||
|
std::array<uint32_t, 128> fogLUT;
|
||||||
|
|
||||||
GPU(Memory& mem, EmulatorConfig& config);
|
GPU(Memory& mem, EmulatorConfig& config);
|
||||||
void display() { renderer->display(); }
|
void display() { renderer->display(); }
|
||||||
void screenshot(const std::string& name) { renderer->screenshot(name); }
|
void screenshot(const std::string& name) { renderer->screenshot(name); }
|
||||||
|
|
|
@ -29,6 +29,18 @@ namespace PICA {
|
||||||
std::array<u32, 4 * 6> tevConfigs;
|
std::array<u32, 4 * 6> tevConfigs;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct FogConfig {
|
||||||
|
union {
|
||||||
|
u32 raw{};
|
||||||
|
|
||||||
|
BitField<0, 3, FogMode> mode;
|
||||||
|
BitField<3, 1, u32> flipDepth;
|
||||||
|
BitField<8, 8, u32> fogColorR;
|
||||||
|
BitField<16, 8, u32> fogColorG;
|
||||||
|
BitField<24, 8, u32> fogColorB;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
struct Light {
|
struct Light {
|
||||||
union {
|
union {
|
||||||
u16 raw;
|
u16 raw;
|
||||||
|
@ -189,6 +201,7 @@ namespace PICA {
|
||||||
struct FragmentConfig {
|
struct FragmentConfig {
|
||||||
OutputConfig outConfig;
|
OutputConfig outConfig;
|
||||||
TextureConfig texConfig;
|
TextureConfig texConfig;
|
||||||
|
FogConfig fogConfig;
|
||||||
LightingConfig lighting;
|
LightingConfig lighting;
|
||||||
|
|
||||||
bool operator==(const FragmentConfig& config) const {
|
bool operator==(const FragmentConfig& config) const {
|
||||||
|
@ -220,12 +233,21 @@ namespace PICA {
|
||||||
setupTevStage(4);
|
setupTevStage(4);
|
||||||
setupTevStage(5);
|
setupTevStage(5);
|
||||||
#undef setupTevStage
|
#undef setupTevStage
|
||||||
|
|
||||||
|
fogConfig.mode = (FogMode)Helpers::getBits<0, 3>(regs[InternalRegs::TexEnvUpdateBuffer]);
|
||||||
|
|
||||||
|
if (fogConfig.mode == FogMode::Fog) {
|
||||||
|
fogConfig.flipDepth = Helpers::getBit<16>(regs[InternalRegs::TexEnvUpdateBuffer]);
|
||||||
|
fogConfig.fogColorR = Helpers::getBits<0, 8>(regs[InternalRegs::FogColor]);
|
||||||
|
fogConfig.fogColorG = Helpers::getBits<8, 8>(regs[InternalRegs::FogColor]);
|
||||||
|
fogConfig.fogColorB = Helpers::getBits<16, 8>(regs[InternalRegs::FogColor]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert(
|
static_assert(
|
||||||
std::has_unique_object_representations<OutputConfig>() && std::has_unique_object_representations<TextureConfig>() &&
|
std::has_unique_object_representations<OutputConfig>() && std::has_unique_object_representations<TextureConfig>() &&
|
||||||
std::has_unique_object_representations<Light>()
|
std::has_unique_object_representations<FogConfig>() && std::has_unique_object_representations<Light>()
|
||||||
);
|
);
|
||||||
} // namespace PICA
|
} // namespace PICA
|
||||||
|
|
||||||
|
|
|
@ -51,6 +51,18 @@ namespace PICA {
|
||||||
#undef defineTexEnv
|
#undef defineTexEnv
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
|
// Fog registers
|
||||||
|
FogColor = 0xE1,
|
||||||
|
FogLUTIndex = 0xE6,
|
||||||
|
FogLUTData0 = 0xE8,
|
||||||
|
FogLUTData1 = 0xE9,
|
||||||
|
FogLUTData2 = 0xEA,
|
||||||
|
FogLUTData3 = 0xEB,
|
||||||
|
FogLUTData4 = 0xEC,
|
||||||
|
FogLUTData5 = 0xED,
|
||||||
|
FogLUTData6 = 0xEE,
|
||||||
|
FogLUTData7 = 0xEF,
|
||||||
|
|
||||||
// Framebuffer registers
|
// Framebuffer registers
|
||||||
ColourOperation = 0x100,
|
ColourOperation = 0x100,
|
||||||
BlendFunc = 0x101,
|
BlendFunc = 0x101,
|
||||||
|
@ -384,6 +396,12 @@ namespace PICA {
|
||||||
GreaterOrEqual = 7,
|
GreaterOrEqual = 7,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class FogMode : u32 {
|
||||||
|
Disabled = 0,
|
||||||
|
Fog = 5,
|
||||||
|
Gas = 7,
|
||||||
|
};
|
||||||
|
|
||||||
struct TexEnvConfig {
|
struct TexEnvConfig {
|
||||||
enum class Source : u8 {
|
enum class Source : u8 {
|
||||||
PrimaryColor = 0x0,
|
PrimaryColor = 0x0,
|
||||||
|
|
|
@ -220,13 +220,9 @@ class PICAShader {
|
||||||
public:
|
public:
|
||||||
static constexpr size_t maxInstructionCount = 4096;
|
static constexpr size_t maxInstructionCount = 4096;
|
||||||
std::array<u32, maxInstructionCount> loadedShader; // Currently loaded & active shader
|
std::array<u32, maxInstructionCount> loadedShader; // Currently loaded & active shader
|
||||||
std::array<u32, maxInstructionCount> bufferedShader; // Shader to be transferred when the SH_CODETRANSFER_END reg gets written to
|
|
||||||
|
|
||||||
PICAShader(ShaderType type) : type(type) {}
|
PICAShader(ShaderType type) : type(type) {}
|
||||||
|
|
||||||
// Theese functions are in the header to be inlined more easily, though with LTO I hope I'll be able to move them
|
|
||||||
void finalize() { std::memcpy(&loadedShader[0], &bufferedShader[0], 4096 * sizeof(u32)); }
|
|
||||||
|
|
||||||
void setBufferIndex(u32 index) { bufferIndex = index & 0xfff; }
|
void setBufferIndex(u32 index) { bufferIndex = index & 0xfff; }
|
||||||
void setOpDescriptorIndex(u32 index) { opDescriptorIndex = index & 0x7f; }
|
void setOpDescriptorIndex(u32 index) { opDescriptorIndex = index & 0x7f; }
|
||||||
|
|
||||||
|
@ -235,7 +231,7 @@ class PICAShader {
|
||||||
Helpers::panic("o no, shader upload overflew");
|
Helpers::panic("o no, shader upload overflew");
|
||||||
}
|
}
|
||||||
|
|
||||||
bufferedShader[bufferIndex++] = word;
|
loadedShader[bufferIndex++] = word;
|
||||||
bufferIndex &= 0xfff;
|
bufferIndex &= 0xfff;
|
||||||
|
|
||||||
codeHashDirty = true; // Signal the JIT if necessary that the program hash has potentially changed
|
codeHashDirty = true; // Signal the JIT if necessary that the program hash has potentially changed
|
||||||
|
|
|
@ -24,6 +24,8 @@ namespace PICA::ShaderGen {
|
||||||
void compileLUTLookup(std::string& shader, const PICA::FragmentConfig& config, u32 lightIndex, u32 lutID);
|
void compileLUTLookup(std::string& shader, const PICA::FragmentConfig& config, u32 lightIndex, u32 lutID);
|
||||||
bool isSamplerEnabled(u32 environmentID, u32 lutID);
|
bool isSamplerEnabled(u32 environmentID, u32 lutID);
|
||||||
|
|
||||||
|
void compileFog(std::string& shader, const PICA::FragmentConfig& config);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FragmentGenerator(API api, Language language) : api(api), language(language) {}
|
FragmentGenerator(API api, Language language) : api(api), language(language) {}
|
||||||
std::string generate(const PICA::FragmentConfig& config);
|
std::string generate(const PICA::FragmentConfig& config);
|
||||||
|
|
|
@ -50,6 +50,7 @@ struct NCCH {
|
||||||
|
|
||||||
static constexpr u64 mediaUnit = 0x200;
|
static constexpr u64 mediaUnit = 0x200;
|
||||||
u64 size = 0; // Size of NCCH converted to bytes
|
u64 size = 0; // Size of NCCH converted to bytes
|
||||||
|
u64 saveDataSize = 0;
|
||||||
u32 stackSize = 0;
|
u32 stackSize = 0;
|
||||||
u32 bssSize = 0;
|
u32 bssSize = 0;
|
||||||
u32 exheaderSize = 0;
|
u32 exheaderSize = 0;
|
||||||
|
@ -64,8 +65,6 @@ struct NCCH {
|
||||||
|
|
||||||
// Contents of the .code file in the ExeFS
|
// Contents of the .code file in the ExeFS
|
||||||
std::vector<u8> codeFile;
|
std::vector<u8> codeFile;
|
||||||
// Contains of the cart's save data
|
|
||||||
std::vector<u8> saveData;
|
|
||||||
// The cart region. Only the CXI's region matters to us. Necessary to get past region locking
|
// The cart region. Only the CXI's region matters to us. Necessary to get past region locking
|
||||||
std::optional<Regions> region = std::nullopt;
|
std::optional<Regions> region = std::nullopt;
|
||||||
std::vector<u8> smdh;
|
std::vector<u8> smdh;
|
||||||
|
@ -78,7 +77,7 @@ struct NCCH {
|
||||||
bool hasExeFS() { return exeFS.size != 0; }
|
bool hasExeFS() { return exeFS.size != 0; }
|
||||||
bool hasRomFS() { return romFS.size != 0; }
|
bool hasRomFS() { return romFS.size != 0; }
|
||||||
bool hasCode() { return codeFile.size() != 0; }
|
bool hasCode() { return codeFile.size() != 0; }
|
||||||
bool hasSaveData() { return saveData.size() != 0; }
|
bool hasSaveData() { return saveDataSize != 0; }
|
||||||
|
|
||||||
// Parse SMDH for region info and such. Returns false on failure, true on success
|
// Parse SMDH for region info and such. Returns false on failure, true on success
|
||||||
bool parseSMDH(const std::vector<u8> &smdh);
|
bool parseSMDH(const std::vector<u8> &smdh);
|
||||||
|
|
|
@ -63,7 +63,7 @@ class RendererGL final : public Renderer {
|
||||||
OpenGL::VertexBuffer dummyVBO;
|
OpenGL::VertexBuffer dummyVBO;
|
||||||
|
|
||||||
OpenGL::Texture screenTexture;
|
OpenGL::Texture screenTexture;
|
||||||
OpenGL::Texture lightLUTTexture;
|
OpenGL::Texture LUTTexture;
|
||||||
OpenGL::Framebuffer screenFramebuffer;
|
OpenGL::Framebuffer screenFramebuffer;
|
||||||
OpenGL::Texture blankTexture;
|
OpenGL::Texture blankTexture;
|
||||||
// The "default" vertex shader to use when using specialized shaders but not PICA vertex shader -> GLSL recompilation
|
// The "default" vertex shader to use when using specialized shaders but not PICA vertex shader -> GLSL recompilation
|
||||||
|
@ -90,6 +90,7 @@ class RendererGL final : public Renderer {
|
||||||
void setupUbershaderTexEnv();
|
void setupUbershaderTexEnv();
|
||||||
void bindTexturesToSlots();
|
void bindTexturesToSlots();
|
||||||
void updateLightingLUT();
|
void updateLightingLUT();
|
||||||
|
void updateFogLUT();
|
||||||
void initGraphicsContextInternal();
|
void initGraphicsContextInternal();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -74,6 +74,9 @@ void GPU::reset() {
|
||||||
lightingLUT.fill(0);
|
lightingLUT.fill(0);
|
||||||
lightingLUTDirty = true;
|
lightingLUTDirty = true;
|
||||||
|
|
||||||
|
fogLUT.fill(0);
|
||||||
|
fogLUTDirty = true;
|
||||||
|
|
||||||
totalAttribCount = 0;
|
totalAttribCount = 0;
|
||||||
fixedAttribMask = 0;
|
fixedAttribMask = 0;
|
||||||
fixedAttribIndex = 0;
|
fixedAttribIndex = 0;
|
||||||
|
|
|
@ -135,6 +135,21 @@ void GPU::writeInternalReg(u32 index, u32 value, u32 mask) {
|
||||||
break;
|
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 LightingLUTData0:
|
||||||
case LightingLUTData1:
|
case LightingLUTData1:
|
||||||
case LightingLUTData2:
|
case LightingLUTData2:
|
||||||
|
@ -314,9 +329,11 @@ void GPU::writeInternalReg(u32 index, u32 value, u32 mask) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* TODO: Find out if this actually does anything
|
||||||
case VertexShaderTransferEnd:
|
case VertexShaderTransferEnd:
|
||||||
if (value != 0) shaderUnit.vs.finalize();
|
if (value != 0) shaderUnit.vs.finalize();
|
||||||
break;
|
break;
|
||||||
|
*/
|
||||||
|
|
||||||
case VertexShaderTransferIndex: shaderUnit.vs.setBufferIndex(value); 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_tex0;
|
||||||
uniform sampler2D u_tex1;
|
uniform sampler2D u_tex1;
|
||||||
uniform sampler2D u_tex2;
|
uniform sampler2D u_tex2;
|
||||||
uniform sampler2D u_tex_lighting_lut;
|
uniform sampler2D u_tex_luts;
|
||||||
)";
|
)";
|
||||||
|
|
||||||
ret += uniformDefinition;
|
ret += uniformDefinition;
|
||||||
|
@ -144,7 +144,7 @@ std::string FragmentGenerator::generate(const FragmentConfig& config) {
|
||||||
}
|
}
|
||||||
|
|
||||||
float lutLookup(uint lut, int index) {
|
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) {
|
vec3 regToColor(uint reg) {
|
||||||
|
@ -194,6 +194,8 @@ std::string FragmentGenerator::generate(const FragmentConfig& config) {
|
||||||
compileTEV(ret, i, config);
|
compileTEV(ret, i, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
compileFog(ret, config);
|
||||||
|
|
||||||
applyAlphaTest(ret, config);
|
applyAlphaTest(ret, config);
|
||||||
|
|
||||||
ret += "fragColor = combinerOutput;\n}"; // End of main function
|
ret += "fragColor = combinerOutput;\n}"; // End of main function
|
||||||
|
@ -653,3 +655,26 @@ void FragmentGenerator::compileLUTLookup(std::string& shader, const PICA::Fragme
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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() {
|
void PICAShader::reset() {
|
||||||
loadedShader.fill(0);
|
loadedShader.fill(0);
|
||||||
bufferedShader.fill(0);
|
|
||||||
operandDescriptors.fill(0);
|
operandDescriptors.fill(0);
|
||||||
|
|
||||||
boolUniform = 0;
|
boolUniform = 0;
|
||||||
|
|
|
@ -25,7 +25,6 @@ bool NCCH::loadFromHeader(Crypto::AESEngine &aesEngine, IOFile& file, const FSIn
|
||||||
}
|
}
|
||||||
|
|
||||||
codeFile.clear();
|
codeFile.clear();
|
||||||
saveData.clear();
|
|
||||||
smdh.clear();
|
smdh.clear();
|
||||||
partitionInfo = info;
|
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
|
saveDataSize = *(u64*)&exheader[0x1C0 + 0x0]; // Size of save data in bytes
|
||||||
saveData.resize(saveDataSize, 0xff);
|
|
||||||
|
|
||||||
compressCode = (exheader[0xD] & 1) != 0;
|
compressCode = (exheader[0xD] & 1) != 0;
|
||||||
stackSize = *(u32*)&exheader[0x1C];
|
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 screenTextureWidth = 400; // Top screen is 400 pixels wide, bottom is 320
|
||||||
const u32 screenTextureHeight = 2 * 240; // Both screens are 240 pixels tall
|
const u32 screenTextureHeight = 2 * 240; // Both screens are 240 pixels tall
|
||||||
|
|
||||||
lightLUTTexture.create(256, Lights::LUT_Count, GL_R32F);
|
// 24 rows for light, 1 for fog
|
||||||
lightLUTTexture.bind();
|
LUTTexture.create(256, Lights::LUT_Count + 1, GL_RG32F);
|
||||||
lightLUTTexture.setMinFilter(OpenGL::Linear);
|
LUTTexture.bind();
|
||||||
lightLUTTexture.setMagFilter(OpenGL::Linear);
|
LUTTexture.setMinFilter(OpenGL::Linear);
|
||||||
|
LUTTexture.setMagFilter(OpenGL::Linear);
|
||||||
|
|
||||||
auto prevTexture = OpenGL::getTex2D();
|
auto prevTexture = OpenGL::getTex2D();
|
||||||
|
|
||||||
|
@ -353,22 +354,49 @@ void RendererGL::bindTexturesToSlots() {
|
||||||
}
|
}
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE0 + 3);
|
glActiveTexture(GL_TEXTURE0 + 3);
|
||||||
lightLUTTexture.bind();
|
LUTTexture.bind();
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RendererGL::updateLightingLUT() {
|
void RendererGL::updateLightingLUT() {
|
||||||
gpu.lightingLUTDirty = false;
|
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++) {
|
for (int i = 0; i < lightingLut.size(); i += 2) {
|
||||||
uint64_t value = gpu.lightingLUT[i] & 0xFFF;
|
uint64_t value = gpu.lightingLUT[i >> 1] & 0xFFF;
|
||||||
lightingLut[i] = (float)(value << 4) / 65535.0f;
|
lightingLut[i] = (float)(value << 4) / 65535.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE0 + 3);
|
glActiveTexture(GL_TEXTURE0 + 3);
|
||||||
lightLUTTexture.bind();
|
LUTTexture.bind();
|
||||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 256, Lights::LUT_Count, GL_RED, GL_FLOAT, lightingLut.data());
|
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);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -453,6 +481,10 @@ void RendererGL::drawVertices(PICA::PrimType primType, std::span<const Vertex> v
|
||||||
|
|
||||||
bindTexturesToSlots();
|
bindTexturesToSlots();
|
||||||
|
|
||||||
|
if (gpu.fogLUTDirty) {
|
||||||
|
updateFogLUT();
|
||||||
|
}
|
||||||
|
|
||||||
if (gpu.lightingLUTDirty) {
|
if (gpu.lightingLUTDirty) {
|
||||||
updateLightingLUT();
|
updateLightingLUT();
|
||||||
}
|
}
|
||||||
|
@ -499,7 +531,6 @@ void RendererGL::display() {
|
||||||
gl.disableScissor();
|
gl.disableScissor();
|
||||||
gl.disableBlend();
|
gl.disableBlend();
|
||||||
gl.disableDepth();
|
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
|
// 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.setLogicOp(GL_COPY);
|
||||||
gl.setColourMask(true, true, true, true);
|
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_tex0"), 0);
|
||||||
glUniform1i(OpenGL::uniformLocation(program, "u_tex1"), 1);
|
glUniform1i(OpenGL::uniformLocation(program, "u_tex1"), 1);
|
||||||
glUniform1i(OpenGL::uniformLocation(program, "u_tex2"), 2);
|
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
|
// Allocate memory for the program UBO
|
||||||
glGenBuffers(1, &programEntry.uboBinding);
|
glGenBuffers(1, &programEntry.uboBinding);
|
||||||
|
@ -994,9 +1025,9 @@ void RendererGL::initUbershader(OpenGL::Program& program) {
|
||||||
ubershaderData.depthmapEnableLoc = OpenGL::uniformLocation(program, "u_depthmapEnable");
|
ubershaderData.depthmapEnableLoc = OpenGL::uniformLocation(program, "u_depthmapEnable");
|
||||||
ubershaderData.picaRegLoc = OpenGL::uniformLocation(program, "u_picaRegs");
|
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_tex0"), 0);
|
||||||
glUniform1i(OpenGL::uniformLocation(program, "u_tex1"), 1);
|
glUniform1i(OpenGL::uniformLocation(program, "u_tex1"), 1);
|
||||||
glUniform1i(OpenGL::uniformLocation(program, "u_tex2"), 2);
|
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_tex0;
|
||||||
uniform sampler2D u_tex1;
|
uniform sampler2D u_tex1;
|
||||||
uniform sampler2D u_tex2;
|
uniform sampler2D u_tex2;
|
||||||
uniform sampler2D u_tex_lighting_lut;
|
uniform sampler2D u_tex_luts;
|
||||||
|
|
||||||
uniform uint u_picaRegs[0x200 - 0x48];
|
uniform uint u_picaRegs[0x200 - 0x48];
|
||||||
|
|
||||||
|
@ -152,6 +152,8 @@ vec4 tevCalculateCombiner(int tev_id) {
|
||||||
#define RG_LUT 5u
|
#define RG_LUT 5u
|
||||||
#define RR_LUT 6u
|
#define RR_LUT 6u
|
||||||
|
|
||||||
|
#define FOG_INDEX 24
|
||||||
|
|
||||||
uint GPUREG_LIGHTi_CONFIG;
|
uint GPUREG_LIGHTi_CONFIG;
|
||||||
uint GPUREG_LIGHTING_CONFIG1;
|
uint GPUREG_LIGHTING_CONFIG1;
|
||||||
uint GPUREG_LIGHTING_LUTINPUT_SELECT;
|
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);
|
vec4 unimpl_color = vec4(1.0, 0.0, 1.0, 1.0);
|
||||||
|
|
||||||
float lutLookup(uint lut, int index) {
|
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) {
|
vec3 regToColor(uint reg) {
|
||||||
|
@ -494,7 +496,7 @@ void main() {
|
||||||
if (tevUnimplementedSourceFlag) {
|
if (tevUnimplementedSourceFlag) {
|
||||||
// fragColour = vec4(1.0, 0.0, 1.0, 1.0);
|
// 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]
|
// 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]
|
// 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
|
// Write final fragment depth
|
||||||
gl_FragDepth = 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
|
// Perform alpha test
|
||||||
uint alphaControl = readPicaReg(0x104u);
|
uint alphaControl = readPicaReg(0x104u);
|
||||||
if ((alphaControl & 1u) != 0u) { // Check if alpha test is on
|
if ((alphaControl & 1u) != 0u) { // Check if alpha test is on
|
||||||
|
|
Loading…
Add table
Reference in a new issue