feat(vk): the upscalers' texture LOD bias at Auto, from the size drawn #1654

Closed
TwoToneEddy wants to merge 6 commits from TwoToneEddy/upscale-lod-bias into main
TwoToneEddy commented 2026-11-10 12:16:59 +00:00 (Migrated from github.com)

Main's upscaler texture LOD bias (#1898) is 0 at Auto, because the menu does not know the size the game's dynamic resolution draws. A scene the game shrank below its 3/4 under DLSS, FSR 3.1 or FSR 4 therefore lost its textures' detail there.

What this adds

  • Auto is covered. Both upscalers report the size they drew from (upscale_lod_drew, called from temporal_upscale and fsr3_upscale). At Auto the bias is main's same log2(share / 0.75) of that measured share, in quarter mip levels (gpu/vk/upscale_lod_bias.h).
  • A step holds at its edge. A step is left only once the size is an eighth of a level past its edge, so a size hovering between two steps does not make the samplers anew every frame.
  • Another step makes the samplers anew (samplers_changed()), after the step is stored.

What it leaves as on main

  • upscale_lod_bias()'s rule: only the samplers the game biases below 0.
  • The fixed Render resolutions, which keep the menu's share.
  • RX_VK_UPSCALE_LOD_BIAS=0 turns it off. There is no strength setting.

The log's vk: upscaler LOD bias at Auto: lines say what is measured.

Checked

  • tests/test_upscale_lod_bias.py: the steps and the hold at an edge as C++ unit tests, and that upscale_lod_drew is outside vk_draw.cpp's anonymous namespace (it did not link before).
  • vk_draw.cpp built to an object with g++: mkwvk::upscale_lod_drew is an exported symbol. The whole renderer was not linked here.
  • Not run in the game.

🤖 Generated with Claude Code

Main's upscaler texture LOD bias (#1898) is 0 at Auto, because the menu does not know the size the game's dynamic resolution draws. A scene the game shrank below its 3/4 under DLSS, FSR 3.1 or FSR 4 therefore lost its textures' detail there. **What this adds** - **Auto is covered.** Both upscalers report the size they drew from (`upscale_lod_drew`, called from `temporal_upscale` and `fsr3_upscale`). At Auto the bias is main's same `log2(share / 0.75)` of that measured share, in quarter mip levels (`gpu/vk/upscale_lod_bias.h`). - **A step holds at its edge.** A step is left only once the size is an eighth of a level past its edge, so a size hovering between two steps does not make the samplers anew every frame. - **Another step makes the samplers anew** (`samplers_changed()`), after the step is stored. **What it leaves as on main** - `upscale_lod_bias()`'s rule: only the samplers the game biases below 0. - The fixed Render resolutions, which keep the menu's share. - `RX_VK_UPSCALE_LOD_BIAS=0` turns it off. There is no strength setting. The log's `vk: upscaler LOD bias at Auto:` lines say what is measured. **Checked** - `tests/test_upscale_lod_bias.py`: the steps and the hold at an edge as C++ unit tests, and that `upscale_lod_drew` is outside `vk_draw.cpp`'s anonymous namespace (it did not link before). - `vk_draw.cpp` built to an object with g++: `mkwvk::upscale_lod_drew` is an exported symbol. The whole renderer was not linked here. - Not run in the game. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
hckrman101 (Migrated from github.com) approved these changes 2026-11-10 16:41:02 +00:00
hckrman101 (Migrated from github.com) left a comment

Read through the diff and the surrounding code on main. The design holds together:

  • The bias only goes to the scene's own mipmapped fragment-stage textures (!gpu_written, levels > 1), never to compare samplers or ones without a mip filter, and only for the jittered B10G11R11 scene target at the size the upscaler last took. It is 0 for DLAA.
  • A biased sampler has its own key in sampler_make, with the unbiased key unchanged. sampler_for has a separate biased table that checks the steps it was filled for.
  • last_desc_lod_steps is part of same_desc, so a draw with another bias rebuilds its descriptors, and this also holds with RX_VK_DESC_SLOTGEN. The compute path's build_descriptors is not affected because of the fragment-stage gate.
  • The quarter-step rounding and the 2-level clamp keep the number of samplers small.

Nits and housekeeping:

  • The PR currently shows as not mergeable (conflicts with main), so it needs a rebase before it can go in.
  • tests/test_upscale_lod_bias.py is picked up by run_all.py automatically but runs with its default --cxx g++. Other C++ tests list ["--cxx", "{cxx}"] in ARGS, which would also cover a Windows runner without g++ on PATH.
  • The Python test is mostly string matching on vk_draw.cpp, so it will break on harmless refactors. The C++ unit test is the useful part.
  • The bias applies to FSR 3.1 via fsr3_inputs::jitter_size. #1008's FSR 4 path doesn't set this, so it keeps the unbiased mips. That seems fine for now, but it is worth a follow-up if FSR 4 wants the same.

Not run in-game as the description says, so I haven't seen how it looks. Approving on the code.

Read through the diff and the surrounding code on main. The design holds together: - The bias only goes to the scene's own mipmapped fragment-stage textures (`!gpu_written`, `levels > 1`), never to compare samplers or ones without a mip filter, and only for the jittered B10G11R11 scene target at the size the upscaler last took. It is 0 for DLAA. - A biased sampler has its own key in `sampler_make`, with the unbiased key unchanged. `sampler_for` has a separate biased table that checks the steps it was filled for. - `last_desc_lod_steps` is part of `same_desc`, so a draw with another bias rebuilds its descriptors, and this also holds with `RX_VK_DESC_SLOTGEN`. The compute path's `build_descriptors` is not affected because of the fragment-stage gate. - The quarter-step rounding and the 2-level clamp keep the number of samplers small. Nits and housekeeping: - The PR currently shows as not mergeable (conflicts with main), so it needs a rebase before it can go in. - `tests/test_upscale_lod_bias.py` is picked up by `run_all.py` automatically but runs with its default `--cxx g++`. Other C++ tests list `["--cxx", "{cxx}"]` in `ARGS`, which would also cover a Windows runner without `g++` on PATH. - The Python test is mostly string matching on `vk_draw.cpp`, so it will break on harmless refactors. The C++ unit test is the useful part. - The bias applies to FSR 3.1 via `fsr3_inputs::jitter_size`. #1008's FSR 4 path doesn't set this, so it keeps the unbiased mips. That seems fine for now, but it is worth a follow-up if FSR 4 wants the same. Not run in-game as the description says, so I haven't seen how it looks. Approving on the code.
hckrman101 commented 2026-11-10 17:50:07 +00:00 (Migrated from github.com)

Heads-up: this conflicts with main now (a lot landed today). Could you merge main into the branch (or rebase) and resolve the conflicts? Thanks!

Heads-up: this conflicts with main now (a lot landed today). Could you merge main into the branch (or rebase) and resolve the conflicts? Thanks!
TwoToneEddy commented 2026-11-10 18:18:27 +00:00 (Migrated from github.com)

Thanks for the review. Main is merged in, and each of your points is answered below.

The PR currently shows as not mergeable (conflicts with main), so it needs a rebase before it can go in.

Done. It is also ported to the TemporalEngine chain (#1008): the scale-to width now comes from temporal_jitter_size axis 3 in vk_temporal.cpp, with fsr3_inputs::jitter_size kept for FSR 3.1.

tests/test_upscale_lod_bias.py […] runs with its default --cxx g++.

Fixed. The test now declares RUN_ALL_ARGS = ["--cxx", "{cxx}"] itself, since the central ARGS table is retired on main.

The Python test is mostly string matching on vk_draw.cpp, so it will break on harmless refactors.

Agreed. I've kept it in line with the other source-reading checks; the C++ unit test carries the logic.

#1008's FSR 4 path doesn't set this, so it keeps the unbiased mips.

Covered by the port. FSR 4 runs on the same chain as DLSS, so it takes the bias too (none for its Native AA, as for DLAA). Docs and readme are updated.

Checked

  • tests/test_upscale_lod_bias.py passes, and the changed files pass a g++ syntax pass.
  • Merges cleanly together with #1653.
  • Still not run in-game.
Thanks for the review. Main is merged in, and each of your points is answered below. > The PR currently shows as not mergeable (conflicts with main), so it needs a rebase before it can go in. Done. It is also ported to the TemporalEngine chain (#1008): the scale-to width now comes from `temporal_jitter_size` axis 3 in `vk_temporal.cpp`, with `fsr3_inputs::jitter_size` kept for FSR 3.1. > `tests/test_upscale_lod_bias.py` […] runs with its default `--cxx g++`. Fixed. The test now declares `RUN_ALL_ARGS = ["--cxx", "{cxx}"]` itself, since the central `ARGS` table is retired on main. > The Python test is mostly string matching on `vk_draw.cpp`, so it will break on harmless refactors. Agreed. I've kept it in line with the other source-reading checks; the C++ unit test carries the logic. > #1008's FSR 4 path doesn't set this, so it keeps the unbiased mips. Covered by the port. FSR 4 runs on the same chain as DLSS, so it takes the bias too (none for its Native AA, as for DLAA). Docs and readme are updated. **Checked** - `tests/test_upscale_lod_bias.py` passes, and the changed files pass a g++ syntax pass. - Merges cleanly together with #1653. - Still not run in-game.
hckrman101 (Migrated from github.com) reviewed 2026-11-11 02:16:55 +00:00
hckrman101 (Migrated from github.com) left a comment

Thanks for the merge and the answers. All four points from my last review are dealt with: the test now declares RUN_ALL_ARGS = ["--cxx", "{cxx}"], the string-matching test is a fair call to keep, and the port to the TemporalEngine chain (temporal_jitter_size axis 3, set beside jitter_w/jitter_h in temporal_upscale) is right. FSR 4 now gets the bias and Native AA gets none, because rw == dw there. The new code is fine as far as it goes.

But main has moved under it again, and this time it's my fault: #1898 (merged at 19:53, after your 18:15 merge) landed an upscaler LOD bias of its own in vk_draw.cpp (upscale_lod_bias(), added in sampler_make and part of the sampler key). That's why the PR is conflicting again (vk_draw.cpp, vk_temporal.*, vk_fsr3_inputs.*, readme.md, docs/development.md). Sorry about that. A plain merge would stack two biases, so the two need reconciling first:

  • Same env var, different meaning. Main's RX_VK_UPSCALE_LOD_BIAS is just "0 = off". Here it's a 0..2 strength. If this PR's strength is kept, main's readme line needs updating too.
  • The game's own bias. OoT already gives its world materials lod_bias = -0.5 for its 3/4 render (that's what the sampler log in #1898 showed). Main only adds log2(share / 0.75) on top of that, and only to the samplers the game biases below 0. This PR adds the full log2(render / picture) to every mipmapped scene texture, so those materials end up about 0.5 past the guides' number. DLSS Quality would be -1.0 total instead of about -0.58, and Performance -1.5 instead of -1.0. See inline.
  • What this PR adds over main. Main returns 0 at Auto (dynamic resolution) and works from the menu's share rather than the size actually drawn. This PR follows the scene's real width each frame via the jitter sizes, and that's the part worth keeping.

My suggestion: rebase onto main's upscale_lod_bias(), and change it (or replace it) to use your measured scene width / picture width relative to the game's 3/4, so that Auto is covered as well. Keep main's rule of biasing only the samplers the game biases, or say why the others (textures the game left at 0) should get it too. Then use one env var with one meaning. I'd also like @NotRexed's view on which shape he wants.

CI hasn't run here (no checks reported while it conflicts). It's still not run in the game, which matters more for a sharpness change like this one.

Thanks for the merge and the answers. All four points from my last review are dealt with: the test now declares `RUN_ALL_ARGS = ["--cxx", "{cxx}"]`, the string-matching test is a fair call to keep, and the port to the TemporalEngine chain (`temporal_jitter_size` axis 3, set beside `jitter_w`/`jitter_h` in `temporal_upscale`) is right. FSR 4 now gets the bias and Native AA gets none, because `rw == dw` there. The new code is fine as far as it goes. But main has moved under it again, and this time it's my fault: #1898 (merged at 19:53, after your 18:15 merge) landed an upscaler LOD bias of its own in `vk_draw.cpp` (`upscale_lod_bias()`, added in `sampler_make` and part of the sampler key). That's why the PR is conflicting again (`vk_draw.cpp`, `vk_temporal.*`, `vk_fsr3_inputs.*`, `readme.md`, `docs/development.md`). Sorry about that. A plain merge would stack two biases, so the two need reconciling first: - **Same env var, different meaning.** Main's `RX_VK_UPSCALE_LOD_BIAS` is just "0 = off". Here it's a 0..2 strength. If this PR's strength is kept, main's readme line needs updating too. - **The game's own bias.** OoT already gives its world materials `lod_bias = -0.5` for its 3/4 render (that's what the sampler log in #1898 showed). Main only adds `log2(share / 0.75)` on top of that, and only to the samplers the game biases below 0. This PR adds the full `log2(render / picture)` to every mipmapped scene texture, so those materials end up about 0.5 past the guides' number. DLSS Quality would be -1.0 total instead of about -0.58, and Performance -1.5 instead of -1.0. See inline. - **What this PR adds over main.** Main returns 0 at Auto (dynamic resolution) and works from the menu's share rather than the size actually drawn. This PR follows the scene's real width each frame via the jitter sizes, and that's the part worth keeping. My suggestion: rebase onto main's `upscale_lod_bias()`, and change it (or replace it) to use your measured `scene width / picture width` relative to the game's 3/4, so that Auto is covered as well. Keep main's rule of biasing only the samplers the game biases, or say why the others (textures the game left at 0) should get it too. Then use one env var with one meaning. I'd also like @NotRexed's view on which shape he wants. CI hasn't run here (no checks reported while it conflicts). It's still not run in the game, which matters more for a sharpness change like this one.
hckrman101 (Migrated from github.com) commented 2026-11-11 02:16:55 +00:00

p.lod_bias is already -0.5 for the game's world materials (its own bias for the 3/4 render), and the full log2(render/picture) goes on top of it here. With DLSS Quality that's about -1.0 in total, where the guides ask for about -0.58. On main, upscale_lod_bias() (#1898) only adds the part below 3/4 for that reason.

`p.lod_bias` is already -0.5 for the game's world materials (its own bias for the 3/4 render), and the full `log2(render/picture)` goes on top of it here. With DLSS Quality that's about -1.0 in total, where the guides ask for about -0.58. On main, `upscale_lod_bias()` (#1898) only adds the part below 3/4 for that reason.
TwoToneEddy (Migrated from github.com) reviewed 2026-11-11 07:36:29 +00:00
TwoToneEddy (Migrated from github.com) commented 2026-11-11 07:36:29 +00:00

No problem, and thanks for the detail. Main is merged in and I've reconciled the two the way you suggested.

  • Nothing stacks. My per-draw bias is removed. upscale_lod_bias(), its rule (only the samplers the game biases below 0) and RX_VK_UPSCALE_LOD_BIAS=0 are main's, unchanged; the 0..2 strength is gone.
  • What's left is Auto. The upscalers report the size they drew from (upscale_lod_drew, called from temporal_upscale and fsr3_upscale), and at Auto the bias is log2(share / 0.75) of that, in quarter mip levels. Quarter levels because the size moves frame to frame and samplers are never destroyed. samplers_changed() is called when the step moves.
  • Fixed Render resolutions are exactly as on main. I left that path alone so this PR changes nothing for it. If you or @NotRexed would rather use the measured size everywhere, that's a small change and I'm happy to make it.

Readme, docs row and tests are updated to match. tests/run_all.py fails only where main does on my machine. Still not run in-game. I'll update the PR title and description, which still describe the earlier, larger change.

No problem, and thanks for the detail. Main is merged in and I've reconciled the two the way you suggested. - **Nothing stacks.** My per-draw bias is removed. `upscale_lod_bias()`, its rule (only the samplers the game biases below 0) and `RX_VK_UPSCALE_LOD_BIAS=0` are main's, unchanged; the 0..2 strength is gone. - **What's left is Auto.** The upscalers report the size they drew from (`upscale_lod_drew`, called from `temporal_upscale` and `fsr3_upscale`), and at Auto the bias is `log2(share / 0.75)` of that, in quarter mip levels. Quarter levels because the size moves frame to frame and samplers are never destroyed. `samplers_changed()` is called when the step moves. - **Fixed Render resolutions are exactly as on main.** I left that path alone so this PR changes nothing for it. If you or @NotRexed would rather use the measured size everywhere, that's a small change and I'm happy to make it. Readme, docs row and tests are updated to match. `tests/run_all.py` fails only where main does on my machine. Still not run in-game. I'll update the PR title and description, which still describe the earlier, larger change.
Joey-Magnus commented 2026-11-11 14:37:05 +00:00 (Migrated from github.com)

A heads-up before this gets merged: on today's main (49f75dc8) the PR still merges without a text conflict, but the renderer no longer links. The build stops with:

hookshot_vk.so has 1 unresolved symbol(s); it would not load:
    _ZN5mkwvk16upscale_lod_drewEjj

Cause: in gpu/vk/vk_draw.cpp on main, the anonymous namespace opened at line 72 now reaches past where this PR adds upscale_lod_drew() (around line 2333). The function becomes file-local, while vk_temporal.cpp and vk_fsr3.cpp call it through vk_draw.h.

Fix that works for me: close the anonymous namespace just around that one function. It still sees the file-local upscale_lod_auto_steps and the other names next to it.

}   // namespace (upscale_lod_drew is called from vk_temporal.cpp and vk_fsr3.cpp, so it is not in the anonymous one)
void upscale_lod_drew(uint32_t scene_width, uint32_t picture_width) {
    ...
}
namespace {

Checked: with that change the renderer links, tests/test_upscale_lod_bias.py passes, and the full tests/run_all.py passes. That was on main 49f75dc8 with this PR and about 30 other open PRs merged, on Linux with Clang through emsdk. Not run in game yet.

🤖 Generated with Claude Code

A heads-up before this gets merged: on today's main (`49f75dc8`) the PR still merges without a text conflict, but the renderer no longer links. The build stops with: ``` hookshot_vk.so has 1 unresolved symbol(s); it would not load: _ZN5mkwvk16upscale_lod_drewEjj ``` **Cause:** in `gpu/vk/vk_draw.cpp` on main, the anonymous namespace opened at line 72 now reaches past where this PR adds `upscale_lod_drew()` (around line 2333). The function becomes file-local, while `vk_temporal.cpp` and `vk_fsr3.cpp` call it through `vk_draw.h`. **Fix that works for me:** close the anonymous namespace just around that one function. It still sees the file-local `upscale_lod_auto_steps` and the other names next to it. ```cpp } // namespace (upscale_lod_drew is called from vk_temporal.cpp and vk_fsr3.cpp, so it is not in the anonymous one) void upscale_lod_drew(uint32_t scene_width, uint32_t picture_width) { ... } namespace { ``` **Checked:** with that change the renderer links, `tests/test_upscale_lod_bias.py` passes, and the full `tests/run_all.py` passes. That was on main `49f75dc8` with this PR and about 30 other open PRs merged, on Linux with Clang through emsdk. Not run in game yet. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
hckrman101 (Migrated from github.com) reviewed 2026-11-11 18:25:46 +00:00
hckrman101 (Migrated from github.com) left a comment

Thanks for reconciling it with #1898. The points from my last review are dealt with:

  • Nothing stacks any more. The per-draw bias is gone, and main's upscale_lod_bias() with its rule (only the samplers the game biases below 0, log2(share / 0.75)) is used as is.
  • One env var, one meaning. RX_VK_UPSCALE_LOD_BIAS=0 is off, as on main, and the 0..2 strength is gone.
  • Auto is covered. This was the part worth keeping. Both upscalers report the size they drew from (upscale_lod_drew in temporal_upscale and fsr3_upscale). The quarter-level steps from upscale_lod_bias.h are relative to the game's 3/4, and moving to a new step bumps the samplers' generation. That looks right to me, and so do the unit tests. Keeping the fixed Render resolutions exactly as on main is fine for this PR.

Still open:

  • It doesn't link. Joey-Magnus already reported this above, and it applies to this head too, not just to newer main. In vk_draw.cpp the anonymous namespace that opens near the top of the file (line 68 here) only closes at line 3283, so upscale_lod_drew at 2193 is defined in it. The mkwvk::upscale_lod_drew that vk_draw.h declares and vk_temporal.cpp/vk_fsr3.cpp call is then never defined. Main's upscale_lod_bias() sits in the same namespace, but only this file uses it. Closing the anonymous namespace around the one function, as Joey suggested, fixes it. A check in test_upscale_lod_bias.py would also help, since none of the source-reading checks would catch this.
  • Conflicts again. GitHub shows the branch as conflicting with main (43 commits ahead since your merge; vk_draw.cpp, vk_temporal.cpp, readme.md and docs/development.md all moved), so it needs another merge of main. CI hasn't run beyond the title check because of that.
  • Title and description. You said you'd update them, but they still describe the earlier per-draw bias with its 0..2 strength and "FSR 3.1" only. Something like "the upscalers' texture LOD bias at Auto, from the size drawn" would match what's left.

One small thing, see inline: a share sitting on a quarter-step boundary could flip the step from frame to frame.

Still not run in the game, and @NotRexed hasn't said which shape he wants yet. Once it links and is merged up, I'm fine with it on the code.

Thanks for reconciling it with #1898. The points from my last review are dealt with: - **Nothing stacks any more.** The per-draw bias is gone, and main's `upscale_lod_bias()` with its rule (only the samplers the game biases below 0, `log2(share / 0.75)`) is used as is. - **One env var, one meaning.** `RX_VK_UPSCALE_LOD_BIAS=0` is off, as on main, and the 0..2 strength is gone. - **Auto is covered.** This was the part worth keeping. Both upscalers report the size they drew from (`upscale_lod_drew` in `temporal_upscale` and `fsr3_upscale`). The quarter-level steps from `upscale_lod_bias.h` are relative to the game's 3/4, and moving to a new step bumps the samplers' generation. That looks right to me, and so do the unit tests. Keeping the fixed Render resolutions exactly as on main is fine for this PR. Still open: - **It doesn't link.** Joey-Magnus already reported this above, and it applies to this head too, not just to newer main. In `vk_draw.cpp` the anonymous namespace that opens near the top of the file (line 68 here) only closes at line 3283, so `upscale_lod_drew` at 2193 is defined in it. The `mkwvk::upscale_lod_drew` that `vk_draw.h` declares and `vk_temporal.cpp`/`vk_fsr3.cpp` call is then never defined. Main's `upscale_lod_bias()` sits in the same namespace, but only this file uses it. Closing the anonymous namespace around the one function, as Joey suggested, fixes it. A check in `test_upscale_lod_bias.py` would also help, since none of the source-reading checks would catch this. - **Conflicts again.** GitHub shows the branch as conflicting with main (43 commits ahead since your merge; `vk_draw.cpp`, `vk_temporal.cpp`, `readme.md` and `docs/development.md` all moved), so it needs another merge of main. CI hasn't run beyond the title check because of that. - **Title and description.** You said you'd update them, but they still describe the earlier per-draw bias with its 0..2 strength and "FSR 3.1" only. Something like "the upscalers' texture LOD bias at Auto, from the size drawn" would match what's left. One small thing, see inline: a share sitting on a quarter-step boundary could flip the step from frame to frame. Still not run in the game, and @NotRexed hasn't said which shape he wants yet. Once it links and is merged up, I'm fine with it on the code.
hckrman101 (Migrated from github.com) commented 2026-11-11 18:25:46 +00:00

This definition is inside the anonymous namespace that opens at line 68 and closes at 3283, so it's a file-local function, not the mkwvk::upscale_lod_drew that vk_draw.h declares. vk_temporal.cpp and vk_fsr3.cpp then hit an unresolved symbol (Joey-Magnus's _ZN5mkwvk16upscale_lod_drewEjj). } // namespace before it and namespace { after it fixes this.

This definition is inside the anonymous namespace that opens at line 68 and closes at 3283, so it's a file-local function, not the `mkwvk::upscale_lod_drew` that `vk_draw.h` declares. `vk_temporal.cpp` and `vk_fsr3.cpp` then hit an unresolved symbol (Joey-Magnus's `_ZN5mkwvk16upscale_lod_drewEjj`). `} // namespace` before it and `namespace {` after it fixes this.
hckrman101 (Migrated from github.com) commented 2026-11-11 18:25:46 +00:00

Nit / worth watching in the game: at Auto, if the dynamic resolution hovers where lround flips between two quarter steps, this bumps the samplers' generation every frame or two. That empties sampler_for's tables and descriptor reuse each time. The told log stops after 16 lines, so you'd see it as a burst at start. If it happens, a little hysteresis (only move once the unrounded value is past the boundary by, say, an eighth of a level) would keep it steady.

Nit / worth watching in the game: at Auto, if the dynamic resolution hovers where `lround` flips between two quarter steps, this bumps the samplers' generation every frame or two. That empties `sampler_for`'s tables and descriptor reuse each time. The `told` log stops after 16 lines, so you'd see it as a burst at start. If it happens, a little hysteresis (only move once the unrounded value is past the boundary by, say, an eighth of a level) would keep it steady.
hckrman101 (Migrated from github.com) reviewed 2026-11-11 18:25:47 +00:00
hckrman101 (Migrated from github.com) commented 2026-11-11 18:25:47 +00:00

Thanks, that's resolved: nothing stacks now, and the Auto part is a clean addition on top of main's rule. One thing left, which is the link error (see my new review).

Thanks, that's resolved: nothing stacks now, and the Auto part is a clean addition on top of main's rule. One thing left, which is the link error (see my new review).
TwoToneEddy commented 2026-11-11 19:02:21 +00:00 (Migrated from github.com)

Sorry I didn't mean to close the PR. Hopefully it's all good now

Sorry I didn't mean to close the PR. Hopefully it's all good now
Joey-Magnus (Migrated from github.com) reviewed 2026-11-11 21:46:05 +00:00
Joey-Magnus (Migrated from github.com) left a comment

The anonymous-namespace fix around upscale_lod_drew is in, and tests/test_upscale_lod_bias.py passes on this head. The Windows part 2/2 failure is on a base from before #2397 (the test_native_astc_texture_count fix), so I don't think it's this PR.

It conflicts again because #2441 (merged 14:27) moved the rule into upscaler_rows::upscale_lod_bias_for(up, share, offset). For DLSS/DLAA it now covers Auto by assuming the game's 3/4 and adds RX_VK_DLSS_LOD_OFFSET (-1 by default). That covers part of what this PR adds. What's left is the measured share at Auto, which is worth keeping. I'd turn the measured steps into a share and pass it to upscale_lod_bias_for when resolution_scale() <= 0. Then DLSS gets log2(measured / 0.75) + offset and FSR 3.1/4 get log2(measured / 0.75), without a second Auto path inside upscale_lod_bias(). Note that upscale_lod::steps() clamps at 0 from 3/4 up, which would drop DLSS's offset if used directly. The readme line should then describe the combined rule.

The anonymous-namespace fix around `upscale_lod_drew` is in, and `tests/test_upscale_lod_bias.py` passes on this head. The Windows part 2/2 failure is on a base from before #2397 (the `test_native_astc_texture_count` fix), so I don't think it's this PR. It conflicts again because #2441 (merged 14:27) moved the rule into `upscaler_rows::upscale_lod_bias_for(up, share, offset)`. For DLSS/DLAA it now covers Auto by assuming the game's 3/4 and adds `RX_VK_DLSS_LOD_OFFSET` (-1 by default). That covers part of what this PR adds. What's left is the measured share at Auto, which is worth keeping. I'd turn the measured steps into a share and pass it to `upscale_lod_bias_for` when `resolution_scale() <= 0`. Then DLSS gets `log2(measured / 0.75) + offset` and FSR 3.1/4 get `log2(measured / 0.75)`, without a second Auto path inside `upscale_lod_bias()`. Note that `upscale_lod::steps()` clamps at 0 from 3/4 up, which would drop DLSS's offset if used directly. The readme line should then describe the combined rule.
hckrman101 commented 2026-11-11 22:55:34 +00:00 (Migrated from github.com)

This now conflicts with main in docs/development.md, gpu/vk/vk_draw.cpp, readme.md. Could you merge main into the branch (or rebase) when you get a chance? I'll take another look once it's up to date.

This now conflicts with main in `docs/development.md`, `gpu/vk/vk_draw.cpp`, `readme.md`. Could you merge main into the branch (or rebase) when you get a chance? I'll take another look once it's up to date.
github-sync closed this pull request 2026-11-12 06:22:48 +00:00
Owner

@TwoToneEddy commented on GitHub · 2026-11-12 05:49 UTC · original

I think I'll leave it now, I've synced my fork and merge main so many times now and I see no indication this will ever be merged

> [@TwoToneEddy](https://github.com/TwoToneEddy) commented on GitHub · 2026-11-12 05:49 UTC · [original](https://github.com/NotRexed/Hookshot/pull/1654#issuecomment-6815841742) I think I'll leave it now, I've synced my fork and merge main so many times now and I see no indication this will ever be merged <!-- github-sync:c:6815841742 -->
Commenting is not possible because the repository is archived.
No description provided.