Forcing RGB mode on a monitor connected via HDMI in macOS

boring apple

Photo by Mitchell Y.

I recently bought myself a new monitor and discovered an annoying issue that affects all macOS users. If the monitor claims to support both colour spaces RGB and YCbCr , macOS always uses the latter, and it is impossible to change this behaviour in the system preferences. On some monitors, this problem manifests itself more strongly. On some, it is not at all noticeable. This problem exists when connecting either via HDMI or via DisplayPort .

How do you know that your monitor is operating in YCbCr colour space?

Some monitors directly indicate what colour space they are using in the OSD (On-screen display). On Dell monitors, for example, one can find this information in Color Settings -> Input Color Format.

My monitor does not show this information, but it automatically switches the black level based on the colour space in use. If it receives an RGB signal, it sets the black level to High, if YCbCr – to Low.

Sometimes you can understand that non-RGB colour space is used by the quality of the picture. Typical signs:

What’s wrong with YCbCr?

A screen image (framebuffer ) is stored on your computer as a set of pixels in the RGB format: three n-bit (most often 8-bit) numbers, one for red, green and blue components. A monitor is made up of pixels, divided into three sub-pixels: red, green, and blue. So, the monitor needs this RGB data to display the picture.

The YCbCr format replaces the luminance values of the red, green, and blue components with three other numbers: pixel luminance and two chromatic components. This colour space is used to reduce the load on the data transmission channel since the human eye is much more susceptible to changes in brightness than to changes in colour, and therefore both chromatic components in a YCbCr signal can be compressed with loss without losing much in perceived picture quality.

Picture from the Wikipedia article

Naturally, this reasoning is utterly inappropriate for the case when we connect a monitor to a MacBook at home with an HDMI cable with a bandwidth of 40 gigabits per second. MacOS, however, whenever possible, prefers the YCbCr colour space.

This often results in distorted and washed-out colours, washed-out blacks, difficulties adjusting the image, coloured pixels around letters, and loss of the picture sharpness. Of course, the severity of the effects will depend on the monitor - on some monitors the picture will be much worse than in RGB mode, but on some monitors, it will be almost indistinguishable.

So what can you do?

Fortunately, macOS has a mechanism that allows fixing this mess: the ability to override the EDID of the monitor. EDID stands for Extended Display Identification Data . EDID is a piece of information that the monitor transmits to the operating system telling it about the colour spaces it supports, modes of operation, audio formats, colour profiles, and much more.

Here I will not describe the structure and specification of EDID as I did not fully understand it and it is very well explained on Wikipedia.
I will only list the specific instructions on making macOS think that your monitor only supports RGB colour space.

So, there is a solution that has been written about many times on the Internet – a Ruby script by Andrew Daugherity . The script does its job, but at the same time deletes from EDID all sections except the main one, which leads to the loss of many monitor capabilities.

For example, if I use this script without any modifications, my 1440p monitor loses the ability to work in modes above 1080p, which, of course, is unacceptable.

Therefore, we will start by using this script, and if the result does not suit you, we will dive a little deeper, modifying EDID manually. It is desirable to have a Windows machine for best results, but in theory, you can do everything without it.

So let’s go.

Step-by-step instruction

1. Download and run the original script

With an external monitor connected, download and run the script by Andrew Daugherity (I forked it to make sure it will not change).

The script performs four steps:

The directory and file name depends on the manufacturer and model of your monitor. For example, in my case it is the DisplayVendorID-1e6d/DisplayProductID-5b80. The file is a plain text plist.

<plist version="1.0">
<dict>
  <key>DisplayProductName</key>
  <string>LG ULTRAGEAR - forced RGB mode (EDID override)</string>
  <key>IODisplayEDID</key>
  <data>AP///////wAebYBbNtMDAAkeAQOAPCJ44oy1r09DqyYOUFQlSwBxQIGAgcCp
wLMA0cCBANHPWqAAoKCgRlAwIDoAVVAhAAAaAAAA/QAwkB7mPAAKICAgICAg
AAAA/ABMRyBVTFRSQUdFQVIKAAAA/wAwMDlOVFNVN0M2NzgKAO8=
</data>
  <key>DisplayVendorID</key>
  <integer>7789</integer>
  <key>DisplayProductID</key>
  <integer>23424</integer>
</dict>
</plist>

The most important part is the data field. It contains modified EDID encoded in base64 .

2. Install modified EDID

The resulting directory must be copied to the directory /Library/Displays/Contents/Resources/Overrides. Create intermediate directories if necessary.

3. Reboot

Restart your computer and check the result. If the monitor goes into RGB mode and nothing breaks, congratulations, nothing else is required, and you can safely close this article.

If something breaks, remove the override, restart your computer again and go to the next step.

4. Modifying EDID manually

Now we need some EDID editor. I used the Advantiv EDID Editor , as it was the only one I tried to recognize all the additional sections of the file generated by my monitor. Unfortunately, it is only available for Windows, so I had to use a virtual machine.

You can use any other EDID editor of your choice.

The first step is to save EDID to the binary file. I used Hex Fiend for this.

The command ioreg -l -d0 -w 0 -r -c AppleDisplay will output EDIDs of the connected external monitors. We are interested in the string "IODisplayEDID"= <...>, where instead of an ellipsis there will be a long hex sequence, which must be inserted into Hex Fiend and saved as edid.bin.

In Advantiv EDID Editor, to open a binary file, you need to use File -> Import -> Binary. After import, all sections and subsections in the file will become visible on the left, and fields for each subsection will be available for editing on the right.

It is necessary to change the values of the following fields:

Now you can export the file (File -> Export -> Binary) to edid-edited.bin.

5. Replacing EDID in the plist file

Now you need to encode the modified binary file to the base64 encoding and replace the <data> section in the file generated on the first step.

For encoding file to the base64, I used the following script:

#!/usr/bin/ruby

require 'base64'

File.open(ARGV[0], 'rb') { |f| puts Base64.encode64(f.read) }

6. Replace the file and reboot

So, the only thing left is to repeat steps 2 and 3. If this does not work, you can try deleting CEA sections one by one, except the CEA -> Video -> SVD, checking if that worked.