Dwm_lut - Apply 3D LUTs to the Windows desktop for system-wide color correction/calibration

About

This tool applies 3D LUTs to the Windows desktop by hooking into DWM. It works in both SDR and HDR modes, and uses tetrahedral interpolation on the LUT data. In SDR, ordered dithering is applied to the output to reduce banding.

Right now it should work on any 20H2 or 21H1 build of Windows 10, and also the current build of Windows 11, and I'll try to update it whenever a new version breaks it.

Usage

Use DisplayCAL or similar to generate .cube LUT files of any size, run DwmLutGUI.exe, assign them to monitors and then click Apply. Note that LUTs cannot be applied to monitors that are in "Duplicate" mode.

For ColourSpace users with HT license level, 65^3 eeColor LUT .txt files are also supported.

HDR LUTs must use BT.2020 + SMPTE ST 2084 values as input and output.

Minimizing the GUI will make it disappear from the taskbar, and you can use the context menu of the tray icon to quickly apply or disable all LUTs. For automation, you can start the exe with any (sensible) combination of -apply, -disable, -minimize and -exit as arguments.

Note: DirectFlip and MPO get force disabled on monitors with an active LUT. These features are designed to improve performance for some windowed applications by allowing them to bypass DWM (and therefore also the LUT). This ensures that LUTs get applied properly to all applications (except exclusive fullscreen ones).

Compiling

Using MSYS2's mingw64 environment: Install mingw-w64-x86_64-MinHook and run

gcc dwm_lut.c -O3 -shared -static -s -lMinHook -ld3dcompiler -luuid -Wl,--exclude-all-symbols -o dwm_lut.dll

to generate the DLL.

As for the GUI, just open the project in Visual Studio and compile a x64 Release build.

Comments
  • Incorrect color when 10bit wide gamut monitor connect to PC through HDMI port which only support 8bit color

    Incorrect color when 10bit wide gamut monitor connect to PC through HDMI port which only support 8bit color

    So I have one PC connecting to monitor A and B through DP ports. However, monitor A also connects to the same PC over an HDMI port with a KVM switch in between. Monitor A, therefore, is identified as two displays in the system, but as they are in duplicate mode, still shows same image.

    Here comes the problem. When I have monitor A connects only through HDMI or DP, the 3dlut works great. But if I connect it through HDMI and DP at the same time, the color is washed out.

    The color of monitor B is not affected though.

  • Stopped working on latest Windows 11 22H1 22000.706 update

    Stopped working on latest Windows 11 22H1 22000.706 update

    It appears dwm_lut is no longer working on Windows 11 22H1 build 22000.706. I'm wondering if Microsoft rolled some of the changes that break 22H2 back into 22H1 22000.706.

  • Adaptive Sync Not Working

    Adaptive Sync Not Working

    Hi,

    Thanks for making this program! When I apply a 3dlut, Adaptive Sync is disabled. I do not game, but the windows Movies & TV UWP video player uses Adaptive Sync to match the display + video framerates to eliminate judder. Is this something that can be fixed?

  • Add ability to specify LUT file paths via command argument

    Add ability to specify LUT file paths via command argument

    DwmLut has some useful command arguments right now. However, if user wants to switch between different lut files via command, he has to edit config.xml then run with -apply.

    This is attempt to fill the void by supporting two extra arguments "-sdr" and "-hdr". Example:

    DwmLutGUI.exe -sdr "1:C:\luts\1\sdr.lut;2:C:\luts\2\sdr.lut" -hdr "1:C:\luts\1\hdr.lut;2:C:\luts\2\hdr.lut" -apply -exit
    

    This example sets monitor 1's SDR lut to "C:\luts\1\sdr.lut", and monitor 2's SDR lut to "C:\luts\2\sdr.lut". Similar to HDR luts.

    Also, paths set via this way does not permanently change the content of config.xml. This suits the "temporary" nature of this argument.

    What do you think?

  • Incompatible with HDCP Protected Content (Netflix)

    Incompatible with HDCP Protected Content (Netflix)

    When playing DRM protected content, HDCP activates and causes one or two black flashes of the screen. The LUT is unloaded. The application status becomes "Inactive". And the video begins playing.

    As a reminder, High-bandwidth Digital Content Protection (HDCP) is used for DRM on video streaming services.

    Instructions:

    1. Launch dwm_lut and press Apply
    2. Log into a video streaming platform, like Netflix, Amazon Prime, BBC iPlayer, etc.
    3. Play a video (I recommend testing on Firefox. It shows a HDCP icon in the address bar whenever it kicks in.)

    I don't know what you could do about this. Maybe reactivate once HDCP is no longer active?

  • Not working with Intel HD3000

    Not working with Intel HD3000

    On Windows 11. Says active but no change in color output is seen. Oddly with a generic Microsoft driver active did work as expected. According to GPU-Z the generic driver supports OpenGL 2.1, the Intel driver supports OpenGL 3.1 with many report on the web talking about wonky OpenGL support.

    Any testing I can do? Let me know.

  • Error - Access to path 0_0.cube is denied.

    Error - Access to path 0_0.cube is denied.

    Hi ledoge,

    I'm getting the following error when I hit the Apply button, after selecting a LUT to apply. Any ideas on what might be causing it?

    For context, the very first time I ran the tool it worked fine, then after trying to load a different LUT file it started throwing this error and I wasn't able to get it working again.

    image


    My OS details:

    Edition Windows 11 Home Version 21H2 Installed on ‎23/‎08/‎2022 OS build 22000.856 Experience Windows Feature Experience Pack 1000.22000.856.0

  • Using LUT with Netflix app causes screen to pixelate

    Using LUT with Netflix app causes screen to pixelate

    Applying the LUT while the Netflix app is running causes the screen to become pixelated and unusable. Disabling the LUT immediately resolves the issue. I also tried with the native Hulu and Amazon Prime Video apps and it did not reproduce. Not a big deal to turn it off, though.

    Example of the issue https://photos.app.goo.gl/r4ta6sHf8H8NBUUZ8

  • Inacuracy in the shadows

    Inacuracy in the shadows

    I found it looks different when I apply my calibration LUT to LUT stress test image in Resolve, compared to loading it into DwmLut. I can't show it, because (luckily) screenshots aren't affected by the LUT, but it makes shadows desaturated, compared to applying the LUT in Resolve. Also it looks like there is some downsizing of the cube size of the LUT before applying the LUT. Probably this is the reason for the artifact I got?

  • Debanding option

    Debanding option

    I hope GitHub issues are the right place for feature requests, if not, feel free to close this.

    I stumbled upon this repo by accident when I was calibrating my friend's brand new OLED TV last weekend and I am absolutely loving it so far. I can't believe I didn't find it sooner, because I posted around 5 years ago on ReShade's forum trying to get ReShade to do what you are doing by hooking the DWM and have been desperate to find something since then.

    Which leads me right into this request. Web content, specifically YouTube, is often rife with banding and the video rendering pipelines of desktop browsers like Chrome and Firefox are optimised for performance and battery life and so do all levels conversion in 8 bit, making the banding even worse.

    I already noticed a reduction in banding when using dwm_lut over the standard GPU gamma table, but the inclusion of a debanding shader would make it even better.

    ReShade already includes an open source debanding effect, but it is written in ReShade's own effect language which according to its author is based on HLSL. I hope porting it to actual HLSL is easy.

    https://github.com/crosire/reshade-shaders/blob/slim/Shaders/Deband.fx

    Thanks!

  • PNG LUT Support

    PNG LUT Support

    Hi there,

    I'm wondering if PNG LUTs (like those used for ReShade) can be supported. I haven't been able to find a tool that can convert my PNG LUTs into .CUBE.

  • Windows framerate locked to 30fps when LUTs are enabled

    Windows framerate locked to 30fps when LUTs are enabled

    My laptop, even when running off of a power brick, cuts all program frame rates in half when this program applies a LUT. I am running a dedicated graphics card through an Intel graphics adapter. Is there a fix for this?

  • Why the recommendation to use sRGB default?

    Why the recommendation to use sRGB default?

    Read all the information from the DisplayCAL forum and I still don't understand the recommendation to use the Windows built in sRGB profile as the display profile.

    dwm_lut applies the lut to everything displayed on screen but color managed apps would still benefit from an sRGB profile created for the display with DisplayCAL no?

    My reasoning is a program needs to know some display characteristics to render stuff correctly otherwise they assume some standard and a sort of reference display and squeeze all pixels displayed into that standard. In most cases they assume a 1:1000 contrast a gamma 2.2 or sRGB tone curve ..., obviously a display is from factory most of the time different than this assumed common denominator standard.

    So wouldn't it make sense to create a display profile aka. sRGB in DisplayCAL use it as default ICC profile generate 3DLUT from it with a preferred gamma of 2.2 as an example and apply the 3DLUT with dwm_lut?

    My only concern with this approach is vcgt that might be applied 2x (Display CAL profile loader + dwm_lut), not sure if it would be the case. I could set tone curve as measured in DisplayCAL when creating the profile to avoid this.

    What are your thoughts on this topic?

    My aim is to give apps info about the display like contrast white point and so on via ICC so they don't assume stuff while globally applying a 3dlut on top.

    It would just be something like a pixel value going from: 0.2343 -> 0.2143 (what the app thinks it should be in sRGB --> 0.2142 (what the actual lut applied would show at the end) My concern is app doing this In file 0.2343 -> 0.2452 (some assumptions in the app without profile) -> 0.2243 final value based on wrong value from the app when dwm_lut is applied.

    Hope you get the example and looking forward to your answer.

  • Clarification on how to use in combination with DisplayCAL

    Clarification on how to use in combination with DisplayCAL

    I must be doing something wrong here....

    So, I have a benq SW270C.

    1. I started windows fresh. No DisplayCAL profile loader running, no dmw_lut running, all color profiles removed in windows.
    2. I hardware calibrated the screen with Palette Master Element to it's native color gamut.
    3. I ran a Calibrate & Profile in DisplayCAL, which generated a ICC profile
    4. I loaded that profile into windows and I ran a Verification step in DisplayCAL. Everything passed, calibration looking good.
    5. After loading the ICC profile in windows, color managed application behave like they should, windows desktop and other application show over saturated color, as expected.

    So far so good and I've been doing this ever since I got this monitor. But then...

    1. I turn that ICC profile into a 3DLUT using DisplayCAL, using it's default setting, and save it to a file.
    2. I remove all ICC profiles from my monitor in windows's color management.
    3. I make sure DisplayCALs profile loader isn't running.
    4. I start dwm_lut, load the 3DLUT cube file and assign it to my monitor as the SDR profile
    5. The windows desktop isn't over saturated anymore, and it looks like color managed applications are also working as expected. No washed out colors, no overly saturated colors. Can't judge color correctness though.

    But when I run DisplayCAL's Verification step again, the report shows the colors are completely wrong. Here's the summary.

    Criteria | Nominal | Recommended | # | Actual | Result -- | -- | -- | -- | -- | -- Measured vs. assumed target whitepoint ΔE*00 | <= 2 | <= 1 |   | 4.61 | NOT OK ✖ Measured vs. display profile whitepoint ΔE00 | <= 1 | |  | 4.95 |   Average ΔE00 | <= 1.5 | <= 1 |   |  5.39 | NOT OK ✖ Maximum ΔE*00 | <= 4 | <= 3 | 322 | 11 | NOT OK ✖


    What's happening here? Why is DisplayCAL's verification step failing?

    Did I miss something fundamental in my workflow above?

AviSynthPlus color correction filter.

Description A color constancy filter that applies color correction based on the grayworld assumption. For more info. This is a port of the FFmpeg filt

Aug 7, 2022
This plugin allows Flutter desktop apps to defines system/inapp wide hotkey (i.e. shortcut).

hotkey_manager This plugin allows Flutter desktop apps to defines system/inapp wide hotkey (i.e. shortcut). hotkey_manager Platform Support Quick Star

Nov 30, 2022
Invoke.hpp - std::invoke/std::apply analogs for C++11/14

invoke.hpp std::invoke/std::apply analogs for C++11/14 Requirements gcc >= 4.9 clang >= 3.8 msvc >= 2015 Installation invoke.hpp is a header-only libr

Jun 30, 2022
Playbit System interface defines an OS-like computing platform which can be implemented on a wide range of hosts

PlaySys The Playbit System interface PlaySys defines an OS-like computing platform which can be implemented on a wide range of hosts like Linux, BSD,

Nov 12, 2022
A simple fisheye distortion correction program
A simple fisheye distortion correction program

Correct Fisheye Distortion of the first Chinese Mars Image 热烈祝贺中国首次火星探测天问一号任务探测器发回火星照片 Requirements A C++ compiler OpenCV How to compile cmake . make

Sep 2, 2022
Lidar-with-velocity - Lidar with Velocity: Motion Distortion Correction of Point Clouds from Oscillating Scanning Lidars
Lidar-with-velocity - Lidar with Velocity: Motion Distortion Correction of Point Clouds from Oscillating Scanning Lidars

Lidar with Velocity A robust camera and Lidar fusion based velocity estimator to undistort the pointcloud. This repository is a barebones implementati

Nov 29, 2022
"Zero setup" cross-compilation for a wide variety of architectures.

"Zero setup" cross-compilation for a wide variety of architectures. xcross includes compact docker images and a build utility for minimal setup C/C++ cross-compiling, inspired by rust-embedded/cross

Nov 10, 2022
An open collection of tools and experiments for rendering wide-gamut scene-linear data into an image for an SDR or HDR display device.

Open Display Transform An open collection of tools and experiments for rendering wide-gamut scene-linear data into an image for an SDR or HDR display

Nov 14, 2022
This repository is used for automatic calibration between high resolution LiDAR and camera in targetless scenes.
This repository is used for automatic calibration between high resolution LiDAR and camera in targetless scenes.

livox_camera_calib livox_camera_calib is a robust, high accuracy extrinsic calibration tool between high resolution LiDAR (e.g. Livox) and camera in t

Nov 26, 2022
Fast and Accurate Extrinsic Calibration for Multiple LiDARs and Cameras
Fast and Accurate Extrinsic Calibration for Multiple LiDARs and Cameras

Fast and Accurate Extrinsic Calibration for Multiple LiDARs and Cameras The pre-print version of our paper is available here. The pre-release code has

Nov 24, 2022
This package estimates the calibration parameters that transforms the camera frame (parent) into the lidar frame (child)
This package estimates the calibration parameters that transforms the camera frame (parent) into the lidar frame (child)

Camera-LiDAR Calibration This package estimates the calibration parameters that transforms the camera frame (parent) into the lidar frame (child). We

Nov 25, 2022
A generic and robust calibration toolbox for multi-camera systems
A generic and robust calibration toolbox for multi-camera systems

MC-Calib Toolbox described in the paper "MultiCamCalib: A Generic Calibration Toolbox for Multi-Camera Systems". Installation Requirements: Ceres, Boo

Nov 28, 2022
This repo contains source code of our paper presented in IROS2021 "Single-Shot is Enough: Panoramic Infrastructure Based Calibration of Multiple Cameras and 3D LiDARs"
This repo contains source code of our paper presented in IROS2021

Single-Shot is Enough: Panoramic Infrastructure Based Calibration of Multiple Cameras and 3D LiDARs Updates [2021/09/01] first commit, source code of

Nov 25, 2022
the implementations of 'A Flexible New Technique for Camera Calibration' and Bouguet's method

StereoCameraCalibration MonocularCameraCalibration/StereoCameraCalibration/StereoCameraRectification 1、Class "MonocularCameraCalibration" provides the

Nov 3, 2022
Project to create a teensy based gamecube controller with hall effect sensors, snapback filtering, and notch calibration
Project to create a teensy based gamecube controller with hall effect sensors, snapback filtering, and notch calibration

PhobGCC Gamecube controller motherboard using a teensy as the microcontroller. Aim is to make an accessible and consistent controller. Has the option

Dec 1, 2022
A beginner friendly desktop UI for Tasmota flashed devices for Windows, macOS and Linux.
A beginner friendly desktop UI for Tasmota flashed devices for Windows, macOS and Linux.

TasmoManager A beginner friendly desktop UI for Tasmota flashed devices for Windows, macOS and Linux. Features Native Tasmota device discovery (via ta

Nov 20, 2022
Add virtual monitors to your windows 10 device! Works with Oculus software, obs, and any desktop sharing software

License MIT and CC0 or Public Domain, whichever is least restrictive -- Use it AS IS - NO IMPLICIT OR EXPLICIT warranty This may break your computer,

Nov 26, 2022
Windscribe 2.0 desktop client for Windows, Mac and Linux

Windscribe 2.0 Desktop Application This repo contains the complete source code for the Windscribe 2.0 app. This includes installer, service/helper, ba

Dec 2, 2022
A npm package that lets you automate your windows desktop.

js-macro A npm package that lets you automate your windows desktop. npm i js-macro Examples Simple cursor usage const { cursor } = require("js-macro"

Jul 30, 2022