Skip to content

[Part 8] CM fixes#13860

Open
UjinT34 wants to merge 38 commits intohyprwm:mainfrom
UjinT34:refactor-8-cm-automation
Open

[Part 8] CM fixes#13860
UjinT34 wants to merge 38 commits intohyprwm:mainfrom
UjinT34:refactor-8-cm-automation

Conversation

@UjinT34
Copy link
Copy Markdown
Contributor

@UjinT34 UjinT34 commented Mar 26, 2026

Describe your PR, what does it fix/add?

Removes render:cm_fs_passthrough. DS and render:cm_auto_hdr should be used to achieve the same effect. DS and FS passthrough are very similar when it comes to CM and made things too complicated.
Fixes render:non_shader_cm interaction with hyprsunset and similar apps.
Changes render:non_shader_cm default to 2 - enabled for DS.
Fixes linear luminance math for non-default linear descriptions.
Makes render:cm_sdr_eotf to actually change the default image description. Should fix some hard to pinpoint srgb <-> gamma22 issues.
Adds render:non_shader_cm_interop. 0 - external ctm is disabled in fullscreen, 1 - external ctm is enabled in fullscreen, 2 - external ctm is disabled for fullscreen photo/video/game content types. 2 is the new default because it doesn't make sense to apply hyprsunset and similar to those content types.
Adds debug:invalidate_fp16 to disable fp16 buffer invalidation. Fixes glitches on some systems but reduces performance.

Is there anything you want to mention? (unchecked code, possible bugs, found problems, breaking compatibility, etc.)

Needs more testing.
hdr with sdr mods might require render:use_shader_blur_blend = 1 for blur

Is it ready for merging, or does it need work?

Ready as is. Any further fixes in separate PRs

  • Fix cm_sdr_eotf
  • Fix screenshare with use_fp16 = 0 not possible for fb copies
  • Fix ctm

@fxzzi
Copy link
Copy Markdown
Contributor

fxzzi commented Mar 26, 2026

hyprsunset temperature and gamma are still unable to apply whilst in a DS scenario. However you're able to go out of fullscreen, do whatever with hyprsunset, and then fullscreen again with ds and hyprsunset still working

edit: wayfreeze changes colours on screen also, dont think this happened before.

@Dregu
Copy link
Copy Markdown
Contributor

Dregu commented Mar 26, 2026

Ok lets be clear about the blue light filters here, I personally don't ever want hyprsunset to work on DS, or rather video/game content that is fullscreen. I have 4 monitors and want to dim 3 of those with ctm when playing a fullscreen game or watching a fullscreen video, but the fullscreen thing should never have ctm/shaders/blue light filters applied to it, it needs to be fully lit with accurate colors. Optionally of course, some might want it orange.

@UjinT34
Copy link
Copy Markdown
Contributor Author

UjinT34 commented Mar 27, 2026

Ok lets be clear about the blue light filters here, I personally don't ever want hyprsunset to work on DS, or rather video/game content that is fullscreen. I have 4 monitors and want to dim 3 of those with ctm when playing a fullscreen game or watching a fullscreen video, but the fullscreen thing should never have ctm/shaders/blue light filters applied to it, it needs to be fully lit with accurate colors. Optionally of course, some might want it orange.

I agree but there were a lot of complains about broken hyprsunset the last time. I'll add a setting to control that

@UjinT34
Copy link
Copy Markdown
Contributor Author

UjinT34 commented Mar 27, 2026

Should work as expected by default. Those who want hyprsunset always on should set render:non_shader_cm_interop = 1.

If hyprsunset doesn't apply in fullscreen when it should I'll need some steps to reproduce with some additional info. It behaves differently depending on HL and source CM settings.

@fxzzi
Copy link
Copy Markdown
Contributor

fxzzi commented Mar 27, 2026

Amazing, thx. Personally I agree not to use blue light filters when gamin but the gamma control is nice when it's needed.

@umbrageodotus
Copy link
Copy Markdown

Can you make this be on top of current API fixes?

@fxzzi
Copy link
Copy Markdown
Contributor

fxzzi commented Mar 27, 2026

Can you make this be on top of current API fixes?

already is on top

@umbrageodotus
Copy link
Copy Markdown

CURRENT. Missing 2 commits and a rebase.

@fxzzi
Copy link
Copy Markdown
Contributor

fxzzi commented Mar 28, 2026

image image

strange artifacts, and blur looks lighter with use_fp16 true. Only shows on specific wallpapers; i've shared this specific one below. Also with this option enabled, the dark background when launching hyprland (just before hyprpaper starts) is a lot brighter too.

Rest of the report is with fp16 false

730_20251024183732_1

render:non_shader_cm_interop = 2 (default) works ok. on mpv video is washed out, toggling hyprsunset darkens the image and stops it being washed out and artifacting lol (ds is only enabled for game content type, so doesn't apply here). so hyprsunset ctm itself doesn't get applied as expected, but something gets applied which makes the video look correct again
Screenshot from 26 03 28 01:10:34
Screenshot from 26 03 28 01:10:42

both ff and chromium now match perfectly but in a bad way - they are now both washed out just like mpv above. hyprpicker claims both their hex codes are the exact same which is good ig.
image

wayfreeze now substantially changes on screen colours when its running. everything lightens. so this issue with things lightening / being washed out is now global afaik.
image

all above was with non_shader_cm 1. last i checked this setting can not be changed at runtime as expected and requires you to restart hyprland entirely for it to take effect. I tried with it on default with no change to above issues.
also cm_sdr_eotf on default, monitor is on 10bit srgb

setting cm sdr eotf to gamma22 fixes many apps being washed out, not mpv and chromium, those are now back to as before, washed out. hyprpicker / wayfreeze now darken the screen instead of lighten. there is no real colour difference on screen between chromium in below image and in above image. screenshot was produced darker after setting gamma22 i guess. so in this screenshot ff looks too dark. Online colour picker on this image itself gives chromium hex 1a1b25 whilst "real" hex is 1a1b26, so the screenshot has made the washed out chromium darker to match correct colours minus inaccuracy
image

setting gamma22force then fixes winewayland and sdl wayland being washed out. Also makes the colours on regular mpv not as washed out - colours are still subtly different between mpv and mpv-with-hyprsunset-but-not-actually-applied-on-it-because-video-content-type. trying to screenshot this makes it look like mpv on its own is super dark when in reality they are actually very close
Screenshot from 26 03 28 01:28:28
Screenshot from 26 03 28 01:28:34

@UjinT34 UjinT34 force-pushed the refactor-8-cm-automation branch from cb966ac to 052f68c Compare March 28, 2026 07:27
@UjinT34
Copy link
Copy Markdown
Contributor Author

UjinT34 commented Mar 28, 2026

@fxzzi If you have two pictures A and B with different saturation you can call A correct and B washed out or A oversaturated and B correct. If you have cm = srgb, your monitor supports a wider gamut and isn't set to convert input signal accordingly then the picture will be oversaturated. Might not be immediately noticeable with P3 and Adobe monitors. Probably won't affect blue colors as much as greens and reds. If you set HL cm to something wide and you monitors treats it as something narrow then you'll get washed out colors. If your monitor isn't explicitly set to a specific colorspace or that colorspace is some internal thing and doesn't apply to input signal then your monitor might detect it incorrectly and this detection can yield different result for different HL settings. srgb, p3 and adobe do not set wcg flag (bt2020), wide and edid set this flag. That's correct only for srgb and wide, other settings should do something differently. That other thing isn't easy to test because it depends on driver and hw support. https://drmdb.emersion.fr/properties/3233857728/Colorspace has some values that aren't present on my setup and it's not clear which ones should be mapped to HL cm. And I am not sure whether it'll be enough to make monitors treat input signal the correct way without tweaking their settings.

Blur artifacts with fp16 are caused by color values going outside 0.0-1.0 range and being incorrectly clamped when something in the pipeline isn't using both fp16 and CM for the input values. Toggling fp16 invalidates blur buffers but doesn't mark blur as dirty leaving it in incorrect state. If this happens you'll see the difference between tiled and floating blur.

Blur with fp16 is significantly lighter and I couldn't figure out why. Might be actually more correct because the values aren't clamped and packed into a smaller range. Default HL internals might cause an unwanted conversion into 8bit somewhere, most of the code lets gl autodetect some internal properties and in general is tailored towards 8bpc.

@fxzzi
Copy link
Copy Markdown
Contributor

fxzzi commented Mar 28, 2026

and isn't set to convert input signal accordingly then the picture will be oversaturated.

Whilst this is a fair assumption I forgot to mention that the reason I'm using srgb in hyprland is because I am instead using the srgb callibrated mode on my monitor for now, as there is a firmware bug with custom modes which crush a lot of the blacks together. This means the colours are clamped to srgb by my monitor, and I in most cases am comfortably able to regard one scene as correct and one as incorrect.

When using "edid" or "dcip3" cm with a regular mode on my monitor the colours are similar to srgb with monitor clamping. I can test and see if all these scenarios still occur when using one of these cm modes instead if you'd like.

Toggling fp16 invalidates blur buffers

This was from a fresh launch of hyprland

@UjinT34
Copy link
Copy Markdown
Contributor Author

UjinT34 commented Mar 28, 2026

Couldn't replicate blur artifacts. It's either specific to some HL settings or the wallpaper itself was recoded during upload and doesn't trigger such artifacts any more.

render:non_shader_cm_interop isn't strictly tied to render:non_shader_cm and will apply to non-DS scenarios. By default a fullscreen video will disable external ctm modifications. render:non_shader_cm controls whether internal modifications are applied in this case.
There are also external lut modifications that aren't touched by both settings in any way.

@fxzzi
Copy link
Copy Markdown
Contributor

fxzzi commented Mar 28, 2026

or the wallpaper itself was recoded during upload and doesn't trigger such artifacts any more.

Don't have any specific settings in hyprland related to blur really, the artifacts are also not specific to foot, you can see them in ags bar above, and it also shows on dunst in HDR (fp16 defaults on in HDR)

decoration:blur:enabled = 1
decoration:blur:passes = 2
decoration:blur:size = 4

This is the image direct from my wallpapers, maybe it'll happen here. https://gitlab.com/fazzi/walls/-/raw/main/images/730_20251024183732_1.jpg?ref_type=heads

with cm=edid bright parts of the wallpaper are coloured incorrectly, not fixed in floating
image

sometimes you can get it into a state where it's only broken if going specifically from floating to fullscreen, instead of tiled to fullscreen. the colours fixing itself near the end of the video in fs is from me doing togglefloating

output.mp4

you can also see http://www.lagom.nl/lcd-test/black.php for the raised black levels

edit: last commit fixed blur in tiled not applying after leaving HDR scenario.
not sure if related to PR but i can commonly experience a screen lockup when launching games with DS enabled, im assuming its right when the SW cursor disappears. hyprctl reload gets me back.

editedit:

image still able to catch instances where blur completely dies, might be after coming out of a DS scenario (no HDR or anything). `hyprctl reload` gets the blur back

@umbrageodotus
Copy link
Copy Markdown

umbrageodotus commented Mar 28, 2026

smol-fix.patch

I believe this simple patch should be added to this. It fixes a variable definition I believe is incorrect (not 100% sure, though :3).

@umbrageodotus
Copy link
Copy Markdown

umbrageodotus commented Mar 28, 2026

I've recently been getting some damage when certain windows appear or move (plus signs in minecraft when switching workspaces).
The lockup also happens to me, altho for me it's temporary.

Not sure if these are caused by API fixes or CM fixes.

@UjinT34 UjinT34 force-pushed the refactor-8-cm-automation branch from a045157 to 93939c1 Compare March 28, 2026 21:59
@fxzzi
Copy link
Copy Markdown
Contributor

fxzzi commented Mar 29, 2026

with gamma22 or gamma22force, screen record is dark and you can tell as the infinity effect in the preview gets darker and darker. making obs fullscreen doesn't change obs colours on screen but corrects the screen recording to not be dark. this is seen as the infinity effect in the preview does not get darker.

image image

this happens with any fullscreen window. colours in screencopy become correct only when a window is in fullscreen. so when triggering hyprpicker / wayfreeze in tiled scenario, screen darkens (with gamma22 stuff), but if foot is in fullscreen, then i trigger hyprpicker / wayfreeze, the screen doesn't darken at all (correct behaviour).

@UjinT34
Copy link
Copy Markdown
Contributor Author

UjinT34 commented Mar 29, 2026

gamma22force forces incorrect cm for srgb clients. if this cm goes through shader then it's applied to the buffer content and goes back into obs with modifications. if it goes through non shader cm then the buffer remains unmodified. fp16 might behave a bit different in those scenarios
I'll check gamma22 and other internals.

@fxzzi
Copy link
Copy Markdown
Contributor

fxzzi commented Mar 29, 2026

It happens with only gamma22 as well. Gamma22force is the only way I can makea lot of games look correct. Gamma22 alone fixes washed out colours in ff, gtk, older electron, etc.

Isn't gamma22 default on kde and gnome?

@ssareta
Copy link
Copy Markdown
Contributor

ssareta commented Apr 11, 2026

Can confirm, am on nvidia (single dgpu), rendering is completely cooked for me (massive black patches on screen) without debug:invalidate_fp16 = 0 on use_fp16=1. This wasn't happening on commit 0bfa45f

@ssareta
Copy link
Copy Markdown
Contributor

ssareta commented Apr 11, 2026

Something about monitorv2:min_luminance, max_luminance, max_avg_luminance is really horribly broken vs main (and vs older version of PR). I think max_luminance in particular.

In HDR mode either in game or even on desktop with cm = hdr, setting this to my usual settings of 0, 1000, 250 (based on my monitor's edid, which is 0, 1060, 253) makes the colours hypr bright, like almost pure white.

The setting actually causing the issues seems to be max_luminance = 1000 (removing it fixes the issue even with the other two settings there), but even if I set max lum to 203 or something the image doesn't look right (brightness level more or less looks ok with 203, but the image looks a bit wrongly saturated, like it's going through inverse tonemapping) vs removing the setting entirely, which makes it look correct again.

I think the tonemap commit is perhaps borked... and also afaik this setting shouldn't affect actual HDR games, which are an HDR source?

@finalfantasian
Copy link
Copy Markdown

finalfantasian commented Apr 11, 2026

Is it only me or is setting max_luminance broken on the latest changes? I've got debug:invalidate_fp16 = 0 set, but at the same time setting max_luminance to anything on any of my HDR monitors causes it to either be too black or too white (to the point where I'm getting either a black or white screen). The only fix so far has just been not setting max_luminance at all and using sdrbrightness or sdr_max_luminance. This didn't happen before btw. It used to be able to set max_luminance and have an effect that didn't make my screens unusable, unfortunately.

@UjinT34
Copy link
Copy Markdown
Contributor Author

UjinT34 commented Apr 11, 2026

@gulafaran "actually apply the tone mapping" thing breaks with overridden target luminances. might be caused by incorrect input (e.g. monitor luminance values aren't sent when they should unless they are overridden or vice versa)

@njdom24 please recheck the tonemapping code from #12204. It does some math to get newLum value but doesn't use it.

I'll leave the tonemapping code unchanged but it's clearly incorrect since #12204. And those changes probably hide some other issue with incorrectly passed values.

@UjinT34
Copy link
Copy Markdown
Contributor Author

UjinT34 commented Apr 11, 2026

Tonemapping happens when source luminance is significantly higher than the taget luminance. Can happen with HDR content displayed on HDR target. Max source luminance is 10000, max typical hdr monitor luminance is 400-4000. Most modern games have a slider to limit their luminance, older games tend to use 10000.

@ssareta
Copy link
Copy Markdown
Contributor

ssareta commented Apr 11, 2026

Hm right, makes sense, I see the (maxLuminance < dstMaxLuminance * 1.01) check in tonemap.glsl. I was playing Assassin's Creed Shadows tho with ingame HDR luminance set to 1000, same as HL override and close to monitor edid... so not sure what happens there, I guess your suspicion about wrong input values might be right

@VeilSilence
Copy link
Copy Markdown

Latest fixes make fp16 issues some kind of worse.
Example
image
Not related to fp16. About my issue that I report previously. Looks like this only happening, when there is no background "wallpaper" at all.

That's not a regression compared to main. Try debug:invalidate_fp16 = 0 (requires and additional fp16 toggle to make it work). Are you on nvidia?

yea, nv 3090. I'll disable for now then.

@UjinT34 UjinT34 mentioned this pull request Apr 11, 2026
MrDwarf7 added a commit to MrDwarf7/dotfiles that referenced this pull request Apr 12, 2026
@finalfantasian
Copy link
Copy Markdown

finalfantasian commented Apr 12, 2026

Yo so is it just me or is screensharing HDR content still not looking right with this PR? It's too acidic and makes HDR content leveling look wrong in both screen capture and window capture. Also screen capture just pauses on a certain frame after some time, and does not continue capturing after that so you have to restart the client.

@nnra6864
Copy link
Copy Markdown
Contributor

This finally fixes incorrect color displayed by electron apps and zed editor for me, great work as always!

@UjinT34
Copy link
Copy Markdown
Contributor Author

UjinT34 commented Apr 12, 2026

Yo so is it just me or is screensharing HDR content still not looking right with this PR? It's too acidic and makes HDR content leveling look wrong in both screen capture and window capture. Also screen capture just pauses on a certain frame after some time, and does not continue capturing after that so you have to restart the client.

Looks ok to me. Probably some cm settings combo makes it look different. Recorded video might differ from the image displayed by the recording app.

@finalfantasian
Copy link
Copy Markdown

finalfantasian commented Apr 12, 2026

I was testing on mpv and it seems like the cauie was simply target-colorspace-hint-mode = source. Commenting that out fixes it.
Edit: Maybe not actually. Blacks seem weird with even this setting off. Could be my config tho so imma investigate.
Note: I'm doing all this with the following:

monitorv2 {
  output = DP-3
  mode = 1920x1080@165
  position = 0x0
  scale = 1
  bitdepth = 10
  cm = hdr
  #sdr_eotf = 2
  sdrbrightness = 1.0
  sdrsaturation = 1.0
  vrr = 1
  #vfr = true
  supports_wide_color = 1
  supports_hdr = 1
  sdr_min_luminance = 0.000
  sdr_max_luminance = 220
  min_luminance = 0
  max_luminance = 1000
  max_avg_luminance = 1000
}

render {
  direct_scanout = 0
  cm_auto_hdr = 1
  cm_enabled = 1
  cm_sdr_eotf = gamma22
  #cm_fs_passthrough = 0
  non_shader_cm = 0
  new_render_scheduling = true
  use_fp16 = 1
  keep_unmodified_copy = 1
  #commit_timing_enabled = true
  non_shader_cm_interop = 1
  #use_vulkan = 1
  use_shader_blur_blend = 1
}

Note 2: trying to stream on Discord w/Equibop/native Discord
Edit 2: Just updated everything Hyprland with this and the simplify shadow PR. Now the floating window becoming transparent up to the wallpaper thing is back, it seems.

@ssareta
Copy link
Copy Markdown
Contributor

ssareta commented Apr 13, 2026

Edit: Maybe not actually. Blacks seem weird with even this setting off. Could be my config tho so imma investigate.

I guess since this is visible in screenshots, maybe you can share some to see if what you're seeing is within expectation or not? For me having target-colorspace-hint-mode = source in mpv doesn't seem to matter for HDR content, but in SDR (depending on content I think) mpv fullscreen will modeset to 8bit for me with that option removed.

Here's something I just captured in mpv with two different versions of the same movie, one SDR and one HDR:

Screenshot from SDR version of movie:
grim-20260413-195744

Screenshot from HDR version of movie:
grim-20260413-195816

As you can see, the HDR screenshot looks a bit overcooked for two reasons: 1) saturation is way high and 2) highlights are blown out. Now ofc how representative the SDR version is of "original creator intent" depends very much on how these two versions of the movie were created, but FWIW in actual viewing on the monitor, while the HDR version has much brighter highlights coming from the windows, it doesn't look functionally that different from the SDR version (including overall scene brightness/saturation).

Here's what I think:

  1. is probably just the direct result of HL's force 8 bit screencopy setting (misc:screencopy_force_8b = true). (Somehow I can't capture screenshots with this disabled using grim, but it works in OBS and if I disable this, the saturation in the recording becomes ok.) The setting is true by default because otherwise it breaks Discord screenshare.

  2. I think this is just the limits of our tonemapping algorithm (I did an experiment just now to replace HL's current tonemap shader code with kwin's tonemap shader code, it produces pretty much identical results), so it's pretty much the best you get with what we have rn. There are better implementations out there (https://bruop.github.io/tonemapping/ is a nice ref) that could perhaps be implemented, but at some point it is just a fundamental physics issue of "can't cram more info into less space". Also, per-channel tonemapping instead of just luminance mapping might help with (1), too.

@ssareta
Copy link
Copy Markdown
Contributor

ssareta commented Apr 13, 2026

Also screen capture just pauses on a certain frame after some time, and does not continue capturing after that so you have to restart the client.

This however is deffo a bug (exists on main too, I think probably since #13631) that I constantly keep hitting randomly (and others have reprod too I think), no idea what triggers it. I suspect it won't happen if you set render:keep_unmodified_copy = 0 (altho that causes other problems), or if you just keep it at the default 2 and are not in HDR mode, but I'm not 100% sure.

Toggling fp16 off and on "unstucks" the frame for me.

@finalfantasian
Copy link
Copy Markdown

@ssareta i see pretty much the same thing you see when comparing a screenshot of an HDR movie to how it is represented on screen whenever played in MPV. Without the tonemapping done by Hyprland, it looks pretty much as it should on my monitor without deleting detail but with screenshotting it using for example grimblast or some other tool it ends up looking wrong (high saturation, acidic, highlights are blown out) and it ends up deleting detail by making blacks too dark.

@ssareta
Copy link
Copy Markdown
Contributor

ssareta commented Apr 13, 2026

Right, matches with my experience then. We can wait for Ujin to confirm that I didn't just talk completely out of my ass, but if not yea, I don't really think this is improvable without a better tonemapping alg. It's already an improvement in mpv vs main (which usually has incorrect HDR colours even in actual viewing without some mpv config hackery)

I might take a stab at it after this PR if I get bored - I was interested to see if mpv/libplacebo's one is any good, because apparently it should be, but the Uchimura one from the link I shared looks quite nice... it might even be worth implementing multiple and letting ppl pick their favourite via a setting, different ones are probably better for different kinds of content

@finalfantasian
Copy link
Copy Markdown

finalfantasian commented Apr 13, 2026

As for the other issue which you said is a bug, setting keep_unmodified_copy = 0 just prevents screen capture from HDR entirely :( it only shows a blank, black image when captured with grimblast. If I set the other new options to on then it results in random fractions of the image turning black.

@njdom24
Copy link
Copy Markdown
Contributor

njdom24 commented Apr 13, 2026

2. (I did an experiment just now to replace HL's current tonemap shader code with kwin's tonemap shader code, it produces pretty much identical results)

My changes in #12204 were adapted from KWin's, with some stuff added/removed until it looked decent, which probably meant it relied on bugs/quirks/my misunderstandings that have since been changed.

If a pure port of their tonemapper works better with this PR, then please blow away my changes.

@UjinT34 UjinT34 mentioned this pull request Apr 13, 2026
12 tasks
@UjinT34
Copy link
Copy Markdown
Contributor Author

UjinT34 commented Apr 13, 2026

Are there any issues with use_fp16 = 0 that aren't present on main? hdr + screenshare was broken in one way or another for a long time. With this PR it should be better with one settings and can be worse with other. Not really possible to make it work in every scenario without some extra rendering steps. I'll look into fp16 issues in #14070

@gulafaran
Copy link
Copy Markdown
Contributor

Are there any issues with use_fp16 = 0 that aren't present on main? hdr + screenshare was broken in one way or another for a long time. With this PR it should be better with one settings and can be worse with other. Not really possible to make it work in every scenario without some extra rendering steps. I'll look into fp16 issues in #14070

I havent noticed any 👍 only fp16 related

@fxzzi
Copy link
Copy Markdown
Contributor

fxzzi commented Apr 13, 2026

everything fine here too. thanks for your work yet again :)

tho i do think at all default settings it's really close to just cm_enabled 0. I ended up opting with this on my systems which don't have good displays or HDR and stuff

@ssareta
Copy link
Copy Markdown
Contributor

ssareta commented Apr 14, 2026

Same here, equal to or better than main in basically every scenario (even with fp16 = 1). Thanks for the work!

@vaxerski
Copy link
Copy Markdown
Member

I think we should make fp16 auto enable it in all CM scenarios outside srgb. If we are in srgb, it's useless, but with e.g. wide it would help with sc and stuff.

That's just my two cents, outside of that code looks good.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.