diff --git a/port/fast3d/gfx_api.h b/port/fast3d/gfx_api.h index 279a684ef..f79c4075d 100644 --- a/port/fast3d/gfx_api.h +++ b/port/fast3d/gfx_api.h @@ -44,7 +44,7 @@ void gfx_start_frame(void); void gfx_run(Gfx* commands); void gfx_end_frame(void); void gfx_set_target_fps(int); -void gfx_set_maximum_frame_latency(int latency); +void gfx_set_texture_filter(enum FilteringMode mode); void gfx_texture_cache_clear(void); void gfx_texture_cache_delete(const uint8_t *orig_addr); int gfx_create_framebuffer(uint32_t width, uint32_t height, int upscale, int autoresize); @@ -52,7 +52,5 @@ void gfx_resize_framebuffer(int fb, uint32_t width, uint32_t height, int upscale void gfx_set_framebuffer(int fb, float noise_scale) ; void gfx_reset_framebuffer(void); void gfx_copy_framebuffer(int fb_dst, int fb_src, int left, int top, int use_back); -void gfx_get_pixel_depth_prepare(float x, float y); -uint16_t gfx_get_pixel_depth(float x, float y); #endif diff --git a/port/fast3d/gfx_opengl.cpp b/port/fast3d/gfx_opengl.cpp index 0a0107755..0f9ee081b 100644 --- a/port/fast3d/gfx_opengl.cpp +++ b/port/fast3d/gfx_opengl.cpp @@ -32,6 +32,7 @@ struct ShaderProgram { uint8_t num_attribs; GLint frame_count_location; GLint noise_scale_location; + GLint three_point_filter_locations[2]; }; struct Framebuffer { @@ -54,6 +55,7 @@ static std::vector framebuffers; static size_t current_framebuffer; static float current_noise_scale; static FilteringMode current_filter_mode = FILTER_LINEAR; +static bool current_linear_filters[2] = {false, false}; static GLenum gl_mirror_clamp = GL_MIRROR_CLAMP_TO_EDGE; @@ -94,6 +96,12 @@ static void gfx_opengl_set_uniforms(struct ShaderProgram* prg) { if (prg->noise_scale_location >= 0) { glUniform1f(prg->noise_scale_location, current_noise_scale); } + if (prg->three_point_filter_locations[0] >= 0) { + glUniform1i(prg->three_point_filter_locations[0], current_linear_filters[0]); + } + if (prg->three_point_filter_locations[1] >= 0) { + glUniform1i(prg->three_point_filter_locations[1], current_linear_filters[1]); + } } static void gfx_opengl_unload_shader(struct ShaderProgram* old_prg) { @@ -369,9 +377,13 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad } if (cc_features.used_textures[0]) { append_line(fs_buf, &fs_len, "uniform sampler2D uTex0;"); + if (current_filter_mode == FILTER_THREE_POINT) + append_line(fs_buf, &fs_len, "uniform int three_point_filter0;"); } if (cc_features.used_textures[1]) { append_line(fs_buf, &fs_len, "uniform sampler2D uTex1;"); + if (current_filter_mode == FILTER_THREE_POINT) + append_line(fs_buf, &fs_len, "uniform int three_point_filter1;"); } append_line(fs_buf, &fs_len, "uniform int frame_count;"); @@ -387,7 +399,7 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad // used to be two for loops from 0 to 4, but apparently intel drivers crashed trying to unroll it // used to have a const weight array, but apparently drivers for the GT620 don't like const array initializers append_line(fs_buf, &fs_len, R"( - lowp vec4 hookTexture2D(in sampler2D t, in vec2 uv, in vec2 tsize) { + lowp vec4 hookTexture2D(in sampler2D t, in vec2 uv, in vec2 tsize, in int three_point_filter) { lowp vec4 cw = vec4(0.0); for (int i = 0; i < 16; ++i) { vec2 xy = vec2(float(i & 3), float(i >> 2)); @@ -411,11 +423,15 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad append_line(fs_buf, &fs_len, " vec4 c2 = TEX_OFFSET(vec2(offset.x, offset.y - sign(offset.y)));"); append_line(fs_buf, &fs_len, " return c0 + abs(offset.x)*(c1-c0) + abs(offset.y)*(c2-c0);"); append_line(fs_buf, &fs_len, "}"); - append_line(fs_buf, &fs_len, "vec4 hookTexture2D(in sampler2D tex, in vec2 uv, in vec2 texSize) {"); - append_line(fs_buf, &fs_len, " return filter3point(tex, uv, texSize);"); + append_line(fs_buf, &fs_len, "vec4 hookTexture2D(in sampler2D tex, in vec2 uv, in vec2 texSize, in int three_point_filter) {"); +#if __APPLE__ + append_line(fs_buf, &fs_len, " return three_point_filter == 1 ? filter3point(tex, uv, texSize) : texture(tex, uv);"); +#else + append_line(fs_buf, &fs_len, " return three_point_filter == 1 ? filter3point(tex, uv, texSize) : texture2D(tex, uv);"); +#endif append_line(fs_buf, &fs_len, "}"); } else { - append_line(fs_buf, &fs_len, "vec4 hookTexture2D(in sampler2D tex, in vec2 uv, in vec2 texSize) {"); + append_line(fs_buf, &fs_len, "vec4 hookTexture2D(in sampler2D tex, in vec2 uv, in vec2 texSize, in int three_point_filter) {"); #if __APPLE__ append_line(fs_buf, &fs_len, " return texture(tex, uv);"); #else @@ -461,7 +477,10 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad } } - fs_len += sprintf(fs_buf + fs_len, "vec4 texVal%d = hookTexture2D(uTex%d, vTexCoordAdj%d, texSize%d);\n", i, i, i, i); + if (current_filter_mode == FILTER_THREE_POINT) + fs_len += sprintf(fs_buf + fs_len, "vec4 texVal%d = hookTexture2D(uTex%d, vTexCoordAdj%d, texSize%d, three_point_filter%d);\n", i, i, i, i, i); + else + fs_len += sprintf(fs_buf + fs_len, "vec4 texVal%d = hookTexture2D(uTex%d, vTexCoordAdj%d, texSize%d, 0);\n", i, i, i, i); } } @@ -574,6 +593,9 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad glAttachShader(shader_program, fragment_shader); glLinkProgram(shader_program); + glDeleteShader(vertex_shader); + glDeleteShader(fragment_shader); + size_t cnt = 0; struct ShaderProgram* prg = &shader_program_pool[make_pair(shader_id0, shader_id1)]; @@ -640,6 +662,8 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad prg->frame_count_location = glGetUniformLocation(shader_program, "frame_count"); prg->noise_scale_location = glGetUniformLocation(shader_program, "noise_scale"); + prg->three_point_filter_locations[0] = glGetUniformLocation(shader_program, "three_point_filter0"); + prg->three_point_filter_locations[1] = glGetUniformLocation(shader_program, "three_point_filter1"); gfx_opengl_load_shader(prg); @@ -657,6 +681,14 @@ static void gfx_opengl_shader_get_info(struct ShaderProgram* prg, uint8_t* num_i used_textures[1] = prg->used_textures[1]; } +static void gfx_opengl_clear_shaders(void) { + glUseProgram(0); + for (auto& pair : shader_program_pool) { + glDeleteProgram(pair.second.opengl_program_id); + } + shader_program_pool.clear(); +} + static GLuint gfx_opengl_new_texture(void) { GLuint ret; glGenTextures(1, &ret); @@ -667,9 +699,11 @@ static void gfx_opengl_delete_texture(uint32_t texID) { glDeleteTextures(1, &texID); } -static void gfx_opengl_select_texture(int tile, GLuint texture_id) { +static void gfx_opengl_select_texture(int tile, GLuint texture_id, bool linear_filter) { glActiveTexture(GL_TEXTURE0 + tile); glBindTexture(GL_TEXTURE_2D, texture_id); + + current_linear_filters[tile] = linear_filter; } static void gfx_opengl_upload_texture(const uint8_t* rgba32_buf, uint32_t width, uint32_t height) { @@ -1065,12 +1099,23 @@ bool gfx_opengl_start_draw_to_framebuffer(int fb_id, float noise_scale) { } } -void gfx_opengl_clear_framebuffer() { +void gfx_opengl_clear_framebuffer(bool clear_color, bool clear_depth) { glDisable(GL_SCISSOR_TEST); - glDepthMask(GL_TRUE); - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glDepthMask(current_depth_mask ? GL_TRUE : GL_FALSE); + + GLbitfield mask = 0; + if (clear_color) { + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + mask |= GL_COLOR_BUFFER_BIT; + } + if (clear_depth) { + glDepthMask(GL_TRUE); + mask |= GL_DEPTH_BUFFER_BIT; + } + glClear(mask); + if (clear_depth) { + glDepthMask(current_depth_mask ? GL_TRUE : GL_FALSE); + } + glEnable(GL_SCISSOR_TEST); } @@ -1156,7 +1201,6 @@ void gfx_opengl_copy_framebuffer(int fb_dst, int fb_src, int left, int top, bool void gfx_opengl_set_texture_filter(FilteringMode mode) { current_filter_mode = mode; - gfx_texture_cache_clear(); } FilteringMode gfx_opengl_get_texture_filter(void) { @@ -1172,6 +1216,7 @@ struct GfxRenderingAPI gfx_opengl_api = { gfx_opengl_create_and_load_new_shader, gfx_opengl_lookup_shader, gfx_opengl_shader_get_info, + gfx_opengl_clear_shaders, gfx_opengl_new_texture, gfx_opengl_select_texture, gfx_opengl_upload_texture, diff --git a/port/fast3d/gfx_pc.cpp b/port/fast3d/gfx_pc.cpp index 07e916aeb..df813796e 100644 --- a/port/fast3d/gfx_pc.cpp +++ b/port/fast3d/gfx_pc.cpp @@ -125,8 +125,6 @@ static struct RSP { float aspect_ofs; float aspect_scale; - float depth_zfar; - struct { // U0.16 uint16_t s, t; @@ -198,7 +196,6 @@ static struct RDP { static struct RenderingState { uint8_t depth_mode; - float depth_zfar; bool alpha_blend; bool modulate; struct XYWidthHeight viewport, scissor; @@ -522,7 +519,7 @@ static bool gfx_texture_cache_lookup(int i, const TextureCacheKey& key) { TextureCacheNode** n = &rendering_state.textures[i]; if (it != gfx_texture_cache.map.end()) { - gfx_rapi->select_texture(i, it->second.texture_id); + gfx_rapi->select_texture(i, it->second.texture_id, it->second.linear_filter); *n = &*it; gfx_texture_cache.lru.splice(gfx_texture_cache.lru.end(), gfx_texture_cache.lru, it->second.lru_location); // move to back @@ -550,7 +547,7 @@ static bool gfx_texture_cache_lookup(int i, const TextureCacheKey& key) { node->second.texture_id = texture_id; node->second.lru_location = gfx_texture_cache.lru.insert(gfx_texture_cache.lru.end(), { it }); - gfx_rapi->select_texture(i, texture_id); + gfx_rapi->select_texture(i, texture_id, false); gfx_rapi->set_sampler_parameters(i, false, 0, 0); *n = node; return false; @@ -1239,12 +1236,6 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo } } - if (rsp.depth_zfar != rendering_state.depth_zfar) { - gfx_flush(); - gfx_rapi->set_depth_range(0.0f, rsp.depth_zfar); - rendering_state.depth_zfar = rsp.depth_zfar; - } - bool depth_test = ((rsp.geometry_mode & G_ZBUFFER) == G_ZBUFFER || (rdp.other_mode_l & G_ZS_PRIM) == G_ZS_PRIM) && ((rdp.other_mode_h & G_CYC_1CYCLE) == G_CYC_1CYCLE || (rdp.other_mode_h & G_CYC_2CYCLE) == G_CYC_2CYCLE); bool depth_update = (rdp.other_mode_l & Z_UPD) == Z_UPD; @@ -1731,18 +1722,6 @@ static void gfx_sp_moveword(uint8_t index, uint16_t offset, uintptr_t data) { case G_MW_SEGMENT: segmentPointers[(offset >> 2) & 0xff] = data; break; - case G_MW_PERSPNORM: - // the default z range is around [100, 10000] - // data is 2 / (znear + zfar) represented as a 0.16 fixed point - // => (znear + zfar) = (2 / (data / 65536)) = 131072 / data - constexpr float full_range_mul = 1.f / 11000.f; // that's around the biggest value I got when testing - if (data == 0) { - rsp.depth_zfar = 1.f; - } else { - // sometimes this will overshoot 1 but GL can handle that - rsp.depth_zfar =((131072.f * full_range_mul) / (float)data); - } - break; } } @@ -2502,6 +2481,10 @@ static void gfx_run_dl(Gfx* cmd) { case G_RDPFLUSH_EXT: gfx_flush(); break; + case G_CLEAR_DEPTH_EXT: + gfx_flush(); + gfx_rapi->clear_framebuffer(false, true); + break; case G_RDPPIPESYNC: case G_RDPFULLSYNC: case G_RDPLOADSYNC: @@ -2552,8 +2535,6 @@ extern "C" void gfx_init(const GfxInitSettings *settings) { tex_upload_buffer = (uint8_t*)malloc(max_tex_size * max_tex_size * 4); } - rsp.depth_zfar = 1.0f; - rsp.lookat[0].dir[0] = rsp.lookat[1].dir[1] = 0x7F; rsp.current_lookat_coeffs[0][0] = rsp.current_lookat_coeffs[1][1] = 1.f; rsp.lookat_enabled = true; @@ -2659,7 +2640,7 @@ extern "C" void gfx_run(Gfx* commands) { gfx_rapi->start_frame(); gfx_rapi->start_draw_to_framebuffer(game_renders_to_framebuffer ? game_framebuffer : 0, (float)gfx_current_dimensions.height / SCREEN_HEIGHT); - gfx_rapi->clear_framebuffer(); + gfx_rapi->clear_framebuffer(true, false); rdp.viewport_or_scissor_changed = true; rendering_state.viewport = {}; rendering_state.scissor = {}; @@ -2669,7 +2650,7 @@ extern "C" void gfx_run(Gfx* commands) { if (game_renders_to_framebuffer) { gfx_rapi->start_draw_to_framebuffer(0, 1); - gfx_rapi->clear_framebuffer(); + gfx_rapi->clear_framebuffer(true, true); if (gfx_msaa_level > 1) { bool different_size = gfx_current_dimensions.width != gfx_current_game_window_viewport.width || @@ -2701,6 +2682,18 @@ extern "C" void gfx_set_target_fps(int fps) { gfx_wapi->set_target_fps(fps); } +extern "C" void gfx_set_texture_filter(enum FilteringMode mode) { + gfx_texture_cache_clear(); + if (rendering_state.shader_program) { + gfx_rapi->unload_shader(rendering_state.shader_program); + rendering_state.shader_program = nullptr; + } + gfx_rapi->clear_shaders(); + color_combiner_pool.clear(); + prev_combiner = color_combiner_pool.end(); + gfx_rapi->set_texture_filter(mode); +} + extern "C" int gfx_create_framebuffer(uint32_t width, uint32_t height, int upscale, int autoresize) { int fb = gfx_rapi->create_framebuffer(); gfx_resize_framebuffer(fb, width, height, upscale, autoresize); @@ -2732,7 +2725,7 @@ extern "C" void gfx_resize_framebuffer(int fb, uint32_t width, uint32_t height, extern "C" void gfx_set_framebuffer(int fb, float noise_scale) { gfx_rapi->start_draw_to_framebuffer(fb, noise_scale); - gfx_rapi->clear_framebuffer(); + gfx_rapi->clear_framebuffer(true, true); } extern "C" void gfx_copy_framebuffer(int fb_dst, int fb_src, int left, int top, int use_back) { diff --git a/port/fast3d/gfx_rendering_api.h b/port/fast3d/gfx_rendering_api.h index fcc287665..2b499479c 100644 --- a/port/fast3d/gfx_rendering_api.h +++ b/port/fast3d/gfx_rendering_api.h @@ -23,8 +23,9 @@ struct GfxRenderingAPI { struct ShaderProgram* (*create_and_load_new_shader)(uint64_t shader_id0, uint32_t shader_id1); struct ShaderProgram* (*lookup_shader)(uint64_t shader_id0, uint32_t shader_id1); void (*shader_get_info)(struct ShaderProgram* prg, uint8_t* num_inputs, bool used_textures[2]); + void (*clear_shaders)(void); uint32_t (*new_texture)(void); - void (*select_texture)(int tile, uint32_t texture_id); + void (*select_texture)(int tile, uint32_t texture_id, bool linear_filter); void (*upload_texture)(const uint8_t* rgba32_buf, uint32_t width, uint32_t height); void (*set_sampler_parameters)(int sampler, bool linear_filter, uint32_t cms, uint32_t cmt); void (*set_depth_mode)(bool depth_test, bool depth_update, bool depth_compare, bool depth_source_prim, uint16_t zmode); @@ -44,7 +45,7 @@ struct GfxRenderingAPI { bool can_extract_depth); bool (*start_draw_to_framebuffer)(int fb_id, float noise_scale); void (*copy_framebuffer)(int fb_dst, int fb_src, int left, int top, bool flip_y, bool use_back); - void (*clear_framebuffer)(void); + void (*clear_framebuffer)(bool clear_color, bool clear_depth); void (*resolve_msaa_color_buffer)(int fb_id_target, int fb_id_source); void* (*get_framebuffer_texture_id)(int fb_id); void (*select_texture_fb)(int fb_id); diff --git a/port/src/optionsmenu.c b/port/src/optionsmenu.c index c3f2ae048..2b845ebe0 100644 --- a/port/src/optionsmenu.c +++ b/port/src/optionsmenu.c @@ -702,12 +702,23 @@ static MenuItemHandlerResult menuhandlerMaximizeWindow(s32 operation, struct men static MenuItemHandlerResult menuhandlerTexFilter(s32 operation, struct menuitem *item, union handlerdata *data) { + static const char *opts[] = { + "Nearest", + "Bilinear", + "Three Point" + }; + switch (operation) { - case MENUOP_GET: - return (videoGetTextureFilter() != 0); - case MENUOP_SET: - videoSetTextureFilter(data->checkbox.value); + case MENUOP_GETOPTIONCOUNT: + data->dropdown.value = ARRAYCOUNT(opts); break; + case MENUOP_GETOPTIONTEXT: + return (intptr_t)opts[data->dropdown.value]; + case MENUOP_SET: + videoSetTextureFilter(data->dropdown.value); + break; + case MENUOP_GETSELECTEDINDEX: + data->dropdown.value = videoGetTextureFilter(); } return 0; @@ -826,7 +837,7 @@ struct menuitem g_ExtendedVideoMenuItems[] = { menuhandlerTexDetail, }, { - MENUITEMTYPE_CHECKBOX, + MENUITEMTYPE_DROPDOWN, 0, MENUITEMFLAG_LITERAL_TEXT, (uintptr_t)"Texture Filtering", diff --git a/port/src/video.c b/port/src/video.c index 181af3ab5..3befff9fb 100644 --- a/port/src/video.c +++ b/port/src/video.c @@ -77,7 +77,7 @@ s32 videoInit(void) } wmAPI->set_target_fps(vidFramerateLimit); // disabled because vsync is on - renderingAPI->set_texture_filter((enum FilteringMode)texFilter); + gfx_set_texture_filter((enum FilteringMode)texFilter); initDone = true; return 0; @@ -219,7 +219,7 @@ void videoSetTextureFilter(u32 filter) { if (filter > FILTER_THREE_POINT) filter = FILTER_THREE_POINT; texFilter = filter; - renderingAPI->set_texture_filter((enum FilteringMode)filter); + gfx_set_texture_filter((enum FilteringMode)filter); } void videoSetTextureFilter2D(s32 filter) diff --git a/src/game/bondgun.c b/src/game/bondgun.c index 8c99e39c1..01a49f065 100644 --- a/src/game/bondgun.c +++ b/src/game/bondgun.c @@ -10933,7 +10933,6 @@ void bgunRender(Gfx **gdlptr) struct modelrenderdata renderdata = {NULL, true, 3}; // 10c struct player *player; s32 i; - const u32 wnorm = mtx00016dcc(0, 300); static bool renderhand = true; // var800702dc @@ -10999,7 +10998,7 @@ void bgunRender(Gfx **gdlptr) gSPLookAt(gdl++, camGetLookAt()); } - gSPPerspNormalize(gdl++, wnorm); + gSPPerspNormalize(gdl++, mtx00016dcc(0, 300)); // There is support for guns having a TV screen on them // but no guns have this model part so it's not used. @@ -11174,17 +11173,7 @@ void bgunRender(Gfx **gdlptr) } } -#ifndef PLATFORM_N64 - // put the casings into the same Z range as the gun - gSPPerspNormalize(gdl++, wnorm); -#endif - casingsRender(&gdl); - -#ifndef PLATFORM_N64 - gSPPerspNormalize(gdl++, viGetPerspScale()); -#endif - zbufSwap(); gdl = zbufConfigureRdp(gdl); diff --git a/src/game/zbuf.c b/src/game/zbuf.c index 67f7a026c..cf1b62140 100644 --- a/src/game/zbuf.c +++ b/src/game/zbuf.c @@ -126,7 +126,6 @@ Gfx *zbufConfigureRdp(Gfx *gdl) Gfx *zbufClear(Gfx *gdl) { #ifdef PLATFORM_N64 - // no reason to do a Z clear on PC, we already do it at frame start s32 left; s32 right; @@ -150,6 +149,8 @@ Gfx *zbufClear(Gfx *gdl) gDPFillRectangle(gdl++, left, 0, right, playerGetFbHeight() - 1); gDPPipeSync(gdl++); +#else + gDPClearDepthEXT(gdl++); #endif return gdl; diff --git a/src/include/gbiex.h b/src/include/gbiex.h index 904de2fd0..8cc1d50c6 100644 --- a/src/include/gbiex.h +++ b/src/include/gbiex.h @@ -195,6 +195,7 @@ #define G_COPYFB_EXT 0x41 #define G_IMAGERECT_EXT 0x42 #define G_RDPFLUSH_EXT 0x43 +#define G_CLEAR_DEPTH_EXT 0x44 /* G_EXTRAGEOMETRYMODE flags */ @@ -300,6 +301,8 @@ #define gDPFlushEXT(pkt) gDPNoParam(pkt, G_RDPFLUSH_EXT) +#define gDPClearDepthEXT(pkt) gDPNoParam(pkt, G_CLEAR_DEPTH_EXT) + #undef gDPFillRectangleScaled #define gDPFillRectangleScaled(pkt, x1, y1, x2, y2) gDPFillRectangleEXT(pkt, (x1) * g_ScaleX, y1, (x2) * g_ScaleX, y2)