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.

@490398290
Copy link

@GetVladimir This bug is so nasty, your new method is good but still not persistant. After a while it reverts to Ycbcr when I shut down TV. In combination with EDID patch and plist editing it persists.

@GetVladimir
Copy link
Author

@490398290 Thank you for the update, I appreciate that a lot!

At this point, I'm not sure if it's going to be fixed with a future update of macOS.

Either way, I'm glad to hear that you got it working

@GetVladimir
Copy link
Author

GetVladimir commented Apr 11, 2023

Prototype Color Profile for Reducing Temporal Dithering

I was looking into how to reduce Temporal Dithering on newer Apple Silicon M1 and M2 Macs, since there doesn't seem to be a way to disable it completely.

On my older Mac mini late 2014, there doesn't seem to be any temporal dithering when connecting to my TV or the monitor. I went ahead and extracted the color profile used on it and applied it to the M1 Mac mini connected to a Dell U2415 monitor with HDMI-to-HDMI cable.

From what I can notice on my specific setup, the temporal dithering is reduced, the colors are solid and the gradients are smoother.
Prototype Color Profile

I'm not sure how good is the color accuracy on it, as this is specifically aimed toward reducing the temporal dithering.

If someone else want to test the color profile, you can download it from here:
https://www.getvladimir.com/uploads/1/8/8/4/18841988/reduce_temporal_dithering.icc

To use the color profile:

  1. Copy the Reduce Temporal Dithering.icc file to /Library/ColorSync/Profiles/Displays
  2. Go to System Settings > Displays > Color Profile and select the Sony TV *00 - Forced RGB Mode color profile from the list
  3. Check the colors where you usually notice temporal dithering on your monitor and write a comment if they are reduced or if you have any issues and questions

Update: There doesn't seem to be enough confirmation that the color profile to reduce temporal dithering works for other systems or configurations, so I can't recommend using it

@traderdude123
Copy link

@GetVladimir
Is this temporal dithering required to do if you TV is calibrated using colorimeter?

@GetVladimir
Copy link
Author

GetVladimir commented Apr 12, 2023

@traderdude123 not sure. Easiest way to check would be to try the color profile without changing anything on the monitor/TV itself and see how it works on your specific setup.

The color accuracy will probably not be the same.

You can always switch back to your old color profile if needed though.

@traderdude123
Copy link

@GetVladimir

I tested the temporal dithering icc.

What is observed is that compared to my calibrated icc, the colors are slightly more saturated as a result i m losing detail in images. other than that i don't see much difference.

may i ask how/where you obtained this temporal dithering icc? in colorSync utility it says Apple and mine says X-Rite.

@GetVladimir
Copy link
Author

@traderdude123 thank you so much for testing this and for the info!

Yes, the end result is to reduce temporal dithering on some color gradients. It basically reduces the number of colors in order to reduce temporal dithering.

I've extracted the profile from my old Mac mini late 2014 connected to a TV with RGB color output.

@traderdude123
Copy link

traderdude123 commented Apr 13, 2023

@GetVladimir

Few more important observations.

I just got a kabeldirect USB-C to HDMI 2.1 Adapter cable with the VM700 Chipset. I flashed a firmware(v112) i got on the mac rumors thread and guess what i am now getting RGB mode if i connect usb-c to hdmi 2.1 cable and if i connect the hdmi-hdmi cable i get ycbcr444.

I then compared both outputs to see if there was any difference. Note that macOS creates a new profile if you connect or make new connection via hdmi or usb-c port. I made sure both outputs had my calibrated icc profile. I did a lot of comparison test with colors , images and text.

I could NOT find any difference between RGB and YCBCR444.

What this means that is people need to color calibrate their monitors irrespective of connecting mac to TV/monitor using usb-c or hdmi. The issues in color accuracy came from improper calibration and NOT because of RGB or YCBCR444. Because both signals are digitally same , so the TV or monitor should produce the same output. This is what i m concluding from my observations.

However, do correct me if my methods or observations are wrong. Below the RGB connection WITHOUT EDID modifications using BD.
Also i check the window server plist. No changes whatsoever. The same 7 bitdepth and all other parameters remain same if use both usbc or hdmi connection.

RGB_4k_120hz_downsizsed

@GetVladimir
Copy link
Author

@traderdude123 thanks for the update.

Are you suspicious that the TV doesn't really receive true RGB color and there is no discernible difference with YCbCr because of the adapter in-between?

While it's true that you can calibrate any type of color output in order to improve it, it won't really match as the calibrated RGB colors when accuracy is a must

@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?

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