WIP: perf(vk): keep opaque ASTC textures as BC1, half of BC3's VRAM (RX_VK_ASTC_BC1, off by default) #521

Draft
Amateurwizrd wants to merge 4 commits from Amateurwizrd/Longshot:perf/astc-bc1 into main
Contributor

Why

On a GPU without ASTC (NVIDIA and most desktop AMD cards) every ASTC texture is kept as BC3, 8 bits a texel, though
the opaque ones need only BC1's 4: a card short of VRAM pays for that alpha nobody uses with evictions and uploads.

What changed

  • vk: gpu/vk/astc_opaque.h (new) reads each ASTC block's mode and colour endpoint modes without decoding; void-extent
    blocks with alpha at its maximum and blocks whose every partition's mode carries no alpha are opaque; modes that carry
    alpha, reserved and illegal blocks are not.
  • vk: with RX_VK_ASTC_BC1=1, create in gpu/vk/vk_texture.cpp makes a texture whose every block is opaque as BC1
    (its RGB format, so no block decodes as transparent), before the image is made and counted, so the budget and the
    eviction see BC1's true size.
  • vk: upload_astc_gpu reads each layer of guest memory once into a private copy, judges that copy, and stages the same
    copy; a layer with alpha makes the image again as BC3 (bc1_to_bc3, the texels it holds kept) before anything is
    reserved or recorded, and a refused remake reserves no staging and is tried again.
  • vk: texture_view_of in gpu/vk/vk_draw.cpp resolves the view again when the touch on a cached hit made the image
    again, so the draw samples the new image; a copy between a BC1 and a BC3 texture goes through the encoder
    (gpu/vk/vk_xfer.cpp). The textures' log line counts those kept as BC1 and the MB saved.
  • tests: tests/test_astc_opaque.py (hand-built blocks of every mode and 420,000 random blocks, each one judged opaque
    decoding to alpha 255 in the tree's decoder), tests/test_astc_bc1_remake.py (the real upload, remake and view code
    with a modelled device: alpha appearing, a game write between the judging and the staging, a refused remake, a cached
    view); tests/test_native_astc_texture_count.py and tests/texture_staging_publication_test.cpp follow the new code.
  • docs: docs/development.md documents RX_VK_ASTC_BC1.

Flags and settings

Flag What it does Default now Recommendation Helps on Doesn't help on Untested on
RX_VK_ASTC_BC1=1 Opaque ASTC textures kept as BC1 instead of BC3 where the GPU has no ASTC off off by default; on after testing on 8 GB cards cards short of VRAM: 158-240 MB less in the scenes measured a 16 GB card: nothing gained, frame time within 0.05 ms of off here 8 GB cards, AMD, Intel, GPUs with ASTC (unchanged there)
RX_VK_COUNT_BY_ESTIMATE=1 (existing) The BC3 remake counts its image as create does under this switch; the switch itself is unchanged off unchanged - - -

Measurements

Baseline: this PR @ 1f9c5eb3, RX_VK_ASTC_BC1=0
The switch is off by default, so main and this PR at their defaults run the same path; the comparison is the switch, on
the same build. The branch's head, 3484acbf, adds only the docs/tested/ files of these runs.
main: 9c9d69ed (2026-11-14)
this PR: perf/astc-bc1 @ 1f9c5eb3
Hardware: RTX 5070 Ti 16 GB, driver 621.01, Ryzen 7 7800X3D, 32 GB, Windows 11 Pro 26200
Scene: Kokiri Forest (child) standing, and a scripted Hyrule Field (child) walk; output 2560x1440, render resolution 75% (1920x1080), frame generation off, uncapped, VSync off, sound off, a 1707x960 window
Method: 60 s of PresentMon (MsBetweenPresents) after 15 s of settling, 2 runs each, alternated (off, on, off, on) after a warm-up run, the median of the runs; VRAM from the last vk: VRAM: line and the textures' line of longshot_log.txt
How to reproduce: a save at each spot, RX_VK_ASTC_BC1=0 and =1 in turn on the same build, the numbers from PresentMon and longshot_log.txt

this PR @ 1f9c5eb3, RX_VK_ASTC_BC1=0 this PR @ 1f9c5eb3, RX_VK_ASTC_BC1=1
Kokiri Forest: fps / 1% low 78.6 / 60.9 78.4 / 62.2
Kokiri Forest: median / p99 frame time 12.64 / 14.97 ms 12.69 / 14.82 ms
Kokiri Forest: VRAM in use / textures 6588 / 3768 MB 6562 / 3481 MB
Hyrule Field walk: fps / 1% low 80.7 / 43.5 80.7 / 41.7
Hyrule Field walk: median / p99 frame time 12.09 / 18.77 ms 12.10 / 18.85 ms
Hyrule Field walk: VRAM in use / textures 10742 / 7774 MB 10461 / 7419 MB
RX_VK_ASTC_BC1=0, Kokiri Forest:     median 12.73 / 12.55 ms, p99 15.18 / 14.75 ms; vk: VRAM: 6526 / 6650 MB used, textures 3672 / 3863 MB
RX_VK_ASTC_BC1=1, Kokiri Forest:     median 12.68 / 12.70 ms, p99 14.74 / 14.90 ms; vk: VRAM: 6596 / 6528 MB used, textures 3510 / 3452 MB
                                     (83 kept as BC1, 159 MB less than as BC3, 0 made BC3 again) / (80 kept as BC1, 157 MB less than as BC3, 0 made BC3 again)
RX_VK_ASTC_BC1=0, Hyrule Field walk: median 12.09 / 12.09 ms, p99 18.11 / 19.42 ms; vk: VRAM: 10677 / 10807 MB used, textures 7780 / 7768 MB
RX_VK_ASTC_BC1=1, Hyrule Field walk: median 12.16 / 12.04 ms, p99 19.11 / 18.59 ms; vk: VRAM: 10613 / 10308 MB used, textures 7435 / 7402 MB
                                     (294 kept as BC1, 238 MB less than as BC3, 0 made BC3 again) / (296 kept as BC1, 239 MB less than as BC3, 0 made BC3 again)

An earlier build that carried this change before the review's fixes (3 rounds against the switch off, with Kokiri
Forest at 4K too) agreed: 157-240 MB less VRAM, none made BC3 again, frame time 0.03-0.19 ms longer.

Testing

Tested: python -I -B tests/run_all.py on Windows 11 (llvm-mingw): main @ 9c9d69ed 531 passed, 5 failed; this PR
532 passed and the same 5 failing on main (test_oot_state_tap, test_portable_builder_home,
test_portable_builder_startup, test_tested_configurations, test_walk_key), plus test_gpu_hang_watch, which
fails and passes on reruns of main @ 9c9d69ed itself (a 4 s timing bound) and passed twice alone on this branch. The
renderer builds. In the game, the runs above: no device loss, no texture made BC3 again.

Not tested: frame dumps compared texel by texel (the screenshots are compared by eye); a card short of VRAM,
where the saving matters; GPUs with ASTC, where nothing changes; a Linux build (no Linux machine here).

Needs other testers:

  • 8 GB NVIDIA or AMD card, Windows, RX_VK_ASTC_BC1=1: Hyrule Field and Castle Town against the switch off, expecting less VRAM in the textures' line, fewer evictions and no texture that turns transparent or wrong (request to open)
  • Linux (x86_64, gcc or clang): the renderer builds with this PR, expecting no error in gpu/vk/vk_texture.cpp or gpu/vk/astc_opaque.h (request to open)

Screenshots

Kokiri Forest from the same save after 15 s of settling, the game's own picture (1280x720), attached in the comments:
"this PR @ 1f9c5eb3, RX_VK_ASTC_BC1=0" and "this PR @ 1f9c5eb3, RX_VK_ASTC_BC1=1". The same picture: the differences
are the fairies, the mist and the light moving between the two captures; no texture turned transparent or wrong.

Risk and rollback

With the switch on, a texture judged opaque wrongly would lose its alpha (the judging is checked against the decoder on
420,000 random blocks), and a mixed BC1/BC3 copy goes through the encoder, which costs CPU time. Off by default: nothing
changes unless RX_VK_ASTC_BC1=1 is set; unset it, or revert the commit.

Reviewer notes

The idea is Hookshot-old's e9868252; here the choice is made before the image is made and counted, BC1 is used in its
RGB format, the staged bytes are the judged bytes, and a texture that gains alpha is made again as BC3. Written for
Longshot.

Issues

None

Checklist

For everyone

  • One topic.
  • The title is a Conventional Commit (type(scope): description).
  • Rebased on current main.
  • python -I -B tests/run_all.py run and passing (any failure that also fails on main is named above).
  • Tested in the game, or what wasn't is named under Testing.
  • Testing filled in: what was tested, what wasn't, and what needs other testers (with test requests).
  • Measured: main and this PR at named commits, on the same PC, scene and settings, at least 2 interleaved runs each, the median reported.
  • No game files, dumps, build output or generated files.
  • third_party/ untouched (a new folder with a PROVENANCE.md instead).
  • The license is OK: GPL-3.0-or-later, nothing incompatible and nothing decompiled.

If applicable

  • AI assistance recorded with Assisted-by: / Co-Authored-By: trailers.
  • Flags noted, and the switch reference updated (docs/development.md, the README).
  • Screenshots for a change that shows on screen.
  • A file in docs/tested/ for each new measured run (format in docs/tested-configurations.md; no appended row or assembled view).
  • A check under tests/ that reads changed source updated in this PR, not weakened.
  • Host code builds on both Windows (llvm-mingw) and Linux, with UTF-8 paths. (Windows only so far: Linux is a test request to open)
  • Docs updated.
## Why On a GPU without ASTC (NVIDIA and most desktop AMD cards) every ASTC texture is kept as BC3, 8 bits a texel, though the opaque ones need only BC1's 4: a card short of VRAM pays for that alpha nobody uses with evictions and uploads. ## What changed - vk: `gpu/vk/astc_opaque.h` (new) reads each ASTC block's mode and colour endpoint modes without decoding; void-extent blocks with alpha at its maximum and blocks whose every partition's mode carries no alpha are opaque; modes that carry alpha, reserved and illegal blocks are not. - vk: with `RX_VK_ASTC_BC1=1`, `create` in `gpu/vk/vk_texture.cpp` makes a texture whose every block is opaque as BC1 (its RGB format, so no block decodes as transparent), before the image is made and counted, so the budget and the eviction see BC1's true size. - vk: `upload_astc_gpu` reads each layer of guest memory once into a private copy, judges that copy, and stages the same copy; a layer with alpha makes the image again as BC3 (`bc1_to_bc3`, the texels it holds kept) before anything is reserved or recorded, and a refused remake reserves no staging and is tried again. - vk: `texture_view_of` in `gpu/vk/vk_draw.cpp` resolves the view again when the touch on a cached hit made the image again, so the draw samples the new image; a copy between a BC1 and a BC3 texture goes through the encoder (`gpu/vk/vk_xfer.cpp`). The textures' log line counts those kept as BC1 and the MB saved. - tests: `tests/test_astc_opaque.py` (hand-built blocks of every mode and 420,000 random blocks, each one judged opaque decoding to alpha 255 in the tree's decoder), `tests/test_astc_bc1_remake.py` (the real upload, remake and view code with a modelled device: alpha appearing, a game write between the judging and the staging, a refused remake, a cached view); `tests/test_native_astc_texture_count.py` and `tests/texture_staging_publication_test.cpp` follow the new code. - docs: `docs/development.md` documents `RX_VK_ASTC_BC1`. ## Flags and settings | Flag | What it does | Default now | Recommendation | Helps on | Doesn't help on | Untested on | |---|---|---|---|---|---|---| | `RX_VK_ASTC_BC1=1` | Opaque ASTC textures kept as BC1 instead of BC3 where the GPU has no ASTC | off | off by default; on after testing on 8 GB cards | cards short of VRAM: 158-240 MB less in the scenes measured | a 16 GB card: nothing gained, frame time within 0.05 ms of off here | 8 GB cards, AMD, Intel, GPUs with ASTC (unchanged there) | | `RX_VK_COUNT_BY_ESTIMATE=1` (existing) | The BC3 remake counts its image as `create` does under this switch; the switch itself is unchanged | off | unchanged | - | - | - | ## Measurements Baseline: this PR @ 1f9c5eb3, RX_VK_ASTC_BC1=0 The switch is off by default, so main and this PR at their defaults run the same path; the comparison is the switch, on the same build. The branch's head, 3484acbf, adds only the `docs/tested/` files of these runs. main: 9c9d69ed (2026-11-14) this PR: perf/astc-bc1 @ 1f9c5eb3 Hardware: RTX 5070 Ti 16 GB, driver 621.01, Ryzen 7 7800X3D, 32 GB, Windows 11 Pro 26200 Scene: Kokiri Forest (child) standing, and a scripted Hyrule Field (child) walk; output 2560x1440, render resolution 75% (1920x1080), frame generation off, uncapped, VSync off, sound off, a 1707x960 window Method: 60 s of PresentMon (MsBetweenPresents) after 15 s of settling, 2 runs each, alternated (off, on, off, on) after a warm-up run, the median of the runs; VRAM from the last `vk: VRAM:` line and the textures' line of `longshot_log.txt` How to reproduce: a save at each spot, `RX_VK_ASTC_BC1=0` and `=1` in turn on the same build, the numbers from PresentMon and `longshot_log.txt` | | this PR @ 1f9c5eb3, RX_VK_ASTC_BC1=0 | this PR @ 1f9c5eb3, RX_VK_ASTC_BC1=1 | |---|---|---| | Kokiri Forest: fps / 1% low | 78.6 / 60.9 | 78.4 / 62.2 | | Kokiri Forest: median / p99 frame time | 12.64 / 14.97 ms | 12.69 / 14.82 ms | | Kokiri Forest: VRAM in use / textures | 6588 / 3768 MB | 6562 / 3481 MB | | Hyrule Field walk: fps / 1% low | 80.7 / 43.5 | 80.7 / 41.7 | | Hyrule Field walk: median / p99 frame time | 12.09 / 18.77 ms | 12.10 / 18.85 ms | | Hyrule Field walk: VRAM in use / textures | 10742 / 7774 MB | 10461 / 7419 MB | ``` RX_VK_ASTC_BC1=0, Kokiri Forest: median 12.73 / 12.55 ms, p99 15.18 / 14.75 ms; vk: VRAM: 6526 / 6650 MB used, textures 3672 / 3863 MB RX_VK_ASTC_BC1=1, Kokiri Forest: median 12.68 / 12.70 ms, p99 14.74 / 14.90 ms; vk: VRAM: 6596 / 6528 MB used, textures 3510 / 3452 MB (83 kept as BC1, 159 MB less than as BC3, 0 made BC3 again) / (80 kept as BC1, 157 MB less than as BC3, 0 made BC3 again) RX_VK_ASTC_BC1=0, Hyrule Field walk: median 12.09 / 12.09 ms, p99 18.11 / 19.42 ms; vk: VRAM: 10677 / 10807 MB used, textures 7780 / 7768 MB RX_VK_ASTC_BC1=1, Hyrule Field walk: median 12.16 / 12.04 ms, p99 19.11 / 18.59 ms; vk: VRAM: 10613 / 10308 MB used, textures 7435 / 7402 MB (294 kept as BC1, 238 MB less than as BC3, 0 made BC3 again) / (296 kept as BC1, 239 MB less than as BC3, 0 made BC3 again) ``` An earlier build that carried this change before the review's fixes (3 rounds against the switch off, with Kokiri Forest at 4K too) agreed: 157-240 MB less VRAM, none made BC3 again, frame time 0.03-0.19 ms longer. ## Testing **Tested:** `python -I -B tests/run_all.py` on Windows 11 (llvm-mingw): main @ 9c9d69ed 531 passed, 5 failed; this PR 532 passed and the same 5 failing on main (`test_oot_state_tap`, `test_portable_builder_home`, `test_portable_builder_startup`, `test_tested_configurations`, `test_walk_key`), plus `test_gpu_hang_watch`, which fails and passes on reruns of main @ 9c9d69ed itself (a 4 s timing bound) and passed twice alone on this branch. The renderer builds. In the game, the runs above: no device loss, no texture made BC3 again. **Not tested:** frame dumps compared texel by texel (the screenshots are compared by eye); a card short of VRAM, where the saving matters; GPUs with ASTC, where nothing changes; a Linux build (no Linux machine here). **Needs other testers:** - 8 GB NVIDIA or AMD card, Windows, `RX_VK_ASTC_BC1=1`: Hyrule Field and Castle Town against the switch off, expecting less VRAM in the textures' line, fewer evictions and no texture that turns transparent or wrong (request to open) - Linux (x86_64, gcc or clang): the renderer builds with this PR, expecting no error in `gpu/vk/vk_texture.cpp` or `gpu/vk/astc_opaque.h` (request to open) ## Screenshots Kokiri Forest from the same save after 15 s of settling, the game's own picture (1280x720), attached in the comments: "this PR @ 1f9c5eb3, RX_VK_ASTC_BC1=0" and "this PR @ 1f9c5eb3, RX_VK_ASTC_BC1=1". The same picture: the differences are the fairies, the mist and the light moving between the two captures; no texture turned transparent or wrong. ## Risk and rollback With the switch on, a texture judged opaque wrongly would lose its alpha (the judging is checked against the decoder on 420,000 random blocks), and a mixed BC1/BC3 copy goes through the encoder, which costs CPU time. Off by default: nothing changes unless `RX_VK_ASTC_BC1=1` is set; unset it, or revert the commit. ## Reviewer notes The idea is Hookshot-old's e9868252; here the choice is made before the image is made and counted, BC1 is used in its RGB format, the staged bytes are the judged bytes, and a texture that gains alpha is made again as BC3. Written for Longshot. ## Issues None ## Checklist ### For everyone - [x] One topic. - [x] The title is a Conventional Commit (`type(scope): description`). - [x] Rebased on current `main`. - [x] `python -I -B tests/run_all.py` run and passing (any failure that also fails on `main` is named above). - [x] Tested in the game, or what wasn't is named under Testing. - [x] Testing filled in: what was tested, what wasn't, and what needs other testers (with test requests). - [x] Measured: main and this PR at named commits, on the same PC, scene and settings, at least 2 interleaved runs each, the median reported. - [x] No game files, dumps, build output or generated files. - [x] `third_party/` untouched (a new folder with a `PROVENANCE.md` instead). - [x] The license is OK: GPL-3.0-or-later, nothing incompatible and nothing decompiled. ### If applicable - [x] AI assistance recorded with `Assisted-by:` / `Co-Authored-By:` trailers. - [x] Flags noted, and the switch reference updated (docs/development.md, the README). - [x] Screenshots for a change that shows on screen. - [x] A file in `docs/tested/` for each new measured run (format in `docs/tested-configurations.md`; no appended row or assembled view). - [x] A check under `tests/` that reads changed source updated in this PR, not weakened. - [ ] Host code builds on both Windows (llvm-mingw) and Linux, with UTF-8 paths. (Windows only so far: Linux is a test request to open) - [x] Docs updated.
perf(vk): opaque ASTC textures kept as BC1, half the video memory of BC3 (RX_VK_ASTC_BC1)
Some checks failed
PR description / Description follows the template (pull_request_target) Successful in 8s
Website / Website on Cloudflare (pull_request_target) Has been skipped
CI / Conventional Commit title (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been cancelled
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been cancelled
CI / Workflow lint (actionlint) (pull_request) Has been cancelled
Third-party parts / As their notes say (pull_request) Has been cancelled
Third-party parts / The same as upstream (pull_request) Has been cancelled
1f9c5eb31d
Where the GPU has no ASTC, ASTC textures are kept as BC3, 8 bits a texel; one
with no alpha needs only BC1's 4. With `RX_VK_ASTC_BC1=1` (off by default until
measured in the game) a texture whose every block is provably opaque is made
as BC1. `gpu/vk/astc_opaque.h` reads each block's mode and colour endpoint
modes without decoding: void-extent blocks with alpha at its maximum, and
blocks whose every partition's mode carries no alpha, are opaque; modes that
carry alpha, reserved and illegal blocks are not.

Unlike Hookshot-old's version, the choice is made before the image is made and
counted, so the budget and the eviction see BC1's true size; BC1 is used in its
RGB format, so no block can decode as transparent; each upload judges the very
bytes it stages, and a texture whose memory later holds alpha is made again as
BC3 before anything is encoded (a draw holding the BC1 image's cached view
resolves the new one); a copy between a BC1 and a BC3 texture goes through the
encoder instead of a block copy. The textures' log line counts those kept as
BC1 and the MB saved.

The idea is Hookshot-old's e9868252 (PR 2554); written anew for Longshot.

Measured on an RTX 5070 Ti, 3 rotated rounds against the same build with it
off: 81 textures kept as BC1 at Kokiri Forest (158 MB less than as BC3), about
295 on a Hyrule Field walk (238-240 MB less), none made BC3 again. Frame time
0.19 ms longer at Kokiri Forest (in each round), 0.06 ms on the walk and 0.03 ms
at 4K (noise). Off by default: the saving is for cards short of VRAM.

Tested: tests/test_astc_opaque.py (hand-built blocks of every mode, and
420,000 random blocks: each one judged opaque decodes to alpha 255 in the
tree's decoder), tests/test_astc_bc1_remake.py (new),
tests/test_native_astc_texture_count.py, the renderer builds.
Not tested: the picture against BC3, a card short of VRAM.

Assisted-by: Claude
docs(tested): RX_VK_ASTC_BC1 off and on at Kokiri Forest and a Hyrule Field walk
Some checks failed
PR description / Description follows the template (pull_request_target) Successful in 4s
beanstalk/approval Test farm not requested
CI / Conventional Commit title (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been cancelled
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been cancelled
CI / Workflow lint (actionlint) (pull_request) Has been cancelled
Third-party parts / As their notes say (pull_request) Has been cancelled
Third-party parts / The same as upstream (pull_request) Has been cancelled
Website / Website on Cloudflare (pull_request) Has been cancelled
3484acbff1
Four runs on an RTX 5070 Ti (621.01), Ryzen 7 7800X3D, Windows 11: the switch
off and on, two alternated runs each, at Kokiri Forest standing and on a
Hyrule Field walk, on perf/astc-bc1 1f9c5eb3.

Assisted-by: Claude
Author
Contributor

This PR's own run is in: perf/astc-bc1 @ 1f9c5eb3, RX_VK_ASTC_BC1 off and on alternated, 2 runs each after a warm-up, at Kokiri Forest standing and on a Hyrule Field walk (RTX 5070 Ti, 621.01). With it on: 287 MB fewer texture MB at Kokiri Forest (3481 against 3768) and 355 MB on the walk (7419 against 7774), 157-239 MB of it from BC1 in the textures' line, none made BC3 again; frame time within 0.05 ms either way. The Measurements now show this run instead of the earlier build's; 3484acbf adds its four docs/tested files. Screenshots in the next comment.

This PR's own run is in: perf/astc-bc1 @ 1f9c5eb3, RX_VK_ASTC_BC1 off and on alternated, 2 runs each after a warm-up, at Kokiri Forest standing and on a Hyrule Field walk (RTX 5070 Ti, 621.01). With it on: 287 MB fewer texture MB at Kokiri Forest (3481 against 3768) and 355 MB on the walk (7419 against 7774), 157-239 MB of it from BC1 in the textures' line, none made BC3 again; frame time within 0.05 ms either way. The Measurements now show this run instead of the earlier build's; 3484acbf adds its four docs/tested files. Screenshots in the next comment.
Author
Contributor

Kokiri Forest from the same save after 15 s of settling, the game's own picture. The same picture both ways: the fairies, the mist and the light move between the captures; no texture turned transparent or wrong.

this PR @ 1f9c5eb3, RX_VK_ASTC_BC1=0
this PR @ 1f9c5eb3, RX_VK_ASTC_BC1=0

this PR @ 1f9c5eb3, RX_VK_ASTC_BC1=1
this PR @ 1f9c5eb3, RX_VK_ASTC_BC1=1

Kokiri Forest from the same save after 15 s of settling, the game's own picture. The same picture both ways: the fairies, the mist and the light move between the captures; no texture turned transparent or wrong. this PR @ 1f9c5eb3, RX_VK_ASTC_BC1=0 ![this PR @ 1f9c5eb3, RX_VK_ASTC_BC1=0](https://git.magicbean.dev/attachments/30aad6e0-c7c4-4240-8ca9-1c2edeb9191e) this PR @ 1f9c5eb3, RX_VK_ASTC_BC1=1 ![this PR @ 1f9c5eb3, RX_VK_ASTC_BC1=1](https://git.magicbean.dev/attachments/846a7766-2524-4667-aa2d-8adfdf53c062)
First-time contributor

Hey, I've got an 8 GB RTX 5060 Ti and this PR says it's untested on 8 GB cards. Happy to run it, same route and A/B setup I used for #421, main vs your branch, VRAM and fps per area. Want me to?

Hey, I've got an 8 GB RTX 5060 Ti and this PR says it's untested on 8 GB cards. Happy to run it, same route and A/B setup I used for #421, main vs your branch, VRAM and fps per area. Want me to?
Contributor

We built the same switch on a local branch before seeing this PR. Yours is closer to landing, so we'd rather help it than compete. What we checked at 3484acbf:

  • The opacity rule is sound. We fuzzed astc_opaque::block against a port of host_shaders/astc_decoder.comp (the decoder the renderer runs): 92M random blocks over all 14 footprints, 0 judged opaque that decode with alpha below 1.
  • Game-free checks pass on Linux with g++ and clang (the 14 that touch these files), and the branch merges into main aa95d35f with no conflicts.

Two things we found:

  1. Low: a BC1 → BC1 copy can be lost if an upload later in the same recording makes that texture BC3 (vk_xfer.cpp:274; the conversion's blit runs before the recording, vk_texture.cpp:2583). Rare. We have a small patch with a test.
  2. Cost on a slow CPU: each opaque texture is scanned twice, at create and at its first upload. About 100 ms for the terrain array on a Zen 2 CPU. A desktop won't show it; a Deck might.

What we can offer, if you want any of it:

  • The patch for 1, and a test that pins the decoder and encoder functions the rule relies on: two commits on your head, on our fork as help-521-bc1-copy-and-pins (308391e0, 2383da57). Cherry-pick them or redo them your way; we won't push to your branch.
  • The fuzzer (one C++ file).
  • A Steam Deck OLED run of your head at 1280x800, switch off and on, across Hyrule Field, the Lost Woods and the Market. That also gives you a Linux build.

Checked by an AI agent (Claude Code) for zeldaootr.

We built the same switch on a local branch before seeing this PR. Yours is closer to landing, so we'd rather help it than compete. What we checked at 3484acbf: - **The opacity rule is sound.** We fuzzed `astc_opaque::block` against a port of `host_shaders/astc_decoder.comp` (the decoder the renderer runs): 92M random blocks over all 14 footprints, 0 judged opaque that decode with alpha below 1. - **Game-free checks pass on Linux** with g++ and clang (the 14 that touch these files), and the branch merges into `main` aa95d35f with no conflicts. Two things we found: 1. **Low: a BC1 → BC1 copy can be lost** if an upload later in the same recording makes that texture BC3 (`vk_xfer.cpp:274`; the conversion's blit runs before the recording, `vk_texture.cpp:2583`). Rare. We have a small patch with a test. 2. **Cost on a slow CPU: each opaque texture is scanned twice,** at `create` and at its first upload. About 100 ms for the terrain array on a Zen 2 CPU. A desktop won't show it; a Deck might. What we can offer, if you want any of it: - The patch for 1, and a test that pins the decoder and encoder functions the rule relies on: two commits on your head, on our fork as [`help-521-bc1-copy-and-pins`](https://git.magicbean.dev/zeldaootr/Longshot/src/branch/help-521-bc1-copy-and-pins) (308391e0, 2383da57). Cherry-pick them or redo them your way; we won't push to your branch. - The fuzzer (one C++ file). - A Steam Deck OLED run of your head at 1280x800, switch off and on, across Hyrule Field, the Lost Woods and the Market. That also gives you a Linux build. *Checked by an AI agent (Claude Code) for zeldaootr.*
HumanBean force-pushed perf/astc-bc1 from 3484acbff1
Some checks failed
PR description / Description follows the template (pull_request_target) Successful in 4s
beanstalk/approval Test farm not requested
CI / Conventional Commit title (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been cancelled
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been cancelled
CI / Workflow lint (actionlint) (pull_request) Has been cancelled
Third-party parts / As their notes say (pull_request) Has been cancelled
Third-party parts / The same as upstream (pull_request) Has been cancelled
Website / Website on Cloudflare (pull_request) Has been cancelled
to 8871fd4f23
Some checks failed
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been skipped
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been skipped
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been skipped
Third-party parts / The same as upstream (pull_request) Has been skipped
Website / Website on Cloudflare (pull_request) Has been skipped
PR description / Description follows the template (pull_request_target) Successful in 4s
CI / Conventional Commit title (pull_request) Successful in 3s
CI / Workflow lint (actionlint) (pull_request) Successful in 5s
Guide screenshots / Guide images and local UI source review (pull_request) Failing after 5s
Third-party parts / As their notes say (pull_request) Successful in 9s
2026-11-15 18:43:46 +00:00
Compare
Owner

Rebased onto main @ bbe6fdf2. No tests were run here; the test boxes stay yours. No conflicts.

Rebased onto `main` @ bbe6fdf2. No tests were run here; the test boxes stay yours. No conflicts.
A block-for-block BC1 -> BC1 copy wrote the BC1 image; a later upload in the same recording that found alpha made the
image BC3 from the upload command buffer, which runs before the recording, so the copy landed in the retired image and
was lost. `copy_t2t` now sends every copy into a BC1 texture to `texture_copy_into_bc`, which makes it BC3 first.

Assisted-by: Claude
test(vk): pin the decoder and encoder functions astc_opaque.h and BC1 rest on
Some checks are pending
CI / Conventional Commit title (pull_request) Blocked by required conditions
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Blocked by required conditions
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Blocked by required conditions
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Blocked by required conditions
CI / Workflow lint (actionlint) (pull_request) Blocked by required conditions
Guide screenshots / Guide images and local UI source review (pull_request) Blocked by required conditions
Third-party parts / As their notes say (pull_request) Blocked by required conditions
Third-party parts / The same as upstream (pull_request) Blocked by required conditions
Website / Website on Cloudflare (pull_request) Blocked by required conditions
PR description / Description follows the template (pull_request_target) Successful in 4s
d36ba1f2b1
Assisted-by: Claude
Author
Contributor

@kingo yes please, thank you. An 8 GB card is exactly the gap. Same route and setup as #421: main vs this PR with RX_VK_ASTC_BC1=1, plus this PR with =0, VRAM and fps per area. Head is d36ba1f2.

@zeldaootr thanks, that's a thorough check. I took both commits as they are (now ac2cc16b, d36ba1f2), on top of the rebase onto bbe6fdf2. Checks that read this diff, one at a time with the pinned llvm-mingw: 372 run, 291 passed; every failure also fails on main on this PC, and test_astc_opaque and test_astc_bc1_remake pass. Yes to the Steam Deck OLED run at 1280x800, off and on, which also covers the Linux build. On the double scan: invisible on a desktop. If the Deck run shows it, carrying the opacity verdict from create to the first upload is the fix; I'd rather measure first. One question: every copy into a BC1 texture now makes it BC3. Do you know whether OoT copies into them often? If it does, part of the saving goes; kingo's run will show it in the VRAM numbers. I'd keep the fuzzer out of the PR unless the maintainers want it in tests/.

@kingo yes please, thank you. An 8 GB card is exactly the gap. Same route and setup as #421: main vs this PR with `RX_VK_ASTC_BC1=1`, plus this PR with `=0`, VRAM and fps per area. Head is `d36ba1f2`. @zeldaootr thanks, that's a thorough check. I took both commits as they are (now `ac2cc16b`, `d36ba1f2`), on top of the rebase onto `bbe6fdf2`. Checks that read this diff, one at a time with the pinned llvm-mingw: 372 run, 291 passed; every failure also fails on main on this PC, and `test_astc_opaque` and `test_astc_bc1_remake` pass. Yes to the Steam Deck OLED run at 1280x800, off and on, which also covers the Linux build. On the double scan: invisible on a desktop. If the Deck run shows it, carrying the opacity verdict from `create` to the first upload is the fix; I'd rather measure first. One question: every copy into a BC1 texture now makes it BC3. Do you know whether OoT copies into them often? If it does, part of the saving goes; kingo's run will show it in the VRAM numbers. I'd keep the fuzzer out of the PR unless the maintainers want it in `tests/`.
Some checks are pending
CI / Conventional Commit title (pull_request) Blocked by required conditions
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Blocked by required conditions
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Blocked by required conditions
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Blocked by required conditions
CI / Workflow lint (actionlint) (pull_request) Blocked by required conditions
Guide screenshots / Guide images and local UI source review (pull_request) Blocked by required conditions
Third-party parts / As their notes say (pull_request) Blocked by required conditions
Third-party parts / The same as upstream (pull_request) Blocked by required conditions
Website / Website on Cloudflare (pull_request) Blocked by required conditions
PR description / Description follows the template (pull_request_target) Successful in 4s
This pull request has changes conflicting with the target branch.
  • gpu/vk/vk_texture.cpp
Some workflows are waiting to be reviewed.
View command line instructions

Manual merge helper

Use this merge commit message when completing the merge manually.

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u 'perf/astc-bc1:Amateurwizrd-perf/astc-bc1'
git switch 'Amateurwizrd-perf/astc-bc1'
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
4 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
MagicBeanDev/Longshot!521
No description provided.