Skip to content

Instantly share code, notes, and snippets.

@GetVladimir
Last active October 4, 2024 17:09
Show Gist options
  • Save GetVladimir/c89a26df1806001543bef4c8d90cc2f8 to your computer and use it in GitHub Desktop.
Save GetVladimir/c89a26df1806001543bef4c8d90cc2f8 to your computer and use it in GitHub Desktop.
Force RGB Color on M1 Mac

Force RGB Color on M1 Mac

How to Force RGB Color Output instead of YPbPr on your M1 Apple Silicon Mac for an External Monitor.

This step-by-step video tutorial will guide you through the procedure of forcing RGB color output on your M1 Mac.

Force RGB Color on M1 Mac

Here is the direct link to the video tutorial: https://www.youtube.com/watch?v=Z1EqH3fd0V4

The video also has Closed Captions (Subtitles) that you can enable, to make it easier to follow if needed.



Please note that you're doing any changes on your own risk.

Terminal commands used in the video

Here are each of the Terminal commands mentioned in the tutorial, so that you can just copy and paste them:

open /Library/Preferences

plutil -convert xml1

plutil -convert binary1

plutil -lint



The step-by-step procedure on how to force RGB Color Output on M1 and M2 based Macs with Terminal commands

  1. Open Terminal and use this command to make Finder select the displays plist file:
    open -R /Library/Preferences/com.apple.windowserver.displays.plist

  2. Drag and drop the com.apple.windowserver.displays.plist file to Desktop manually. Don't use the cp command, as it won't add your current user with writing privileges.

  3. Convert the file to XML:
    plutil -convert xml1 ~/Desktop/com.apple.windowserver.displays.plist

  4. Open the converted file with the default plain text editor (avoid using the built-in TextEdit app if possible, since it might modify the file and make it unreadable by the system)
    open -t ~/Desktop/com.apple.windowserver.displays.plist
    or
    open -a CotEditor.app ~/Desktop/com.apple.windowserver.displays.plist

  5. Copy and paste the missing LinkDesription Key under the current display (check the screenshot below for an example of how it should look like):

				<key>LinkDescription</key>
				<dict>
					<key>BitDepth</key>
					<integer>8</integer>
					<key>EOTF</key>
					<integer>0</integer>
					<key>PixelEncoding</key>
					<integer>0</integer>
					<key>Range</key>
					<integer>1</integer>
				</dict>
  1. Save the file and then convert it to binary again:
    plutil -convert binary1 ~/Desktop/com.apple.windowserver.displays.plist

  2. Check if the plist file is valid:
    plutil -lint ~/Desktop/com.apple.windowserver.displays.plist

  3. Open the /Library/Preferences/ folder again:
    open /Library/Preferences/

  4. Drag and drop the updated com.apple.windowserver.displays.plist file from Desktop to the Library folder manually. Don't use the cp command, as it won't add your current user with writing privileges.

  5. Right Click on the com.apple.windowserver.displays.plist file in the Library folder and click on Get Info

  6. Check the boxes for Stationery and Locked.

  7. Reboot the Mac.

That's it!



(Alternative) Terminal commands to force RGB Color Output on M1 and M2 based Macs and workaround for losing RGB color after waking up from sleep

  1. Open Terminal

  2. Paste the following commands to edit the User's displays plist file com.apple.windowserver.displays.[UUID].plist using the built-in PlistBuddy function in macOS:

/usr/libexec/PlistBuddy -c "add DisplaySets:Configs:DisplayConfig:DisplayConfig:DisplayConfig:LinkDescription:BitDepth integer" ~/Library/Preferences/ByHost/com.apple.windowserver.displays.*.plist
/usr/libexec/PlistBuddy -c "set DisplaySets:Configs:DisplayConfig:DisplayConfig:DisplayConfig:LinkDescription:BitDepth 8" ~/Library/Preferences/ByHost/com.apple.windowserver.displays.*.plist
/usr/libexec/PlistBuddy -c "add DisplaySets:Configs:DisplayConfig:DisplayConfig:DisplayConfig:LinkDescription:EOTF integer" ~/Library/Preferences/ByHost/com.apple.windowserver.displays.*.plist
/usr/libexec/PlistBuddy -c "add DisplaySets:Configs:DisplayConfig:DisplayConfig:DisplayConfig:LinkDescription:PixelEncoding integer" ~/Library/Preferences/ByHost/com.apple.windowserver.displays.*.plist
/usr/libexec/PlistBuddy -c "add DisplaySets:Configs:DisplayConfig:DisplayConfig:DisplayConfig:LinkDescription:Range integer" ~/Library/Preferences/ByHost/com.apple.windowserver.displays.*.plist
  1. Reboot your Mac

(Workaround) If your Mac loses RGB color after waking up from sleep mode, either Reboot your Mac (recommended) or use this Terminal command to stop the WindowServer and login again (not recommended):

sudo killall -HUP WindowServer



End result

The end result is having your M1 mac output RGB color to your external monitor instead of YPbPr, potentially making the colors more accurate and the text a bit more crisp, even on older 1080p monitors.

Hopefully this tutorial would be useful to someone.

Please feel free to ask in the comment section if you have any questions regarding this procedure.



Background

While doing a lot of testing on how the Dual-Cable workaround makes RGB to work on M1, I've discovered what changes it makes to macOS, and managed to create a more streamlined workaround without the need to use a second cable.

To make things easier, I've created a step-by-step video tutorial of the whole procedure that should force RGB color output on your M1 Mac connected to an external monitor, and works on an HDMI-to-HDMI cable connection.

Credits

Big thanks goes to the amazing community and all their help over the years to solve issues like this:
https://gist.github.com/ejdyksen/8302862
https://gist.github.com/adaugherity/7435890

Useful Sources

Apple Open Source Project Files for Displays and Graphics
https://opensource.apple.com/source/IOKitUser/IOKitUser-1445.60.1/graphics.subproj/IODisplayLib.c
https://opensource.apple.com/source/IOGraphics/IOGraphics-517.17/IOGraphicsFamily/IOFramebuffer.cpp.auto.html

How to Edit and Convert binary plist files
http://hints.macworld.com/article.php?story=20050803111126899
https://apple.stackexchange.com/questions/155393/how-to-beautify-binary-dict-files
https://discussions.apple.com/thread/1768480

How to Edit plist files using defaults and PlistBuddy
https://ss64.com/osx/defaults.html
https://github.com/mathiasbynens/dotfiles/blob/master/.macos

Apps based on this method

@sudowork has created an awesome script written in Phyton that automates the steps and checks for duplicate files.
You can find more info about it here: https://github.com/sudowork/fix_m1_rgb

@dangh has created an alernative script for fishshell.
You can find more info about it here: https://github.com/dangh/force-rgb.fish

@GetVladimir I've also created a Shortcut to Force RGB Color Output using the built-in Shortcuts app.
You can find how to create the Shortcut here: https://gist.github.com/GetVladimir/c89a26df1806001543bef4c8d90cc2f8?permalink_comment_id=4531552#gistcomment-4531552

@entropyconquers has created a script based on this method written in Phyton that automates the steps, makes a backup and checks for duplicate files.
You can find more info about it here: https://github.com/entropyconquers/Force-RGB-Color-on-M1-M2-Mac-Script

Additional notes

Multiple PixelEncoding and Range keys in the same plist file
Note that there might be multiple instances of the PixelEncoding and Range keys in the same file, one for each output of your monitor and for different AirPlay devices. You might need to update the integer on each one to get RGB color output on all displays.

Getting RGB color only before login
There might be multiple duplicate plist files with the same name in different locations.

Make sure that you only have the main modified file in:
/Library/Preferences

Then make a backup and remove duplicate displays plist files from these locations (if any):
~/Library/Preferences
or
/Users/username/Library/Preferences
and
/Users/username/Library/Preferences/ByHost


Please note that you'll need to have administrator privileges in order to modify the file in /Library/Preferences. Thanks goes to @keegandent and @StrategicalIT for pointing this out.

Updates regarding macOS Monterey

USB-C to DisplayPort
From what I've seen, it seems that macOS Monterey 12.0.1 finally outputs RGB color by default on some monitors when using USB-C to DisplayPort cable on M1 Apple Silicone Macs.

You might need to make a backup and delete these 2 files:
/Library/Preferences/com.apple.windowserver.displays.plist
and
/Users/yourname/Library/Preferences/ByHost/com.apple.windowserver.displays.[UDID].plist

Restart your Mac and it should properly output RGB color on the monitor on the next boot.

HDMI to HDMI
The situation with HDMI seems to got a bit more complicated. Now the whole section for the LinkDescription might be missing from the com.apple.windowserver.displays.plist on a clean install and doesn't seem to be recreated when rotating the screen either.

Luckily, the solution still works, but you might need to manually add this whole section in the displays plist file:

					<key>LinkDescription</key>
					<dict>
						<key>BitDepth</key>
						<integer>8</integer>
						<key>EOTF</key>
						<integer>0</integer>
						<key>PixelEncoding</key>
						<integer>0</integer>
						<key>Range</key>
						<integer>1</integer>
					</dict>



The section usually goes right under the CurrentInfo key, and it should look something like this:

pixelencoding

This should get your RGB color output working on M1 Mac mini, even when connected with HDMI to HDMI cable.

Multiple monitors when one them is using HDMI to HDMI
Additional thanks goes to @somogyi-ede who tested this with multiple monitors and confirmed that the LinkDescription key needs to be added under each monitor instance in order for all of them to receive RGB color output. Link to the comment

Updates regarding macOS 13 Ventura

USB-C to DisplayPort
The macOS 13 Ventura beta seems to outputs RGB color by default on some monitors when using USB-C to DisplayPort cable on M1 Apple Silicone Macs.

You might need to make a backup and delete these 2 files:
/Library/Preferences/com.apple.windowserver.displays.plist
and
/Users/yourname/Library/Preferences/ByHost/com.apple.windowserver.displays.[UDID].plist

Restart your Mac and it should properly output RGB color on the monitor on the next boot.

HDMI to HDMI
Similar as macOS Monterey, the situation with HDMI on macOS Venturs seems a bit more complicated. Usually the whole section for the LinkDescription might be missing from the com.apple.windowserver.displays.plist on a clean install and doesn't seem to be recreated when rotating the screen either.

Luckily, the solution still works, and you still need to manually add this whole section in the displays plist file:

					<key>LinkDescription</key>
					<dict>
						<key>BitDepth</key>
						<integer>8</integer>
						<key>EOTF</key>
						<integer>0</integer>
						<key>PixelEncoding</key>
						<integer>0</integer>
						<key>Range</key>
						<integer>1</integer>
					</dict>



The section usually goes right under the CurrentInfo key, and it should look something like this:

pixelencoding

This should get your RGB color output working on M1 Mac mini, even when connected with HDMI to HDMI cable.

(Optional) Lock the plist file and set it as stationary
After the macOS Ventura 13.3 update, the plist file seems to get overwritten on reboot.

After you make the edits in the file, you can try setting the file /Library/Preferences/com.apple.windowserver.displays.plist as Stationery pad and Locked, so that it doesn't get overwritten on every reboot

Stationery Pad Locked

To do this, right click on the plist file, click on Get Info and check the boxes next to Stationery pad and Locked

This requires further testing and might cause some issues, like not being able to remember new resolutions or display settings. Please note that you're making any changes at your own risk.

Updates regarding macOS 14 Sonoma Beta

USB-C to DisplayPort
The macOS 14 Sonoma seems to outputs RGB color by default when using USB-C to DisplayPort cable.

HDMI to HDMI
The macOS 14 Sonoma seems to outputs YCbCr color by default when using HDMI to HDMI cable.

  • Forcing RGB Color Output still seems to work with the original procedure of modifying the plist files

  • Modifying the display plist files still works with the alternative version

  • After the plist files are modified, putting the Mac to sleep and waking it, it seem to keep the RGB Color output (this seems to be fixed at least on a M1 Mac mini)

If you have any additional questions, please feel free to contact me.

@Amritus
Copy link

Amritus commented Jun 26, 2024

@GetVladimir New user and rebooting doesn't work. New Belkin USB-C -> DP cable still showing off colors.

Also, only way to get correct colors before login is to do your fix, reboot and then at login screen colors are correct. But only then and only once. After login colors are off and after reboot also not correct colors at login screen.

@GetVladimir
Copy link
Author

@Amritus thank you for the update. Glad that it works at least with the workaround.

Try to lock the display plist file from changes to see if that makes any difference. You can check how to lock it in the guide on the top

@Amritus
Copy link

Amritus commented Jun 26, 2024

@GetVladimir Ok, so I just tried with your solution, and tested HDMI. Works the same, only once, and only until login. Tried locking file but did no good. But at least I now know it can be done with HDMI, so that is a nice progress. :D

Any other suggestions?

I do notice that even if I delete the whole com.apple.windowserver.displays.plist file, all my previous settings are restored once rebooted. All my saved connections re-appear even though the file is deleted... Guess they reside somewhere else too?

@GetVladimir
Copy link
Author

@Amritus are you also locking the users display file located in ByHosts:
/Users/[yourname]/Library/Preferences/ByHost/com.apple.windowserver.displays.[UDID].plist

@Amritus
Copy link

Amritus commented Jun 26, 2024

@GetVladimir Yeah!!!

WooHoo! Now it works, even after reboot and login.

But, I disconnect and re-connect A LOT of screens, though for this specific purpose I think the UUID will stay the same as the HDMI will be connected to the same port on the same product.

However, if things go off again, I guess I just have to make a chron job or similar to check status of added UUID and then run a script that fixes it.

So boring that Apple just won't address this.

@GetVladimir
Copy link
Author

@Amritus Awesome! Glad to hear that you got it working.

Yes indeed, it would be very convenient if they just added a menu option in the display settings to choose between RGB and YCbCr color output, similar like they already have on tvOS

@aozaki-kuro
Copy link

I tried to connect the Macbook to the Dock, then plug the screen to the Dock...The UUID doesn't change that often but the full rang RGB fallbacks to YUV limited like after screen sleep. So there isn't any possible fix for this?

@Amritus
Copy link

Amritus commented Jul 18, 2024

I tried to connect the Macbook to the Dock, then plug the screen to the Dock...The UUID doesn't change that often but the full rang RGB fallbacks to YUV limited like after screen sleep. So there isn't any possible fix for this?

Every time the UUID change, the fix need to be applied.
Does the UUID change at all after screen sleep?
Inte doesn't change, but I run directly from HDMI.
As long as I connect the same device my UUID stays the same and the fix works.

@aozaki-kuro
Copy link

I tried to connect the Macbook to the Dock, then plug the screen to the Dock...The UUID doesn't change that often but the full rang RGB fallbacks to YUV limited like after screen sleep. So there isn't any possible fix for this?

Every time the UUID change, the fix need to be applied. Does the UUID change at all after screen sleep? Inte doesn't change, but I run directly from HDMI. As long as I connect the same device my UUID stays the same and the fix works.

Mine is Macbook Pro (M1 Pro) and using Caldigit TS4
Screen is a 4K 144Hz set to 2560 x 1440 HiDPI 144Hz 10bit.
I connected to the dock using TB4 cable, then I tried DP to DP, DP to C, C to C, once connected the display is fine and is able to use full range RGB, but after sleep-wakeup cycle it ends up become YUV limited.

The weird thing is that the UUID did not change, but it turned into YUV limited anyways.

@GetVladimir
Copy link
Author

@aozaki-kuro the suggestion from @Amritus when the UUID changes is correct.

There is also a bug in macOS that loses the RGB color output after waking up from sleep on some configurations and ignores the plist files completely: https://gist.github.com/GetVladimir/c89a26df1806001543bef4c8d90cc2f8#alternative-terminal-commands-to-force-rgb-color-output-on-m1-and-m2-based-macs-and-workaround-for-losing-rgb-color-after-waking-up-from-sleep

The workaround is to either reboot (recommended) or to restart the service with the command in the link above (not recommended)

@waydabber
Copy link

waydabber commented Aug 4, 2024

Hi there,

just want to note that the v3.x version of BetterDisplay has a menu to switch color mode (on the fly, Apple Silicon-only):

353243918-f63ee104-a8e1-415c-aec8-73c27dbe1b85

You can use Configuration Protection to force the color mode if it gets changed to something undesired:

353242788-f7a2100e-016c-439e-a96f-b39fda2671d8

The app also has full CLI access so you can script everything using betterdisplaycli:

Examples to get color modes:

betterdisplaycli get -namelike=lg -connectionMode
betterdisplaycli get -namelike=lg -preferredConnectionMode
betterdisplaycli get -namelike=lg -connectionModeList
betterdisplaycli get -namelike=lg -connectionModeListAll

Examples to set color mode:

betterdisplaycli set -namelike=lg -connectionMode=bpc:12+range:full+encoding:rgb+chroma:444+hdrmode:hdr10
betterdisplaycli set -namelike=lg -connectionMode=bpc:8
betterdisplaycli set -namelike=lg -connectionMode=hdrmode:dolby
betterdisplaycli set -namelike=lg -connectionMode=bpc:10+range:limited
betterdisplaycli set -namelike=lg -connectionMode=encoding:ycbcr+chroma:422
betterdisplaycli set -namelike=lg -connectionMode=2707781557398802176

@aozaki-kuro
Copy link

aozaki-kuro commented Aug 4, 2024

Hi there,

just want to note that the v3.x version of BetterDisplay has a menu to switch color mode (on the fly, Apple Silicon-only):
...

@waydabber Oh thank you soooooooooo much for the information. I just tried it out and it worked like magic! The pro license finally worth the price.

Again, Apple, fix the damn problem since a third-party software already did 🙄

Edit: It's still not good when being used with a dock, the screen went back to YUV limited instead of RGB Full

@waydabber
Copy link

@aozaki-kuro - If RGB is simply not available all in the color mode list, only YUV with chroma subsampling then that probably means simply there is no enough bandwidth for the mode. YUV with chroma subsampling requires less bandwidth. The app lists color modes that are at tenable/attainable based on the display's EDID and negotiated bandwidth.

@aozaki-kuro
Copy link

aozaki-kuro commented Aug 18, 2024

@waydabber Welp I am 100% sure that the monitor should work within the bandwidth limit. When I plug it in or after a restart, the monitor runs in 2560x1440 HiDPI 120Hz 10bit (RGB full) without a problem. But after a sleep cycle, macOS refuse to recognize it as RGB full mode. The problem only appears when I connect through dock, no problem when I connect it with the Macbook Pro directly. I have checked that the UUID never changed.

Now I'm not sure whether this is a macOS / hardware bug or the monitor's problem.

@waydabber
Copy link

@aozaki-kuro - oh ok, so the problem is that it reverts back to the old setting but the RGB is still available? If so, then you can use Configuration Protection menu in the app so the OS does not revert to some unwanted Color Mode (see the screenshot for this in the post above). Anyway, let's not hijack this thread, if there is any question regarding how to use the app, go to the discussions section here: https://github.com/waydabber/BetterDisplay/discussions. Let's leave this thread for the configuration file edit based approach which is a entirely valid and great solution.

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