Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HDR support #97

Open
musm opened this issue Oct 22, 2020 · 36 comments
Open

HDR support #97

musm opened this issue Oct 22, 2020 · 36 comments
Labels
feature request help wanted Extra attention is needed

Comments

@musm
Copy link

musm commented Oct 22, 2020

When HDR support is enabled, brightness control on my monitor is disabled.

Instead, the following slider can control brightness of SDR apps, which acts like a 'pseudo' brightness bar.

image

Twinkle tray's brightness control in this scenario should either

  1. Acts as a proxy and adjust the slider shown in the image above.
  2. Disable itself

Right now I can mess around with the brightness slier in Twinkle tray, but it looks like it's corrupting my monitors brightness setting (which are disabled) and has the ability to completely turn off my monitor at setting 0%, and in general doesn't look like it's doing the correct thing and possibly corrupting some state. I had to restart my monitor to reset settings back.

@xanderfrangos
Copy link
Owner

Odd. I have an HDR monitor and the brightness slider works fine. I have no idea what controls that "HDR/SDR" bar and I don't think it affects true HDR content. Only SDR. I would assume the registry controls it, but I can't find any documentation on where/how it's stored.

@musm
Copy link
Author

musm commented Nov 10, 2020

Is your monitor 10-bit? Here are the other setting on that same page
image

@musm
Copy link
Author

musm commented Jan 13, 2021

This doesn't really help: https://support.microsoft.com/en-us/windows/hdr-and-wcg-color-settings-in-windows-10-2d767185-38ec-7fdc-6f97-bbc6c5ef24e6
Sadly I also wasn't able to find anything in the regsitry.

@xanderfrangos xanderfrangos added the help wanted Extra attention is needed label Feb 6, 2021
@xanderfrangos
Copy link
Owner

I haven't found much on my own either. Without access to a bunch of HDR monitors, I don't know that I'll be able to do much about this. In a future update, I'll allow users to exclude their monitor from Twinkle Tray. So at least HDR displays can be excluded.

If anyone can provide DDC/CI information about their own HDR display, documentation about adjusting HDR programmatically, or a PR for this feature, it would be greatly appreciated.

@drewchurch
Copy link

@xanderfrangos I just dug through procmon when making the HDR toggle and can't find anything that stands out.. it's very chatty at about 47k lines in just a few seconds. If there's anything I can look for, LMK.

Also, how can I provide you DDC/CI info? I've got two HDR compatible displays from different major manufacturers.

@catshitz
Copy link

catshitz commented Sep 7, 2021

relevant issue here: couldn't reset back to normal mode brightness after turning on & off HDR mode (not the windows fake one but the true HDR mode in a game or a movie),
for example, when I finished playing RE3R in true HDR mode, the monitor will automatically come back to normal mode after I shut the game down(let's say the brightness in HDR is 70 and normal mode 20), at first the twinkle-tray doesn't effect anything until you click it on the traybar and call out its panel, then it'll somehow think you'are still in the HDR mode and automatically set your monitor brightness "back" to 70, which really is some flawness that needs to be fixed.

@FlyingFaller
Copy link

Also would like to see HDR support added if possible. Makes the app unusable because I like to keep Windows HDR enabled.

@kev007
Copy link

kev007 commented Mar 18, 2022

I recently upgraded to Windows 11 and the brightness control of my HDR monitor stopped working. As soon as I turn off HDR, it works again. Even the v1.14-beta1 version does not allow the control that the stable version did on Windows 10.

@wywywywy
Copy link

wywywywy commented Jul 7, 2022

Ok I've found the registry key that the setting changes (tested on Win 11).

Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\GraphicsDrivers\MonitorDataStore\DELA1E4#G7IYMxgwAAgX_10_07E6_A1\SDRWhiteLevel

The value is from 1000 (0%) to 3500 (50%) to 6000 (100%) in dec.

Once the SystemSettings.exe has changed the registry value, it calls something in D3D12 to actually apply the change.

I hope this is somewhat useful.

@xanderfrangos
Copy link
Owner

@wywywywy That might actually help. Thanks!

The only HDR display I have at the moment seems to control HDR brightness via DDC/CI, which is not normal. So someone else will have to look into this further for now.

@wywywywy
Copy link

It appears that every 1000 equals 80 nit, although I kind of question that because my screen is supposed to be 400 nit max rather than 480 nit.

Anyway I found out how to get the SDR balance through the Win32 API. I think that to be able to set the SDR balance we'll have to make a call to the display driver.

Data structure: https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-displayconfig_sdr_white_level

Get: https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-displayconfiggetdeviceinfo

Set: https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-displayconfigsetdeviceinfo

@lulle2007200
Copy link

@xanderfrangos Brightness of SDR content can be controlled programatically (see my answer here), HDR brightness cant be controlled by "design".

@xanderfrangos
Copy link
Owner

@xanderfrangos Brightness of SDR content can be controlled programatically (see my answer here), HDR brightness cant be controlled by "design".

That's great! Thank you for sharing. I'm not sure when I'll have a chance to look into this again, but it's great to finally have a working example.

@lulle2007200
Copy link

lulle2007200 commented Jun 23, 2023

For HDR brightness control, you could adjust the (reported) peak luminance in color profile, but that is a hacky solution at best and most HDR applications and games ignore that anyway and roll their own brightness calibration.

I've also left some more info that may be relevant on the issue over at Monitorian, see link above.

@T0biasCZe
Copy link

Acts as a proxy and adjust the slider shown in the image above.
Right now I can mess around with the brightness slier in Twinkle tray, but it looks like it's corrupting my monitors brightness setting (which are disabled)

thats just your monitor. it depends on the specific monitor. For example on my samsung oddysey, I can control the screen brightness in the OSD menu when HDR is on
so twinkle tray should control the brightness when hdr is on on compatible monitors

@lightingman117
Copy link

IMO, this is super complicated and while it would be lovely to fix in the future.

I don't think it would be worth the immediate effort. Dev time is precious.

Let's consider the use-case scenarios.
-Gaming - HDR looks glorious
-Movies - HDR is useful
-TV - eh?
-YT - eh?
-Work [spreadsheets]- eh?
-Other - who cares

I mainly want HDR to operate how f.lux works [disable for full-screen apps] (in reverse).

Enable HDR when full-screen apps are running. Disable when not (use brightness control).

HDR would now auto-enable (and f.lux would auto-disable) at the same time when I launch a game or a movie in full-screen.

This solves a few things:

  1. reduced dev time
    (ain't got time for dat)

  2. HDR functions as intended by developers
    (no fancy overrides/scaling)

  3. fixes several open tickets HDR brightness control broken #447 Twinkle Tray turns off monitor HDR #419 HDR #316 HDR displays not supported #260
    (yay dopamine)

  4. gets a 'fix' in the hands of users sooner rather than later
    "Don't chase perfection when good will do." -someone

My 2cents

Thanks for awesome software!

@lulle2007200
Copy link

I don't agree. Implementing the HDR on-off switching properly and correctly is not simple either and i don't think it requires less resources to implement. Besides that, why would you want to limit HDR to fullscreen (games)? YT and other platforms can deliver HDR content just fine, i might want to watch some content in one window while doing other stuff in another. Just straight up dismissing windowed HDR content seems a little too far.

Having what you propose is better than nothing, but it's only a workaround and doesn't really solve the original issue imo (not being able to control SDR brightness with HDR enabled).

@lulle2007200
Copy link

@xanderfrangos I am starting to work on adding HDR support (unless you are already doing that?).
Basic idea is:
If there is atleast one monitor with HDR enabled, add an SDR brightness slider to the taskbar menu.
Clamp the SDR slider to the smallest peak brightness over all HDR monitors and the highest minim brightness over all HDR monitors, additionally make the range adjustabel in settings, those values come from monitor EDID or from OS default if EDID is not available.
For all monitors with HDR enabled, hide or grey out their "own" brightness slider by default, add a setting to show it anyway.
Additionally, a HDR toggle per monitor could be added.

Let me know what you think about this.

@xanderfrangos
Copy link
Owner

@lulle2007200 I'm not actively working on it. A PR for it would be very welcome. Are you working off the master or beta branch? In the beta branch I've added more code related to dynamically adding user-controlled sliders per-monitor. It might make sense to piggyback off of that instead of having it use separate logic/UI/settings for just the one slider. The HDR (well, SDR-in-HDR) slider could also replace the brightness slider and work off the existing "linked levels" and "normalize brightness" features. Either way, I'm sure the feature would make several users happy.

If you can get the code for updating the SDR brightness working per-display, I can get it wired up to the UI if needed.

@lulle2007200
Copy link

lulle2007200 commented Dec 13, 2023

Yeah, i am on the beta branch.

If you can get the code for updating the SDR brightness working per-display

Im currently researching how to do that. If it is possible to set per monitor, it'd make sense to just replace the slider for HDR monitors.

@ChiIIBiII
Copy link

Hey, having this feature would be awesome, how is it coming along? Maybe I'll have a look at it too. In the meantime, I wanted to point out that there is a script here that is adjusting sdr 'brightness' over multiple monitors if that helps

@klofi
Copy link

klofi commented May 7, 2024

Some dev posted yesterday info about an undocumented Windows 10/11 API allowing to change SDR brightness on HDR display here: https://stackoverflow.com/a/78435051/1054589

@carbongo
Copy link

When I switched to HDR monitors, I was shocked to find out that this hadn't been implemented yet :(

@lulle2007200
Copy link

lulle2007200 commented Jul 9, 2024

Finally figured out how to do it properly.
To set SDR brightness, windows has two methods:

DwmpSDRToHDRBoost(HMONITOR hMon, double brightness) // allowed values: >=80 nits, brightness = nits / 80

DisplayConfigSetDeviceInfo(DISPLAYCONFIG_SET_WHITE_LEVEL* devInfo)
struct DISPLAYCONFIG_SET_WHITE_LEVEL{
	DISPLAYCONFIG_DEVICE_INFO_HEADER header;
	UINT brightness; // allowed values: 80-480 nits, brightness = nits * 1000 / 80
	bool flag_unk; // true to set brightness, false to only update brightness
}

DwmpSDRToHDRBoost is fast, but only sets the new brightness, it doesn't update the system, cached values etc.
The other method is calling DisplayConfigSetDeviceInfo with DISPLAYCONFIG_SET_WHITE_LEVEL.
DISPLAYCONFIG_SET_WHITE_LEVEL has a flag flag_unk that controlls if it sets and updates the brightness or only sets it.
When flag_unk is set, it sets and updates the system for the new brightness, this is very slow.
When flag_unk is not set, it only updates the system for the new brightness.

To update the brightness when the user moves the brightness slider, you'd use DwmpSDRToHDRBoost, followed by a call to DisplayConfigSetDeviceInfo with DISPLAYCONFIG_SET_WHITE_LEVEL and flag_unk = false once the user lets go of the slider.

Windows hard-limits the SDR white level to 480 nits internally, DisplayConfigSetDeviceInfo will fail if the brightness is not in the allowed range. It is possible to apply higher values with DwmpSDRToHDRBoost, but i don't know if this has any side effects.

When i have some more time, i'll implement it.

Note: both of these are undocumented.

@lulle2007200
Copy link

lulle2007200 commented Jul 9, 2024

Also,
HDR can be toggled on and off with:

#define DISPLAYCONFIG_DEVICE_INFO_SET_HDR_STATE 0x10;
DisplayConfigSetDeviceInfo(DISPLAYCONFIG_SET_HDR_STATE* devInfo)
struct DISPLAYCONFIG_SET_HDR_STATE{
	DISPLAYCONFIG_DEVICE_INFO_HEADER header;
	UINT flags; // bit 1 sets HDR enabled/disabled, other bits unknown
}

Auto HDR can be toggled with:

directxdatabasehelper.dll has a function WriteUserGlobalSetting(unsigned int setting, void* callback_unk, void* data, size_t data_size) that is exported by ordinal 110.

to enable/disable auto HDR:

unsigned int data = 1 ; // 1 for enable, 0 for disable
WriteUserGlobalSetting(9 /* setting 9 is Auto HDR */, nullptr, &data, sizeof(data));

@Bush-cat
Copy link

I recommend everyone to check out this repo https://github.com/ledoge/set_maxtml, I tried other scripts that set the sdr brigthness in differrent ways but they were always buggy.

I then made an auto hotkey script with a schedule, transitions, hotkeys and I made it pause for fullscreen apps (I like it for playing games or watching movies)

#Requires AutoHotkey v2.0
#SingleInstance Force

; Schedule entries with brightness levels directly
SCHEDULE := Map()
SCHEDULE["08:00"] := 480
SCHEDULE["12:00"] := 400
SCHEDULE["15:00"] := 320
SCHEDULE["19:00"] := 240
SCHEDULE["21:00"] := 160
SCHEDULE["22:00"] := 80

; Variable to store the resume time
ResumeTime := 0

; Convert time string to minutes since midnight
TimeToMinutes(time) {
    parts := StrSplit(time, ":")
    return parts[1] * 60 + parts[2]
}

; Get the current time in minutes since midnight
GetCurrentTime() {
    return A_Hour * 60 + A_Min
}

; Check if any window is in fullscreen mode
IsFullscreen() {
    activeWindow := WinGetID("A")
/*
    WinGetPos(&winX, &winY, &winWidth, &winHeight, activeWindow)
    screenWidth := A_ScreenWidth
    screenHeight := A_ScreenHeight
    return (winWidth >= screenWidth and winHeight >= screenHeight)
*/
    winStyle := WinGetStyle(activeWindow)
    ; WS_CAPTION = 0xC00000 WS_SIZEBOX = 0x40000
    if (winStyle & (0xC00000 | 0x40000)) {
        return false ; It's not borderless
    }
    return true ; It's borderless
}

; Set brightness level
SetBrightness(value) {
    ; Using 0 as the monitor index will apply the SDR white value to all monitors.
    RunWait(".\set_maxtml\set_sdrwhite.exe 1 " value, , "Hide")
}

; Interpolate brightness between two times
InterpolateBrightness(currentTime, prevTime, nextTime, prevBrightness, nextBrightness) {
    ; Ensure the interpolated brightness is divisible by 4
    return Round((prevBrightness + ((currentTime - prevTime) / (nextTime - prevTime)) * (nextBrightness - prevBrightness)) / 4) * 4
}

; Set brightness based on schedule
SetScheduledBrightness() {
    if (GetCurrentTime() < ResumeTime || IsFullscreen()) {
        ; Schedule is paused or fullscreen is active, do nothing
        SetTimer(SetScheduledBrightness, 600000) ; Check every 10 minutes
        return
    }

    currentTime := GetCurrentTime()
    previousTime := -1
    previousBrightness := 0
    nextTime := 1440 ; Default to end of day
    nextBrightness := 0
    
    for time, brightness in SCHEDULE {
        scheduleTime := TimeToMinutes(time)
        if (scheduleTime <= currentTime && scheduleTime > previousTime) {
            previousTime := scheduleTime
            previousBrightness := brightness
        } else if (scheduleTime > currentTime && scheduleTime < nextTime) {
            nextTime := scheduleTime
            nextBrightness := brightness
        }
    }

    ; Interpolate if there's a next scheduled time
    if (nextTime != 1440) {
        brightness := InterpolateBrightness(currentTime, previousTime, nextTime, previousBrightness, nextBrightness)
        SetBrightness(Round(brightness))
    } else {
        SetBrightness(previousBrightness)
    }

    SetTimer(SetScheduledBrightness, 300000) ; Check every 5 minutes
}

; Apply the brightness level based on the previous scheduled time when the script starts
SetScheduledBrightness()

; Set manual brightness and pause schedule for 2 hours
SetManualBrightness(value) {
    SetBrightness(value)
    ResumeTime := GetCurrentTime() + 120  ; Pause for 2 hours
    if (ResumeTime >= 1440) {
        ResumeTime -= 1440  ; Adjust for overflow past midnight
    }
}

; Resume schedule immediately
ResumeSchedule() {
    ResumeTime := 0
    SetScheduledBrightness()
}

; Hotkeys for manual brightness setting
^!1::SetManualBrightness(80)
^!2::SetManualBrightness(160)
^!3::SetManualBrightness(240)
^!4::SetManualBrightness(320)
^!5::SetManualBrightness(400)
^!6::SetManualBrightness(480)

; Hotkey to resume the schedule immediately
^!0::ResumeSchedule()

@simonboet
Copy link

Tested and this works 100% to adjust SDR brightness and displays changes in the OS SDR settings too.
Can we please get integration into TwinkleTray?
Unfortunately it only supports Windows 11

xanderfrangos added a commit that referenced this issue Oct 3, 2024
@xanderfrangos
Copy link
Owner

Hi all,

I've started adapting https://github.com/ledoge/set_maxtml for Twinkle Tray. So far I only have the SDR brightness sliders working. It's still early, but I wanted to make sure it's working as expected. I don't have a display to properly test this with.

Give this build a try if you have an HDR monitor: https://github.com/xanderfrangos/twinkle-tray/actions/runs/11227334110/artifacts/2027121771

You can enable the SDR brightness slider from Monitor Settings -> Show HDR Settings. Only the sliders are available right now. No hotkey support or other advanced features.

@Bush-cat
Copy link

Bush-cat commented Oct 8, 2024

@xanderfrangos thank you for putting in the work to support HDR, the new builds HDR Slider works perfectly but it does not seem to change from using hotkeys or time adjustments and DDC/CI still is required to be on for the display to appear (which isn't necessary for HDR SDR Brightness), I usually keep DDC off because my Display locks most OSD Options in HDR Mode and when I change them outside the OSD, the Displays Colors become weird.

@SirBughunter
Copy link

SirBughunter commented Oct 8, 2024

Hi all,

I've started adapting https://github.com/ledoge/set_maxtml for Twinkle Tray. So far I only have the SDR brightness sliders working. It's still early, but I wanted to make sure it's working as expected. I don't have a display to properly test this with.

Give this build a try if you have an HDR monitor: https://github.com/xanderfrangos/twinkle-tray/actions/runs/11227334110/artifacts/2027121771

You can enable the SDR brightness slider from Monitor Settings -> Show HDR Settings. Only the sliders are available right now. No hotkey support or other advanced features.

This is working perfectly fine on my Huawei GT 27" display on a Windows 11 24H2 build running on an RX7900XTX! Everything that you mentioned just works 🔥

I've waited so long for a feature like this! Now the only thing left is time of day adjustments support, a way to disable the normal brightness slider and only have the HDR slider shown and it would be perfect! 🙌

@Sleep312
Copy link

大家好

我已经开始为 Twinkle Tray 调整 https://github.com/ledoge/set_maxtml。到目前为止,我只有 SDR 亮度滑块工作。现在还为时过早,但我想确保它按预期工作。我没有显示器来正确测试它。

如果您有 HDR 显示器,请尝试此版本:https://github.com/xanderfrangos/twinkle-tray/actions/runs/11227334110/artifacts/2027121771

您可以从 中启用 SDR 亮度滑块。现在只有滑块可用。没有热键支持或其他高级功能。Monitor Settings -> Show HDR Settings

In version 1.16.2, the entry point for this feature cannot be found.

@xanderfrangos
Copy link
Owner

HDR isn't yet an official feature. Only the build I posted 2 days ago (partially) supports it right now. There's a lot of work to be done still, so don't expect any official releases to include HDR soon.

@microlomaniac
Copy link

Just downloaded and tried the build from the link. works great so far. thank you! looking forward to setting it via scroll wheel on the tray icon again one day, but for now this'll do just fine.

@miish3lov
Copy link

Hi all,

I've started adapting https://github.com/ledoge/set_maxtml for Twinkle Tray. So far I only have the SDR brightness sliders working. It's still early, but I wanted to make sure it's working as expected. I don't have a display to properly test this with.

Give this build a try if you have an HDR monitor: https://github.com/xanderfrangos/twinkle-tray/actions/runs/11227334110/artifacts/2027121771

You can enable the SDR brightness slider from Monitor Settings -> Show HDR Settings. Only the sliders are available right now. No hotkey support or other advanced features.

The download link is dead. Can you please or anyone who downloaded it already re-upload?

@xanderfrangos
Copy link
Owner

The link should still work if you're signed into GitHub

@miish3lov
Copy link

miish3lov commented Dec 16, 2024

sorry, I had to login to comment and didn't realize this was my issue.

I understand there's still no hotkey support?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature request help wanted Extra attention is needed
Projects
Development

No branches or pull requests