BartoszCichecki / LenovoLegionToolkit

Lightweight Lenovo Vantage and Hotkeys replacement for Lenovo Legion laptops.
GNU General Public License v3.0
4.52k stars 219 forks source link

[FEAT]: Use the more battery-efficient 60Hz refresh rate mode that Vantage uses. #1325

Closed shockdude closed 3 weeks ago

shockdude commented 3 weeks ago

Rules

Version

2.22.1

OS

Windows 11 23H2 build 22631

Device

Legion 5 Slim 16APH8

Is your feature request related to a problem?

Vantage can activate a different 60Hz refresh rate mode than LLT, and I believe this alternative 60Hz mode is more battery efficient. When LLT sets the screen's refresh rate to 60Hz, the screen doesn't flicker. Meanwhile, Vantage's Adaptive Refresh (60Hz refresh rate change on unplug) causes the screen to flicker - an indication that an alternative 60Hz mode was activated. This alternative 60Hz mode can be manually set in Windows Settings > System > Display > Advanced Display > Choose a refresh rate. When selecting 60Hz here, the screen flickers, and the alternative 60Hz mode is activated.

How would you like the problem to be solved?

When using LLT to set a 60Hz refresh rate, have LLT activate the alternative 60Hz mode the same way Vantage & Windows settings does, for better battery efficiency.

What alternatives have you considered?

Do nothing - this is all based on an untested battery saving assumption. But why else would this alternative 60Hz mode exist?

Additional information

As described above, this particular Windows refresh rate setting can also activate the alternative 60Hz mode. image

BartoszCichecki commented 3 weeks ago

I am not aware of any "alternative" 60Hz settings. In fact, the Windows APIs that LLT do not support VRR (Dynamic) rates at all.

shockdude commented 3 weeks ago

The alternative 60Hz mode is very obvious when using the described Advanced display refresh rate setting. But this whole thing is weird, so understandable that this is not planned.

I have no idea why there's 2 different 60Hz modes, one of which is usable by those Windows APIs (other resolution-changing tools I've tried access the same APIs), and one of which is usable by some other method (Vantage). Why not just have a single 60Hz resolution mode.

shockdude commented 3 weeks ago

I found the Windows API that sets this alternative 60Hz mode. Might do a PR if I have enough time. Based on https://stackoverflow.com/questions/58824449/is-there-an-api-for-the-windows-10-instant-resolution-change

#include <windows.h>

int main()
{
    UINT32 numPathArrayElements = 0, numModeInfoArrayElements = 0;
    UINT32 filter = QDC_ALL_PATHS;
    GetDisplayConfigBufferSizes(filter, &numPathArrayElements, &numModeInfoArrayElements);

    DISPLAYCONFIG_PATH_INFO* pathArray = new DISPLAYCONFIG_PATH_INFO[numPathArrayElements];
    DISPLAYCONFIG_MODE_INFO* modeInfoArray = new DISPLAYCONFIG_MODE_INFO[numModeInfoArrayElements];
    ZeroMemory(pathArray, sizeof(DISPLAYCONFIG_PATH_INFO) * numPathArrayElements);
    ZeroMemory(modeInfoArray, sizeof(DISPLAYCONFIG_MODE_INFO) * numModeInfoArrayElements);
    QueryDisplayConfig(filter, &numPathArrayElements, pathArray, &numModeInfoArrayElements, modeInfoArray, NULL);

    int ix = pathArray[0].targetInfo.modeInfoIdx; //assuming path[0] is primary
    modeInfoArray[ix].targetMode.targetVideoSignalInfo.vSyncFreq.Numerator = 60;
    modeInfoArray[ix].targetMode.targetVideoSignalInfo.vSyncFreq.Denominator = 1;
    SetDisplayConfig(numPathArrayElements, pathArray, numModeInfoArrayElements, modeInfoArray, SDC_APPLY | SDC_USE_SUPPLIED_DISPLAY_CONFIG | SDC_ALLOW_CHANGES | SDC_SAVE_TO_DATABASE);

    return 0;
}
BartoszCichecki commented 3 weeks ago

It's not "alternative" or anything. There is only one API that is documented and that is ChangeDisplaySettings. Windows 11 does all sorts of magic to figure out how to "reinitialize" display depending on different things like availabe Adaptive Sync range (aka FreeSync range) etc. If refresh rate can be changed without blacking out it is changed on the fly, if it can't then display blacks out.

Since the old days, registry contained definitions of available modes for the display which include resolution, vertical and horizontal frequencies, color depth etc. Later displays started advertising their capabilities via EDID which contains same information. Recently EDID was extended with FreeSync range (and the cryptic Gsync equivalent). The Settings app filters available refresh rates based on some unknown criteria,

So basically now there are two ways to change vertical refresh rate:

  1. stop whatever you are doing, set new display mode - this will black out
  2. set new display mode "on the fly" - this will not black out (and also requires WDDM 3.1 driver)

Of course display driver has some role here in deciding which route to take, but the result is the same for both: 60Hz is 60Hz.

The setting you mentioned in Vantage is very similar. Lenovo exposes compatible vertical refresh rates via LENOVO_INTERNAL_PANEL_REFRESH_RATE_DATA and also allows toggling this via WMI interface. Since this will be performed on a low level it likely takes route number 1 mentioned above to avoid confusing Windows and drivers. That is possible, because for a very long time now, display (and display adapter) can also initiate mode change, in which case Windows will just accept the setting even though it was not available before.

This approach was taken most likely to get rid of some moving parts like refresh rates missing/disappearing after bad driver installs etc. Since this method doesn't have any benefits over using WinAPI it was not (and probably never will be) included in LLT.

Regardless of the method, if you see 60Hz it is the same 60Hz as any other. There might of course be differences in horizontal refresh rate or synchronization block sizes etc. but with LCD panels and digital interfaces they are in 99.9% of cases irrelevant (constant).

BartoszCichecki commented 3 weeks ago

I found the Windows API that sets this alternative 60Hz mode. Might do a PR if I have enough time. Based on https://stackoverflow.com/questions/58824449/is-there-an-api-for-the-windows-10-instant-resolution-change

#include <windows.h>

int main()
{
    UINT32 numPathArrayElements = 0, numModeInfoArrayElements = 0;
    UINT32 filter = QDC_ALL_PATHS;
    GetDisplayConfigBufferSizes(filter, &numPathArrayElements, &numModeInfoArrayElements);

    DISPLAYCONFIG_PATH_INFO* pathArray = new DISPLAYCONFIG_PATH_INFO[numPathArrayElements];
    DISPLAYCONFIG_MODE_INFO* modeInfoArray = new DISPLAYCONFIG_MODE_INFO[numModeInfoArrayElements];
    ZeroMemory(pathArray, sizeof(DISPLAYCONFIG_PATH_INFO) * numPathArrayElements);
    ZeroMemory(modeInfoArray, sizeof(DISPLAYCONFIG_MODE_INFO) * numModeInfoArrayElements);
    QueryDisplayConfig(filter, &numPathArrayElements, pathArray, &numModeInfoArrayElements, modeInfoArray, NULL);

    int ix = pathArray[0].targetInfo.modeInfoIdx; //assuming path[0] is primary
    modeInfoArray[ix].targetMode.targetVideoSignalInfo.vSyncFreq.Numerator = 60;
    modeInfoArray[ix].targetMode.targetVideoSignalInfo.vSyncFreq.Denominator = 1;
    SetDisplayConfig(numPathArrayElements, pathArray, numModeInfoArrayElements, modeInfoArray, SDC_APPLY | SDC_USE_SUPPLIED_DISPLAY_CONFIG | SDC_ALLOW_CHANGES | SDC_SAVE_TO_DATABASE);

    return 0;
}

Regarding this - this is just uses a "lower level" WinAPI that is also used by the one I mentioned above.

shockdude commented 3 weeks ago

Appreciate the insight. Having 2 different methods of setting refresh rate (legacy vs. modern WDDM3.1) does make more sense than having different 60Hz refresh rate modes.

BartoszCichecki commented 3 weeks ago

This is a pretty cool video going into details of how display modes work in real life https://www.youtube.com/watch?v=l7rce6IQDWs

It discusses VGA interface, but today (skipping connectors and protocols) the same thing happens.