Native HDR flickers between correct colours and grey: one of the three window images stays RGBA8 (one-line workaround included) #2038

Open
opened 2026-11-11 00:43:37 +00:00 by Moosky73 · 5 comments
Moosky73 commented 2026-11-11 00:43:37 +00:00 (Migrated from github.com)

Hookshot version

hookshot v2.0.11-867-gfc375e9

What kind of problem

Graphics (missing, black or wrong-coloured things, lighting, flicker)

What happened

Problem

With HDR set to Native, the picture alternates quickly between correct colours and a washed-out grey, several times a second. Expanded does not flicker. FSR 4 is not the cause: history reset appears once in the log, at start-up.

Version

Before: hookshot v2.0.11-867-gfc375e9 (source 806f912f)
After the change below: hookshot v2.0.11-867-gfc375e9-dirty (source e45dfd4b) (-dirty because I built from the working tree before committing the one-line change).

Built from source on Linux (main at fc375e9, make_game.py --fsr). I haven't tried the newest release because it has no FSR 4.

Hardware and settings

  • GPU: RX 7900 GRE, RADV, Mesa 26.2.6-arch3.1 (mesa and vulkan-radeon 26.2.6-1), Vulkan 1.4
  • OS/desktop: CachyOS, KDE Plasma 6.8.2 (KWin 6.8.2), Wayland
  • Display: Alienware AW3423DWF, 3440x1440 @ 164.90 Hz, DisplayPort. HDR enabled in Plasma (SDR brightness 200 nits, peak brightness 993 nits overridden to 980 nits, wide colour gamut on, VRR automatic)
  • Launched with SDL_VIDEODRIVER=wayland
  • Hookshot settings: HDR Native, paper white 200 nits, peak 1000 nits, Upscaler AMD FSR 4, Render resolution Quality (67%)
  • Overlays or injectors: none. The "before" log (native3) was run without Mesa's anti-lag layer. The "after" log (native4) had ENABLE_LAYER_MESA_ANTI_LAG=1; I also ran the fixed build without it (native5) and it is just as steady.

Where

Kakariko Village, Hyrule Fields and Hyrule Castle Town. The attached logs cover only the start of a session (intro and early gameplay).

What the log shows

At start-up the game's window is created as 0x25 (RGBA8) and then recreated as 0x3d (RGB10A2):

nvn: window of 3 textures (3 active), 2576x1080 format 0x25
nvn: window of 3 textures (3 active), 2576x1080 format 0x3d
vi: QueryDisplayHdrStatus -> HDR10 (the game's native HDR)

Afterwards two of the three window images are RGB10A2 (vk 64), but one stays RGBA8 (vk 37) for the whole run:

0x10057db000 2576x1080x1 NVN 0x3d
0x1004c89000 2576x1080x1 NVN 0x3d
0x1004137000 2576x1080x1 NVN 0x25   <- stays RGBA8

and it is created before the switch:

vk: texture 0x1004137000 2576x1080x1 x1 levels 1 NVN 0x25 -> vk 37 (3 textures, 23 MB)

All present texture lines say format 0x3d, so the game presents all three as RGB10A2.

Cause (from reading the source)

  • format_class() in gpu/vk/vk_texture.cpp returns the same class for RGBA8 and RGB10A2 (both 4 bytes per texel), and Key has no format field. The comment at the top of the file says images are shared by class on purpose (MUTABLE_FORMAT).
  • 0x1004137000 was first made as RGBA8 before the game switched to HDR10. After the switch, texture_get finds the same image by key, so no vk 64 image is made for that address. The other two addresses were first created after the switch.
  • In vk_replay.cpp the native-HDR check is ... && tex->format == VK_FORMAT_A2B10G10R10_UNORM_PACK32, which uses the image's creation format. For the stale image it is false, so that frame goes through the SDR-to-HDR pass (framegen_hdr), which treats the PQ-coded picture as SDR. One frame in three is grey.

I have not stepped through this in a debugger; it is my reading of the code and the logs.

Workaround that fixes it for me

Give RGB10A2 its own class in format_class():

return 0x40000u | (uint32_t)bpb | (from ? 0x100u : 0u) | (vf == VK_FORMAT_A2B10G10R10_UNORM_PACK32 ? 0x200u : 0u);

Commit: github.com/moosky73/Hookshot@b04f99a

With it, the log shows a new image for that address (texture #4 at 0x1004137000 ... class 0x40204 NVN 0x3d, instead of class 0x40004 for the old one), and all three window images are NVN 0x3d -> vk 64. The flicker is gone on Native.

Logs attached: hookshot-native3.log (before the change) and hookshot-native4.log (after; this run was at 3440x1440 output).

Caveats

  • Tested only on RX 7900 GRE / RADV on Plasma Wayland, for a few minutes of play. I haven't checked other GPUs, or whether any other RGB10A2 image relied on sharing with a 32-bit format.
  • The cleaner fix may be different, for example re-making the cached window textures when the game recreates its window in a new format, or checking the game's own format on the present path.

Happy to test patches.

Where in the game

Kakariko Village, Hyrule Fields & Hyrule Castle Town

How often

Every time

Graphics card and driver version

AMD RX 7900 GRE, RADV, Mesa 26.2.6-arch3.1

CPU, RAM and operating system

Ryzen 5 5600, 16 GB, CachyOS, KDE Plasma 6.8.2 (Wayland)

Changes from the defaults

HDR: Native (paper white 200 nits, peak 1000 nits)
Upscaler: AMD FSR 4, Render resolution Quality (67%)
Frame cap 165
Launched with SDL_VIDEODRIVER=wayland
"After" log only: ENABLE_LAYER_MESA_ANTI_LAG=1 (Mesa's anti-lag layer, AMD Anti-Lag 2 on); the fixed build is also steady without it

Other software hooked into the game

No, nothing hooked in

hookshot_log.txt

hookshot-native3.log
hookshot-native4.log

Screenshots or video

No response

Before you send it

  • I'm on the newest release, or the problem is still there on it.
  • I searched the open issues for this problem.
  • I'm not attaching game files, keys, hookshot.exe, the .bin caches or saves.
### Hookshot version hookshot v2.0.11-867-gfc375e9 ### What kind of problem Graphics (missing, black or wrong-coloured things, lighting, flicker) ### What happened ## Problem With HDR set to **Native**, the picture alternates quickly between correct colours and a washed-out grey, several times a second. **Expanded** does not flicker. FSR 4 is not the cause: `history reset` appears once in the log, at start-up. ## Version Before: `hookshot v2.0.11-867-gfc375e9 (source 806f912f)` After the change below: `hookshot v2.0.11-867-gfc375e9-dirty (source e45dfd4b)` (`-dirty` because I built from the working tree before committing the one-line change). Built from source on Linux (`main` at fc375e9, `make_game.py --fsr`). I haven't tried the newest release because it has no FSR 4. ## Hardware and settings - GPU: RX 7900 GRE, RADV, Mesa 26.2.6-arch3.1 (mesa and vulkan-radeon 26.2.6-1), Vulkan 1.4 - OS/desktop: CachyOS, KDE Plasma 6.8.2 (KWin 6.8.2), Wayland - Display: Alienware AW3423DWF, 3440x1440 @ 164.90 Hz, DisplayPort. HDR enabled in Plasma (SDR brightness 200 nits, peak brightness 993 nits overridden to 980 nits, wide colour gamut on, VRR automatic) - Launched with `SDL_VIDEODRIVER=wayland` - Hookshot settings: HDR Native, paper white 200 nits, peak 1000 nits, Upscaler AMD FSR 4, Render resolution Quality (67%) - Overlays or injectors: none. The "before" log (`native3`) was run without Mesa's anti-lag layer. The "after" log (`native4`) had `ENABLE_LAYER_MESA_ANTI_LAG=1`; I also ran the fixed build without it (`native5`) and it is just as steady. ## Where Kakariko Village, Hyrule Fields and Hyrule Castle Town. The attached logs cover only the start of a session (intro and early gameplay). ## What the log shows At start-up the game's window is created as `0x25` (RGBA8) and then recreated as `0x3d` (RGB10A2): ``` nvn: window of 3 textures (3 active), 2576x1080 format 0x25 nvn: window of 3 textures (3 active), 2576x1080 format 0x3d vi: QueryDisplayHdrStatus -> HDR10 (the game's native HDR) ``` Afterwards two of the three window images are RGB10A2 (`vk 64`), but one stays RGBA8 (`vk 37`) for the whole run: ``` 0x10057db000 2576x1080x1 NVN 0x3d 0x1004c89000 2576x1080x1 NVN 0x3d 0x1004137000 2576x1080x1 NVN 0x25 <- stays RGBA8 ``` and it is created before the switch: ``` vk: texture 0x1004137000 2576x1080x1 x1 levels 1 NVN 0x25 -> vk 37 (3 textures, 23 MB) ``` All `present texture` lines say `format 0x3d`, so the game presents all three as RGB10A2. ## Cause (from reading the source) - `format_class()` in `gpu/vk/vk_texture.cpp` returns the same class for RGBA8 and RGB10A2 (both 4 bytes per texel), and `Key` has no format field. The comment at the top of the file says images are shared by class on purpose (`MUTABLE_FORMAT`). - `0x1004137000` was first made as RGBA8 before the game switched to HDR10. After the switch, `texture_get` finds the same image by key, so no `vk 64` image is made for that address. The other two addresses were first created after the switch. - In `vk_replay.cpp` the native-HDR check is `... && tex->format == VK_FORMAT_A2B10G10R10_UNORM_PACK32`, which uses the image's creation format. For the stale image it is false, so that frame goes through the SDR-to-HDR pass (`framegen_hdr`), which treats the PQ-coded picture as SDR. One frame in three is grey. I have not stepped through this in a debugger; it is my reading of the code and the logs. ## Workaround that fixes it for me Give RGB10A2 its own class in `format_class()`: ``` return 0x40000u | (uint32_t)bpb | (from ? 0x100u : 0u) | (vf == VK_FORMAT_A2B10G10R10_UNORM_PACK32 ? 0x200u : 0u); ``` Commit: https://github.com/moosky73/Hookshot/commit/b04f99a With it, the log shows a new image for that address (`texture #4 at 0x1004137000 ... class 0x40204 NVN 0x3d`, instead of `class 0x40004` for the old one), and all three window images are `NVN 0x3d -> vk 64`. The flicker is gone on Native. Logs attached: `hookshot-native3.log` (before the change) and `hookshot-native4.log` (after; this run was at 3440x1440 output). ## Caveats - Tested only on RX 7900 GRE / RADV on Plasma Wayland, for a few minutes of play. I haven't checked other GPUs, or whether any other RGB10A2 image relied on sharing with a 32-bit format. - The cleaner fix may be different, for example re-making the cached window textures when the game recreates its window in a new format, or checking the game's own format on the present path. Happy to test patches. ### Where in the game Kakariko Village, Hyrule Fields & Hyrule Castle Town ### How often Every time ### Graphics card and driver version AMD RX 7900 GRE, RADV, Mesa 26.2.6-arch3.1 ### CPU, RAM and operating system Ryzen 5 5600, 16 GB, CachyOS, KDE Plasma 6.8.2 (Wayland) ### Changes from the defaults HDR: Native (paper white 200 nits, peak 1000 nits) Upscaler: AMD FSR 4, Render resolution Quality (67%) Frame cap 165 Launched with SDL_VIDEODRIVER=wayland "After" log only: ENABLE_LAYER_MESA_ANTI_LAG=1 (Mesa's anti-lag layer, AMD Anti-Lag 2 on); the fixed build is also steady without it ### Other software hooked into the game No, nothing hooked in ### hookshot_log.txt [hookshot-native3.log](https://github.com/user-attachments/files/34660781/hookshot-native3.log) [hookshot-native4.log](https://github.com/user-attachments/files/34660780/hookshot-native4.log) ### Screenshots or video _No response_ ### Before you send it - [x] I'm on the newest release, or the problem is still there on it. - [x] I searched the open issues for this problem. - [x] I'm not attaching game files, keys, hookshot.exe, the .bin caches or saves.
Angeluz01 commented 2026-11-11 01:13:10 +00:00 (Migrated from github.com)

with the latest ver, I still getting same Purple or Blue screen

4K HDR10 TV, 4090

with the latest ver, I still getting same Purple or Blue screen 4K HDR10 TV, 4090
Unboltingdog commented 2026-11-11 02:43:31 +00:00 (Migrated from github.com)

I'm on the latest build 2.1.0, and I'm getting a black screen with both implementations of HDR. I can only see something unless I turn it off. One of the other recomps uses RenoDX for HDR; maybe we can mimic that, as this recomp is (imo) the gold standard at the moment

I'm on the latest build 2.1.0, and I'm getting a black screen with both implementations of HDR. I can only see something unless I turn it off. One of the other recomps uses RenoDX for HDR; maybe we can mimic that, as this recomp is (imo) the gold standard at the moment
braydencurtis commented 2026-11-11 04:36:33 +00:00 (Migrated from github.com)

Yeah HDR is just a black screen for me, have to switch back to SDR to get picture. 2.1.0

Yeah HDR is just a black screen for me, have to switch back to SDR to get picture. 2.1.0
NotRexed commented 2026-11-11 05:12:42 +00:00 (Migrated from github.com)

Your fix (RGB10A2 as its own image class) is merged to main in #2147, credited to you as co-author. The same PR fixes the black, grey or purple HDR picture whenever an upscaler or Sharpness above 0 is on: the scaled picture the HDR pass reads wasn't marked as sampleable. Both ship in the next release; this stays open until then.

Your fix (RGB10A2 as its own image class) is merged to main in #2147, credited to you as co-author. The same PR fixes the black, grey or purple HDR picture whenever an upscaler or Sharpness above 0 is on: the scaled picture the HDR pass reads wasn't marked as sampleable. Both ship in the next release; this stays open until then.
maxdsmichael commented 2026-11-11 21:14:44 +00:00 (Migrated from github.com)

Confirming the #2147 fix on real HDR hardware, since the PR notes it couldn't be checked in game.

Fixed on nightly v2.1.0-rc.3-112-g6c8c1bfb (source b2925bb1). Broken on v2.1.0 (source 633eb435).

Setup

  • RTX 5070 Ti, driver 621.01, Windows 11 Pro
  • Ryzen 7 9800X3D, 32 GB
  • 3440x1440 @ 164 Hz, , Windows "Use HDR" on
  • Fullscreen, Ultrawide on, Ultrawide menus on, Upscaler off

On v2.1.0

  • Expanded: black picture in game.
  • Native: heavy flicker, and the game's menus did not show.
  • The log matched this issue exactly: window texture 0x1004137000 was presented first as 0x25, then as 0x3d at the same address.

On the nightly (each: ~20 s of walking outdoors, then the pause menu)

HDR Sharpness Frame generation Picture Pause menu
Expanded 0 Off ok ok
Expanded 50 Off ok ok
Native 0 Off ok ok
Native 50 Off ok ok
Native 0 3x ok ok

Switching HDR Off → Expanded → Native with the Insert menu open also showed the menu correctly.

One thing worth noting for ultrawide: on v2.1.0 framegen_scale also ran for ultrawide menu sides (!opts.upscale && !opts.sharpness && !wide.side), so ultrawide users could reach the unsampleable scaled image with the upscaler off and Sharpness at 0. The PR text only lists an upscaler or Sharpness as triggers. The same fix covers it; the Expanded / Sharpness 0 row above is that case.

Log from the nightly session attached.

hookshot_log_nightly_hdr.txt

Confirming the #2147 fix on real HDR hardware, since the PR notes it couldn't be checked in game. **Fixed on nightly** `v2.1.0-rc.3-112-g6c8c1bfb` (source `b2925bb1`). Broken on v2.1.0 (source `633eb435`). **Setup** - RTX 5070 Ti, driver 621.01, Windows 11 Pro - Ryzen 7 9800X3D, 32 GB - 3440x1440 @ 164 Hz, <MONITOR MODEL>, Windows "Use HDR" on - Fullscreen, Ultrawide on, Ultrawide menus on, Upscaler off **On v2.1.0** - Expanded: black picture in game. - Native: heavy flicker, and the game's menus did not show. - The log matched this issue exactly: window texture `0x1004137000` was presented first as `0x25`, then as `0x3d` at the same address. **On the nightly** (each: ~20 s of walking outdoors, then the pause menu) | HDR | Sharpness | Frame generation | Picture | Pause menu | |---|---|---|---|---| | Expanded | 0 | Off | ok | ok | | Expanded | 50 | Off | ok | ok | | Native | 0 | Off | ok | ok | | Native | 50 | Off | ok | ok | | Native | 0 | 3x | ok | ok | Switching HDR Off → Expanded → Native with the Insert menu open also showed the menu correctly. **One thing worth noting for ultrawide:** on v2.1.0 `framegen_scale` also ran for ultrawide menu sides (`!opts.upscale && !opts.sharpness && !wide.side`), so ultrawide users could reach the unsampleable scaled image with the upscaler off and Sharpness at 0. The PR text only lists an upscaler or Sharpness as triggers. The same fix covers it; the Expanded / Sharpness 0 row above is that case. Log from the nightly session attached. [hookshot_log_nightly_hdr.txt](https://github.com/user-attachments/files/34707173/hookshot_log_nightly_hdr.txt)
Commenting is not possible because the repository is archived.
No milestone
No assignees
1 participant
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/Hookshot#2038
No description provided.