Skip to content

Instantly share code, notes, and snippets.

@GetVladimir
Last active November 15, 2024 14:00
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.

@traderdude123
Copy link

@GetVladimir

The TV is receiving RGB since i can see that TV shows RGB as in the screenshot above.

What i m saying is even if there is a difference between RGB and YCBCR444, the human eye cannot make out the difference. if there was a difference it would show in some tests. But i have tested color gradients / images and texts and i cannot find any difference. I even tested the grays and blacks. There is no difference.

if you think there is a difference, let me know how i can test the difference. Because now i have both cables which can do RGB and YCBCR444. But the USB-C adapter does get hot after a while. so i prefer using direct hdmi-hdmi connection with YCBCR444.

@GetVladimir
Copy link
Author

@traderdude123 that is a pretty cool setup if you can test both of them.

My suggestion would be to check with these tests from Lagom if you haven't done already: http://www.lagom.nl/lcd-test/

Check them first with YCbCr and then with RGB to see if you can notice any difference on your setup on any of the tests, colors and texts.

Make sure to use native screen resolutions (without scaling) and be aware of browsers like Safari that do color profiles.

@traderdude123
Copy link

@GetVladimir

Which browser do you recommend?

@GetVladimir
Copy link
Author

@traderdude123 They should all work. Safari uses the color profile selected in the System Preferences and it might give a different results for images that have color profiles set to them.

Google Chrome and Edge usually default to sRGB, but newer versions might also read the System Color Profile. It's just something to be aware about.

On the main page of the Lagom tests, there are also images that can be downloaded without the color profiles, so you don't need to depend on the browser.

@traderdude123
Copy link

@GetVladimir

OK , so i set native resolution (default) in display settings and native icc profile(as assigned to TV by macOS). No Calibration done.

I used chrome and set full screen with contrast gradient images.

I capture photos of YCBCR and RGB Blue contrast gradient images. I could not find any difference. I even looked as closes as possible and still could not find any difference.

I check all the test, still could not find any difference. may be my eyes are not so good.

Is there any objective way to find the difference between RGB and YCBCR444?

Here attached gradient test from 1 to 6 captured on phone.

YCBCR444:
IMG_0181_YCBCR

RGB:
IMG_0180_RGB

@GetVladimir
Copy link
Author

@traderdude123 thank you for the details.

I trust you, if you compared everything and there are no noticeable differences, that means there aren't any differences on your setup.

I do appreciate that you checked this and for all the informations.

@traderdude123
Copy link

traderdude123 commented Apr 14, 2023

@GetVladimir

I found the issue with RGB and YCBCR outputs.

The reason they were matching is because on a OLED TV, the black level setting was set to Auto. What this does is it sets low for YCBCR and high for RGB. and as a result no difference.

I then changed to RGB low, the image color contrast improved compared to YCBCR low. But now when i view text or any videos in browser ,text is looking washed out on white background, and i m losing a lot of shadow detail in videos.

But yes, now there is a difference between RGB low and YCBCR low.

In windows , i can control the RGB full and limited signal , is there any way to set RGB Full or limited in macos?

Note i have the option to set RGB Low or High i.e Limited or full in my Apple TV device. But there is no such option in macOS.

@GetVladimir
Copy link
Author

@traderdude123 good question. There doesn't seems to be an option in macOS to set RGB low or high (Full or limited range).

This option is available on tvOS and needs to be added in macOS

@traderdude123
Copy link

@GetVladimir

Anyway to get RGB on hdmi-hdmi? because the usbc-hdmi Adapter is getting very hot.

I did get RGB on hdmi-hdmi but then i tested sleep with it and now its gone. I have no idea what i did to get RGB on hdmi-hdmi. LOL.

@GetVladimir
Copy link
Author

@traderdude123
Copy link

@GetVladimir

The method worked after i removed both the window server plist file and then ran the commands.

Thanks for that.

But i m now getting RGB 8b, I was getting RGB 10b earlier.

I tried changing the bitdepth to 10 in the command , but its still stuck at 8b.

@GetVladimir
Copy link
Author

@traderdude123 Awesome! Glad to hear that you got RGB color output working.

I'm not sure if you can get 10 bit and RGB on the HDMI-to-HDMI connection at the same time.

You can try editing the plist manually and change both depth and bit depth to 10 bit (needs to be changed on two places).

@traderdude123
Copy link

@GetVladimir

I tried setting 10-bit to both depth and bit depth. No luck.

Few more observations.

The commands work only if you remove both com.window.server.plist file i.e from /Library/Preferences and ~/Library/Preferences/ByHost.
Then reboot so they get generated again.
Then run the commands
Then reboot again.

Another caveat is if you change refresh rate , then it switches back to YCBCR.

@traderdude123
Copy link

@GetVladimir

Another observation , on hdmi-hdmi connection on RGB is taking low on auto. but with usb-c-hdmi connection the RGB is taking high on auto. There is some observable color difference between hdmi-hdmi 8b RGB and usb-c-hdmi 10b RGB.

This could be due to color depth , but i can't seem to get 10b on hdmi-hdmi connection.

@GetVladimir
Copy link
Author

@traderdude123 thanks for the info.

Yes, that might make sense, since the HDMI on the Mac might not have the bandwidth required for 10 bit RGB

@traderdude123
Copy link

@GetVladimir

But the hdmi-hdmi cable had bandwidth for 10b YCBCR444, isnt that enough bandwidth for 10b RGB?

@GetVladimir
Copy link
Author

@traderdude123 No, that's actually one of the differences between RGB and YCbCr.

RGB carries the full info for each channel (Red, Green and Blue) and requires more bandwidth, while YCbCr is usually compressed

@traderdude123
Copy link

@GetVladimir

So you are saying YCBCR444 is compressed?

@GetVladimir
Copy link
Author

@traderdude123 Yes, at least on macOS.

That's why the Pixel Encoding key in the plist is set to 1 when using YCbCr.

When using RGB, the Pixel Encoding is set to 0

@traderdude123
Copy link

@GetVladimir

Hmm, thats interesting. This is first time i heard that YCBCR444 is compressed.

I thought YCBCR422 or 420 was compressed and 444 was uncompressed. But in macOS even ycbcr444 is compressed.

But is this the case in windows also?

@GetVladimir
Copy link
Author

@traderdude123 Do you think perhaps macOS uses 4:2:2 instead of 4:4:4 YCbCr when the Pixel Encoding is set to 1?

How does it show on the On Screen Display menu of the TV/Monitor when you set it to 1?

@traderdude123
Copy link

@GetVladimir

Also , i was able to get 10b RGB on hdmi-hdmi with BetterDisplay when i had the trial.

So i m sure the hdmi cable can do 10b RGB.

@GetVladimir
Copy link
Author

GetVladimir commented Apr 14, 2023

@traderdude123 does your Mac have HDMI 2.1 or 2.0 port?

As far as I know, there isn't a way to realistically get 10-bit RGB 4K over HDMI 2.0 connection.

@traderdude123
Copy link

@GetVladimir

M2 Mac mini with hdmi 2.1

@GetVladimir
Copy link
Author

@traderdude123 Then the bandwidth limitations doesn't apply to you.

HDMI 2.1 theoretically has 48Gbps in bandwidth (compared to 18Gbps of HDMI 2.0), so it can handle 10-bit RGB at 4K.

I haven't tested this myself though, since my M1 Mac mini has HDMI 2.0.

@traderdude123
Copy link

@GetVladimir

ahh ic.

Ok , so let me know what i need to test to get 10b RGB over hdmi-hdmi.

I was playing around with both the cables yesterday and i somehow got 10b RGB 4k over hdmi-hdmi.

But now what i suspect is RGB colors are different from hdmi 2.1 port and usb-c port. Because even if we run at 8b RGB over hdmi, the auto black level should set it to high, but its setting it to low. which means there is a signal difference between hdmi 2.1 port and usb-c port

Also there is color differences coming for the same RGB signal coming from hdmi 2.1 port and usb-c.

Why couldn't apple just provide a simple switch for RGB and YCBCR, i will never know. when they clearly know they are selling mac mini and till today no way to configure external displays correctly like in windows.

@GetVladimir
Copy link
Author

@traderdude123 Maybe the USB-C adapter that you have does some kind of active conversion to HDMI, that might be the reason why it gets hot as well.

At the moment, I don't know of any other way to activate the 10 bit RGB color except with the plist files.

And you're right, all this would be so much easier if the setting to choose RGB color and range was added by Apple in the System Settings.

@traderdude123
Copy link

@GetVladimir

Can you test on your monitor or TV if RGB either 8b or 10b coming from hdmi and usb-c port are same or different?

Try testing some random images.

Let me know , because now this is another new issue i think we will face.

I just want to know if its just my particular TV or this issue is in general affecting all m1/m2 mac minis.

@GetVladimir
Copy link
Author

@traderdude123 Yes, of course. I have an USB-C to DisplayPort connection and also HDMI-to-HDMI connection.

I can confirm that both of these connections output the same when using RGB color output on my monitor.

On my TV, I can test only HDMI-to-HDMI, but I don't have any USB-C to HDMI adapters, and the TV only accepts HDMI.

My guess is the adapter might be causing the discrepancy.

At the moment, I can't test 10-bit on my Monitor, as neither the Monitor or the M1 Mac mini HDMI port supports it.

@traderdude123
Copy link

traderdude123 commented Apr 15, 2023

@GetVladimir

I got RGB 10b 4k over hdmi-hdmi.

This is another alternate way of getting there. Below are the steps. I almost feel bad for dev of BD.Below method is for users whos trial has expired for BD and do not want to pay for the license.

  1. Create a new user ( this is going to be temporary)
  2. Install BetterDisplay, you should now get 14-day trial.
  3. Extract EDID using BD.
  4. Install AW Editor to modify EDID.
  5. Edit the EDID using AW Editor and remove all references to YCBCR and make EDID version 4.
  6. Upload the EDID using BetterDisplay. Steps 3-6 can be skipped if you already have a modified EDID and ready to upload.
  7. Now you should get RGB 10b for all users on your system.
  8. Switch to Original user, it should now have RGB. Reboot and login to original user to verify you have RGB 10b.
  9. Delete the temporary created user.
  10. Done.

Note: Do not go into sleep , you might lose RGB.

Coming back to RGB vs YCBCR differences.

The macOS is sending RGB Full(high) by default to the TV. if the TV is set to Auto black level it will set black level to high.This confirms that macOS is sending RGB Full and not Limited. Which is correct and this can be verified on lagom test Black levels page. I will refer to RGB Full as RGB High and RGB Limited as RGB Low.

In the lagom Black level test ,if RGB Low is set on TV, you can see that 1-15 Blacks will be too dark to see and that is correct. if you are seeing greys or even visible dark , then your monitor needs calibration.if RGB full is set on TV, you can and should see all blacks from 1-15.

However , Limited RGB(low) can give deeper blacks and better contrast and some users may prefer this.One use case for this is Coding on OLED Monitors/TV. for e.g. i do coding on Xcode and RGB limited(low) is much better as everything is deep dark on OLEDs. Also images looks better due to better contrast.

But when consuming videos , Limited RGB will make dark scenes very dark and Full RGB or better yet YCBCR444 is the best. you can compare this by running a video on your browser and check all three options 1. RGB High 2.RGB Low 3. YCBCR444. You can then choose your preference.

Edit: In summary , the weird thing is with Full RGB as source(macOS) and TV set to RGB Low, we lose the black and white details as they get crushed, but what we lose in some black/white details , we gain in color vibrancy and deeper blacks which some may enjoy for certain use cases. This is more so suitable for an OLED display. Please test and let me know what you all prefer. Another benefit is the text clarity is somewhat improved on RGB Low compared to RGB high/Full.

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