diff --git a/port/fast3d/gfx_opengl.cpp b/port/fast3d/gfx_opengl.cpp index f172ce96d..236f535c7 100644 --- a/port/fast3d/gfx_opengl.cpp +++ b/port/fast3d/gfx_opengl.cpp @@ -34,9 +34,7 @@ struct ShaderProgram { GLint noise_scale_location; GLint three_point_filter_locations[2]; GLint decal_mode_location; - GLint decal_scale_location; int decal_mode; - float decal_scale; }; struct Framebuffer { @@ -66,10 +64,8 @@ static MipmapFilteringMode current_mipmap_filter_mode = MIPMAP_LINEAR; static bool current_textures_linear_filter[2] = {false, false}; static struct ShaderProgram* current_shader_program; -// N64 decal depth mode: pixels only pass when close to the stored depth, using a copy of the depth buffer +// Decals are clipped to the geometry they lie on, using a copy of the depth buffer #define DECAL_DEPTH_TEXTURE_UNIT 2 -// Height of the N64 frame; the RDP's depth slope tolerance is measured in N64 pixels -#define DECAL_N64_SCREEN_HEIGHT 240.0f static bool depth_copy_supported; static bool depth_copy_dirty = true; static size_t depth_copy_source; @@ -403,7 +399,6 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad append_line(fs_buf, &fs_len, "uniform int frame_count;"); append_line(fs_buf, &fs_len, "uniform float noise_scale;"); append_line(fs_buf, &fs_len, "uniform int uDecalMode;"); - append_line(fs_buf, &fs_len, "uniform highp float uDecalPixelScale;"); append_line(fs_buf, &fs_len, "uniform highp sampler2D uDepthTex;"); append_line(fs_buf, &fs_len, "float random(in vec3 value) {"); @@ -465,13 +460,12 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad append_line(fs_buf, &fs_len, "void main() {"); - // RDP decal Z mode: pass only if |z - stored z| <= dz (the per-pixel depth slope), and never over cleared depth. - // The slope is computed before anything can discard, since derivatives are undefined after a neighbor discards. + // Discard decal pixels hanging past an edge, i.e. where the stored surface is clearly further away than the decal. + // (1 - z) is roughly proportional to 1 / distance, so this allows a gap of about 3% of the distance, plus slope. append_line(fs_buf, &fs_len, " highp float decalSlope = fwidth(gl_FragCoord.z);"); append_line(fs_buf, &fs_len, " if (uDecalMode != 0) {"); append_line(fs_buf, &fs_len, " highp float storedZ = texelFetch(uDepthTex, ivec2(gl_FragCoord.xy), 0).r;"); - append_line(fs_buf, &fs_len, " highp float dz = max(decalSlope * uDecalPixelScale, 1.0 / 262144.0);"); - append_line(fs_buf, &fs_len, " if (storedZ >= 1.0 || abs(gl_FragCoord.z - storedZ) > dz) discard;"); + append_line(fs_buf, &fs_len, " if (storedZ - gl_FragCoord.z > 0.03 * (1.0 - gl_FragCoord.z) + 3.0 * decalSlope) discard;"); append_line(fs_buf, &fs_len, " }"); for (int i = 0; i < 2; i++) { @@ -685,9 +679,7 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad prg->three_point_filter_locations[0] = glGetUniformLocation(shader_program, "three_point_filter0"); prg->three_point_filter_locations[1] = glGetUniformLocation(shader_program, "three_point_filter1"); prg->decal_mode_location = glGetUniformLocation(shader_program, "uDecalMode"); - prg->decal_scale_location = glGetUniformLocation(shader_program, "uDecalPixelScale"); prg->decal_mode = 0; - prg->decal_scale = 0.0f; if (prg->decal_mode_location >= 0) { glUniform1i(prg->decal_mode_location, 0); glUniform1i(glGetUniformLocation(shader_program, "uDepthTex"), DECAL_DEPTH_TEXTURE_UNIT); @@ -934,29 +926,11 @@ static void gfx_opengl_set_decal_uniforms(struct ShaderProgram* prg, bool enable glUniform1i(prg->decal_mode_location, mode); prg->decal_mode = mode; } - - const float scale = framebuffers[current_framebuffer].height / DECAL_N64_SCREEN_HEIGHT; - if (enabled && prg->decal_scale != scale) { - glUniform1f(prg->decal_scale_location, scale); - prg->decal_scale = scale; - } } static void gfx_opengl_draw_triangles(float buf_vbo[], size_t buf_vbo_len, size_t buf_vbo_num_tris) { // printf("flushing %d tris\n", buf_vbo_num_tris); - if (current_depth_decal) { - // The shader replaces the depth test like the RDP does; fall back to polygon offset if depth can't be copied - const bool decal = gfx_opengl_update_depth_copy(); - glDepthFunc(decal ? GL_ALWAYS : GL_LEQUAL); - if (decal) { - glDisable(GL_POLYGON_OFFSET_FILL); - } else { - glEnable(GL_POLYGON_OFFSET_FILL); - } - gfx_opengl_set_decal_uniforms(current_shader_program, decal); - } else { - gfx_opengl_set_decal_uniforms(current_shader_program, false); - } + gfx_opengl_set_decal_uniforms(current_shader_program, current_depth_decal && gfx_opengl_update_depth_copy()); glBufferData(GL_ARRAY_BUFFER, sizeof(float) * buf_vbo_len, buf_vbo, GL_STREAM_DRAW); glDrawArrays(GL_TRIANGLES, 0, 3 * buf_vbo_num_tris);