forked from Ports/goldeneye-pc-port
D74: rework sub-tile UV pre-wrap as opt-in Video.WrapFix (was dead + OOB)
The D74 block in gfx_sp_tri was inert (guard `cms & G_TX_WRAP` == `& 0`, always false) AND OOB (`tex_width2[i]` indexed by the vertex i=0..2, but the array is per-texunit [2]). SMALL-FIXES B1: the naive in-place correction boot-crashed -level_09. Rework per the B1 plan: precompute per-texunit `wrap_s/t[t]`, `wrap_tw/th[t]`, `wrap_uls/ult[t]` once in the texunit setup loop (needs the original cms/cmt before the CLAMP-clear), keyed on 'clamp bit not set' + window smaller than the uploaded image; apply per vertex indexed by `t`. Gated behind `Video.WrapFix` (default 0 -- new/never-run path). Verified: WrapFix=0 unchanged; WrapFix=1 -level_09 renders clean through frame 375, no boot crash, no visible corruption. Visual fix on wrapped triangle textures (room panels) needs a level with them + an N64 reference -- Depot per B1.
This commit is contained in:
1 parent
e86ad05ba8
commit
3e5720c01b
3 files changed
+50
-24
No files matched your search
@@ -47,6 +47,7 @@ void gfx_set_target_fps(int);
|
||||
void gfx_set_texture_filter(enum FilteringMode mode);
|
||||
void gfx_set_mipmap_filter(enum MipmapFilteringMode mode);
|
||||
void gfx_set_fix_mip_textures(int on);
|
||||
void gfx_set_wrap_fix(int on);
|
||||
void gfx_texture_cache_clear(void);
|
||||
void gfx_texture_cache_delete(const uint8_t *orig_addr);
|
||||
void gfx_texture_cache_delete_range(const uint8_t *start, const uint8_t *end);
|
||||
|
||||
+46
-24
@@ -911,6 +911,10 @@ static void import_texture_ci8(int tile, const LoadedTexture& loaded_texture, bo
|
||||
* Video.FixMipTextures = 0 restores the raw over-tall upload. */
|
||||
bool g_fix_mip_textures = true;
|
||||
|
||||
/* D74 sub-tile UV pre-wrap (see gfx_sp_tri). Opt-in (never-run path); default
|
||||
* off. Video.WrapFix = 1. */
|
||||
bool g_wrap_fix = false;
|
||||
|
||||
static void import_texture(int i, int tile, bool importReplacement) {
|
||||
LoadedTexture& loaded_texture = rdp.loaded_texture[rdp.texture_tile[tile].tmem];
|
||||
const uint8_t fmt = rdp.texture_tile[tile].fmt;
|
||||
@@ -1486,6 +1490,17 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo
|
||||
uint32_t tm = 0;
|
||||
uint32_t tex_width[2], tex_height[2], tex_width2[2], tex_height2[2];
|
||||
|
||||
/* D74 (Video.WrapFix): per-texunit pre-wrap window. N64 wraps a render
|
||||
* tile's UVs at the TILE period (uls/ult + lrs/lrt window) when the tile
|
||||
* is a sub-region of the uploaded image; GL wraps at the full image size.
|
||||
* Computed once per texunit here (needs the ORIGINAL cms/cmt, before the
|
||||
* CLAMP-clearing below) and applied per vertex in the loop. Opt-in --
|
||||
* this path never ran before (the old guard was `cms & G_TX_WRAP` ==
|
||||
* `& 0`), so it is new behaviour. */
|
||||
bool wrap_s[2] = { false, false }, wrap_t[2] = { false, false };
|
||||
float wrap_tw[2] = { 0, 0 }, wrap_th[2] = { 0, 0 };
|
||||
float wrap_uls[2] = { 0, 0 }, wrap_ult[2] = { 0, 0 };
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
// TODO: fix this; for now just ignore smaller mips
|
||||
const uint32_t tile = rdp.first_tile_index + gfx_lod_tile_offset(i);
|
||||
@@ -1529,6 +1544,21 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo
|
||||
uint32_t tex_width1 = tex_width[i] << (cms & G_TX_MIRROR);
|
||||
uint32_t tex_height1 = tex_height[i] << (cmt & G_TX_MIRROR);
|
||||
|
||||
if (g_wrap_fix && !(cms & G_TX_MIRROR)) {
|
||||
/* wrap tile (clamp bit not set) whose window is smaller than
|
||||
* the uploaded image -> pre-fmod the UVs at the window size. */
|
||||
if (!(cms & G_TX_CLAMP) && tex_width2[i] > 0 && tex_width2[i] < tex_width[i]) {
|
||||
wrap_s[i] = true;
|
||||
wrap_tw[i] = (float)tex_width2[i];
|
||||
wrap_uls[i] = rdp.texture_tile[tile].uls / 4.0f;
|
||||
}
|
||||
if (!(cmt & G_TX_CLAMP) && tex_height2[i] > 0 && tex_height2[i] < tex_height[i]) {
|
||||
wrap_t[i] = true;
|
||||
wrap_th[i] = (float)tex_height2[i];
|
||||
wrap_ult[i] = rdp.texture_tile[tile].ult / 4.0f;
|
||||
}
|
||||
}
|
||||
|
||||
if ((cms & G_TX_CLAMP) && ((cms & G_TX_MIRROR) || tex_width1 != tex_width2[i])) {
|
||||
tm |= 1 << 2 * i;
|
||||
cms &= ~G_TX_CLAMP;
|
||||
@@ -1618,30 +1648,21 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo
|
||||
u -= rdp.texture_tile[rdp.first_tile_index + tile].uls / 4.0f;
|
||||
v -= rdp.texture_tile[rdp.first_tile_index + tile].ult / 4.0f;
|
||||
|
||||
// D74: N64 wraps UVs by the TILE size when a render tile is a
|
||||
// sub-region of the image (uls/ult offset + lrs/lrt window); GL
|
||||
// would wrap at the full uploaded image size instead. Pre-wrap per
|
||||
// vertex (GE/PD triangles never span more than one tile period).
|
||||
// NOTE (SMALL-FIXES B1, DEFERRED): this block's guard is dead
|
||||
// (`& G_TX_WRAP` == `& 0`) and its indices are OOB (`[i]` is the
|
||||
// vertex, arrays are per-texunit [2]). Correcting it to
|
||||
// `(cms & G_TX_CLAMP) == 0` + `[t]` activates never-run code and
|
||||
// crashed -level_09 at boot (0 frames) -- needs the hoist-out-of-
|
||||
// -loop rework + per-level visual verification, not an in-place
|
||||
// one-liner. Left inert for now.
|
||||
{
|
||||
const uint32_t tw = tex_width2[i];
|
||||
const uint32_t th = tex_height2[i];
|
||||
if ((rdp.texture_tile[rdp.first_tile_index + tile].cms & G_TX_WRAP) && tw < tex_width[i]) {
|
||||
u = fmodf(u, (float)tw);
|
||||
if (u < 0.0f) u += (float)tw;
|
||||
u += rdp.texture_tile[rdp.first_tile_index + tile].uls / 4.0f;
|
||||
}
|
||||
if ((rdp.texture_tile[rdp.first_tile_index + tile].cmt & G_TX_WRAP) && th < tex_height[i]) {
|
||||
v = fmodf(v, (float)th);
|
||||
if (v < 0.0f) v += (float)th;
|
||||
v += rdp.texture_tile[rdp.first_tile_index + tile].ult / 4.0f;
|
||||
}
|
||||
// D74 (Video.WrapFix, opt-in): pre-wrap UVs at the tile-window
|
||||
// period when the render tile is a sub-region of the uploaded
|
||||
// image. Flags/sizes are precomputed per texunit above (indexed by
|
||||
// `t`, not the vertex `i`). The old in-place version was inert
|
||||
// (guard `cms & G_TX_WRAP` == `& 0`) and OOB (`tex_width2[i]` with
|
||||
// `i` = vertex). See SMALL-FIXES B1.
|
||||
if (wrap_s[t]) {
|
||||
u = fmodf(u, wrap_tw[t]);
|
||||
if (u < 0.0f) u += wrap_tw[t];
|
||||
u += wrap_uls[t];
|
||||
}
|
||||
if (wrap_t[t]) {
|
||||
v = fmodf(v, wrap_th[t]);
|
||||
if (v < 0.0f) v += wrap_th[t];
|
||||
v += wrap_ult[t];
|
||||
}
|
||||
|
||||
if (!is_rect) {
|
||||
@@ -3011,6 +3032,7 @@ extern "C" void gfx_set_mipmap_filter(enum MipmapFilteringMode mode) {
|
||||
}
|
||||
|
||||
extern "C" void gfx_set_fix_mip_textures(int on) { g_fix_mip_textures = !!on; }
|
||||
extern "C" void gfx_set_wrap_fix(int on) { g_wrap_fix = !!on; }
|
||||
|
||||
extern "C" int gfx_create_framebuffer(uint32_t width, uint32_t height, int upscale, int autoresize) {
|
||||
int fb = gfx_rapi->create_framebuffer();
|
||||
|
||||
@@ -56,6 +56,7 @@ static int cfgFpsCap = 0; /* frame cap in fps; 0 = uncapped (vsync)
|
||||
static int cfgMSAA = 1; /* 1/2/4/8 samples; 1 = off */
|
||||
static int cfgTexFilter = 1; /* 0 = nearest, 1 = bilinear (default), 2 = N64 3-point + trilinear */
|
||||
static int cfgFixMipTex = 1; /* RC2: clip mip-contaminated texture uploads to base height */
|
||||
static int cfgWrapFix = 0; /* D74: sub-tile UV pre-wrap (opt-in, never-run path) */
|
||||
static int cfgFullscreen = 0; /* 0 = windowed, 1 = borderless fullscreen */
|
||||
|
||||
/*
|
||||
@@ -77,6 +78,7 @@ PD_CONSTRUCTOR static void videoConfigInit(void)
|
||||
configRegisterInt("Video.MSAA", &cfgMSAA, 1, 8);
|
||||
configRegisterInt("Video.TextureFilter", &cfgTexFilter, 0, 2);
|
||||
configRegisterInt("Video.FixMipTextures", &cfgFixMipTex, 0, 1);
|
||||
configRegisterInt("Video.WrapFix", &cfgWrapFix, 0, 1);
|
||||
configRegisterInt("Video.Fullscreen", &cfgFullscreen, 0, 1);
|
||||
configRegisterInt("Window.Width", &cfgWinW, 0, 16384);
|
||||
configRegisterInt("Window.Height", &cfgWinH, 0, 16384);
|
||||
@@ -140,6 +142,7 @@ int videoInit(void)
|
||||
* NOT fix the Depot roof, see docs/BRIEF-B2-depot-textures.md). All keep
|
||||
* point-sampled tiles (HUD, G_TF_POINT) crisp via the per-tile flag. */
|
||||
gfx_set_fix_mip_textures(cfgFixMipTex);
|
||||
gfx_set_wrap_fix(cfgWrapFix);
|
||||
|
||||
if (cfgTexFilter >= 2) {
|
||||
gfx_set_texture_filter(FILTER_THREE_POINT);
|
||||
|
||||
Reference in new issue
Block a user