Skip to content

Instantly share code, notes, and snippets.

@adaugherity
Forked from BugRoger/patch-edid.rb
Last active September 3, 2024 02:34
Show Gist options
  • Save adaugherity/7435890 to your computer and use it in GitHub Desktop.
Save adaugherity/7435890 to your computer and use it in GitHub Desktop.
#!/usr/bin/ruby
# Create display override file to force Mac OS X to use RGB mode for Display
# see http://embdev.net/topic/284710
require 'base64'
data=`ioreg -l -d0 -w 0 -r -c AppleDisplay`
edids=data.scan(/IODisplayEDID.*?<([a-z0-9]+)>/i).flatten
vendorids=data.scan(/DisplayVendorID.*?([0-9]+)/i).flatten
productids=data.scan(/DisplayProductID.*?([0-9]+)/i).flatten
displays = []
edids.each_with_index do |edid, i|
disp = { "edid_hex"=>edid, "vendorid"=>vendorids[i].to_i, "productid"=>productids[i].to_i }
displays.push(disp)
end
# Process all displays
if displays.length > 1
puts "Found %d displays! You should only install the override file for the one which" % displays.length
puts "is giving you problems.","\n"
elsif displays.length == 0
puts "No display data found! Are any external displays connected?"
puts "\nNote: Apple Silicon (arm64) devices are currently unsupported, as the standard"
puts "method of retrieving display information does not work."
end
displays.each do |disp|
# Retrieve monitor model from EDID display descriptor
i = disp["edid_hex"].index('000000fc00')
if i.nil?
monitor_name = "Display"
else
# The monitor name is stored in (up to) 13 bytes of text following 00 00 00 fc 00.
# If the name is shorter than 13 bytes, it is terminated with a newline (0a) and then padded with spaces.
monitor_name = [disp["edid_hex"][i + 10, 26].to_s].pack("H*")
monitor_name.rstrip! # remove trailing newline/spaces
end
puts "Found display '#{monitor_name}': vendor ID=#{disp["vendorid"]} (0x%x), product ID=#{disp["productid"]} (0x%x)" %
[disp["vendorid"], disp["productid"]]
puts "Raw EDID data:\n#{disp["edid_hex"]}"
bytes=disp["edid_hex"].scan(/../).map{|x|Integer("0x#{x}")}.flatten
puts "Setting color support to RGB 4:4:4 only"
bytes[24] &= ~(0b11000)
puts "Number of extension blocks: #{bytes[126]}"
puts "removing extension block"
bytes = bytes[0..127]
bytes[126] = 0
bytes[127] = (0x100-(bytes[0..126].reduce(:+) % 256)) % 256
puts
puts "Recalculated checksum: 0x%x" % bytes[127]
puts "new EDID:\n#{bytes.map{|b|"%02X"%b}.join}"
Dir.mkdir("DisplayVendorID-%x" % disp["vendorid"]) rescue nil
filename = "DisplayVendorID-%x/DisplayProductID-%x" % [disp["vendorid"], disp["productid"]]
puts "Output file: #{Dir.pwd}/#{filename}"
f = File.open(filename, 'w')
f.write '<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">'
f.write "
<dict>
<key>DisplayProductName</key>
<string>#{monitor_name} - forced RGB mode (EDID override)</string>
<key>IODisplayEDID</key>
<data>#{Base64.encode64(bytes.pack('C*'))}</data>
<key>DisplayVendorID</key>
<integer>#{disp["vendorid"]}</integer>
<key>DisplayProductID</key>
<integer>#{disp["productid"]}</integer>
</dict>
</plist>"
f.close
puts "\n"
end # displays.each
@hagarj
Copy link

hagarj commented Feb 10, 2022

It has to be possible somehow to get MacOS to do chroma 4:4:4 with this display. I dug out one of these:

https://www.startech.com/en-us/cards-adapters/dk30a2dh

And connected the TV to it, and now I get "mostly" clear text. It's a little soft but drastically improved. Somehow I'm still stuck with 30Hz though. The dock supports 4k@60Hz so I'm quite puzzled why I'm stuck here with 30Hz. I removed the display override and unplugged/replugged in the dock, still stuck with 30 HZ.

@GetVladimir
Copy link

GetVladimir commented Feb 10, 2022

@hagarj not a problem, glad if it helps.

I meant don't use any adapters/docks/hubs when connecting your TV. Macs don't have good support for them, and this might be what's causing the issue.

If possible, use a simple USB-C to HDMI cable to connect your TV

@hagarj
Copy link

hagarj commented Feb 10, 2022

@GetVladimir That's an interesting thought. When I looked into it, HDMI themselves say HDMI Alt Mode isn't here yet:

https://www.hdmi.org/spec/typec

We'd need HDMI Alt Mode to get a direct connection to the display without an active adapter in the middle. Comparing to an Amazon HDMI to USB-C cable:

https://www.amazon.com/uni-Thunderbolt-Compatible-MacBook-Surface/dp/B075V5JK36

This says it still only works with DisplayPort Alt Mode enabled devices, so it's still an active conversion cable. Also hence why it has advertising for heat dissipation since there's a converter chip inside the cable somewhere.

I agree the support here is poor from Apple. I'll keep "plugging away" at it haha for a bit more before giving up.

@GetVladimir
Copy link

GetVladimir commented Feb 10, 2022

@hagarj Indeed, it's still an active conversion. You will need to look into an USB-C to DisplayPort cable otherwise, but your TV can't accept that input.

The benefit is that cables which are specifically designed to do the function of converting USB-C to HDMI have a much better chance to work properly.

Compared to docks which have multiple ports, they have a lot more things to worry about and the main priority becomes to output an image. They usually can't test too much whether that image is 4:2:2 or 4:4:4 with a specific TV, and it's ok for them as long as it works.

@hanoii
Copy link

hanoii commented Mar 23, 2022

Hi All, I got myself a new Dell s2721dgf monitor mostly for coding, I am coming from an P2715Q (4 years old) that worked perfectly. The former is 2k@165hz and the later is 4k@60k. I am having bad looking text.. The resolution I use is 2k for both monitors but on this new one the text looks bad... it is a bit blurry. The color format reported on the display is RGB, but I don't understand the odd looking text vs my 4k display (at 2k), it's a huge noticeable difference. Is anything in here that you think might help?

@GetVladimir
Copy link

@hanoii If the monitor already outputs RGB color and the text still doesn't look sharp, the options are a bit limited on what you can do to improve it.

First, make sure you're on the latest version on macOS 12.3, since older versions are know to have blurry text issues (which aren't fully resolved yet).

Second, make a backup and delete any displays plist files in /Library/Preferences/ that might be leftover from the older monitor.

Finally, if nothing else works, you can look into apps that create a fake second monitor that allows you to set HiDPI resolution on your current monitor. Something like this for example: https://github.com/waydabber/BetterDummy

@hanoii
Copy link

hanoii commented Mar 23, 2022

@GetVladimir thanks! I was trying BetterDummy but couldn't make it a difference. I wonder if I am just asking something that's not possible, so maybe you can share some advise there. Based on my previous comment I am having a second monitor for a second setup at home. I use my 4k P2715Q at 2560x1440 resolution which is my sweet spot of real estate and test size.

I now got my DELL D2721DGF which is 2K (2560x1440) but was looking for a different experience in terms of refresh rates. I expected the text to look just as good, but it's not. It's not super blurry, just kind of oldschool looking and not what I'd expect to be.

As for BetterDummy I am not sure what combinations of resolutions I should be using, but I always end up looking at the display as if there was no dummy on top. I didn't see any plist files, but will double check.

EDIT: NOTE that this is a 2017 MBP

@GetVladimir
Copy link

GetVladimir commented Mar 23, 2022

@hanoii thank you for the additional details.

From what you explained, the 4K monitor seems that it's actually running in HiDPI mode. This means that it uses its native 4K resolution, but macOS makes it zoomed in like it's on 1440p regarding the size.

If you go to System Preferences > Displays and click on "Scaled" and they select "Show all resolutions", you might see some entries showing as (low resolution) next to them.

My guess is that the 4K P2715Q is running at 2560x1440 HiDPI mode, while the D2721DFG is running at 2560x1440 (low resolution) mode.

There is a good explanation on HiDPI if you want to read more about it here: https://www.eizo.com/library/basics/hidpi/

If you don't use an M1 based Mac, you can also try apps such as SwitchResX to generate a custom override file with the display resolutions that you need: https://www.madrau.com/support/support/faq_files/ns_How_can_I_define_a_new_HiDPI_re.html

Let us know how it goes.

@hanoii
Copy link

hanoii commented Mar 23, 2022

@GetVladimir great info, thanks. I am also close to having a new M1 based MBP. So do you think I should be able to to run 2560x1440 at HiDPI mode on my new monitor and get the same text sharpness as with the 4k monitor at the same resolution. If so, how :)? I will read on all of that.

EDIT: Also, should I bi able to run hiDPI mode on the new monitor at 2560x1440 even though the pixel density is not as high?

@GetVladimir
Copy link

@hanoii No, actually the support for HiDPI on M1 based Macs is even more restricted, and the workarounds that worked on older x86 Macs for HiDPI no longer work on M1.

The limitation seems to be intentional. You can also read more details about it here: https://www.madrau.com/support/support/faq_files/ns_Why_isnt_there_any_HiDPI_resolu.html

@the1010boy
Copy link

I applied this workaround / mod ...and yet, the image & text on my Dell U3014 still look "scratchy" and harsh on the eyes.

Screen Shot 2022-04-04 at 2 42 56 PM

I have a Mac Pro 5,1 running Mojave (10.14.6).

Screen Shot 2022-04-04 at 3 56 14 PM

Interestingly enough, when I replace the HDMI 2.0b HDCP 2.2 compatible HDIM cable with a DisplayPort cable the image looks GREAT! just as I would expect it too. However, because I'm driving 3 displays (all Dell U3014) at once I have to use HDMI for one of the monitors since my graphics card (Saphire Radeon RX580) only has 2x DisplayPort outputs. And it's the always the monitor connected to the HDMI cable that has the "scratchy" rendering.

Screen Shot 2022-04-04 at 3 56 00 PM

FYI, I had this working successfully for 4 years before I needed to rebuild my machine (reinstall the OS anew) and I forgot to take notes of how I got it all working last time (or I forgot where I put my notes 😅). ...and so far all my searches on the interweb haven't lead me to a solution that resolves this issue for me. So any help I could get would be greatly appreciated.

Lastly, as this might not be the right place to ask for such help let me know & I'll delete my post, as I know this goes beyond what this code is intended to do.

Also, for what it's worth, here's the contents of the "override file" this script created for me that I am using. At the time I ran the script to generate this file, I had only 1 dell monitor connected via HDMI.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>DisplayProductName</key>
  <string>DELL U3014 - forced RGB mode (EDID override)</string>
  <key>IODisplayEDID</key>
  <data>AP///////wAQrINATDYwMgkYAQOAQCh44h31rk81syUNUFSlSwCBALMA0QBx
T6lAgYDRwAEB4mgAoKBALmAwIDYAgZEhAAAaAAAA/wBQMVY2TjQyUDIwNkwK
AAAA/ABERUxMIFUzMDE0CiAgAAAA/QAxVh1xHAAKICAgICAgAHg=
</data>
  <key>DisplayVendorID</key>
  <integer>4268</integer>
  <key>DisplayProductID</key>
  <integer>16515</integer>
</dict>
</plist>

@mfaughn
Copy link

mfaughn commented Apr 13, 2022

I've got something working on an M1 Mac. I'm not messing with RGB settings but I have been able to use a (rather sloppy) modification of the script to semi-successfully alter the name of the display as it is displayed in the MacOS 15.3.1 System Settings for displays. I really wanted it renamed in the Sound settings, which it sadly doesn't do. I'm using two Dell U3023e monitors and there is no way to distinguish which one to select for my sound output. I don't know much about plist files. Maybe there is a way to do conditionals in them or something?

Also referenced this to know where to put the generated files.

@GetVladimir
Copy link

@mfaughn Thank you for creating the modification and for sharing it. Every little bit helps.

This is useful to generate the correct displays override file on M1 based Macs, even if the EDID override doesn't work.

Perhaps this script can be used to add the DisplayIsTV key in the override file:

<key>DisplayIsTV</key>
<false/>

So that the generated example file looks something like this:

<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>DisplayProductName</key>
  <string>DELL U2415 (RGB)</string>
  <key>DisplayIsTV</key>
  <false/>
  <key>IODisplayEDID</key>
  <data>AP///////wAQrLigTEY0MCUYAQSlNCB4IgSVqVVNnSYQUFSlSwBxT4GAqUDR
wNEAAQEBAQEBKDyAoHCwI0AwIDYABkQhAAAeAAAA/wAwOERYRDQ5NzA0RkwK
AAAA/ABERUxMIFUyNDE1CiAgAAAA/QAxPR5TEQAKICAgICAgAGo=
</data>
  <key>DisplayVendorID</key>
  <integer>4268</integer>
  <key>DisplayProductID</key>
  <integer>41144</integer>
</dict>
</plist>

This seems to help some M1 Macs that incorrectly detect the monitor as a TV. However, more testing with more models is needed in order to confirm that the DisplayIsTV still makes a difference in those situations.

@nvcken
Copy link

nvcken commented Apr 14, 2022

Hi @GetVladimir
My problem is when connect MacBook Pro M1 to LG TV, the color on LG TV is washed out like very high contrast. I don't get this trouble when connect MBP Intel though.
So this plist would fix for it, is it? and can I know how to use that file plist?
THanks

@nvcken
Copy link

nvcken commented Apr 14, 2022

and does have anyway to revert patch script or overrides?

@mfaughn
Copy link

mfaughn commented Apr 14, 2022

and does have anyway to revert patch script or overrides?

On an M1, just deleting the plist file from /Library/Displays/Contents/Resources/Overrides/ and restarting should revert the patch.

@ibehnam
Copy link

ibehnam commented May 5, 2022

Folks I have a problem. Since ioreg -l | grep "DisplayVendorID" doesn't work on M1 mac, I don't know how to extract the DisplayProductID and DisplayVendorID. I tried using Switchresx which outputs EDID. In the EDID file, I was able to find DisplayProductID, but not the DisplayVendorID. The closest thing I found was Manufacturer ID, which is "SAM" (hex: 4C2D). However, "SAM" is not an integer and I don't know how to insert it in the fake plist file to force HiDPI. Can anyone please help?
image

@GetVladimir
Copy link

@ibehnam perhaps you can check if you can use the script from @mfaughn to help you generate just the DisplayVendorID and DisplayProductID here: https://gist.github.com/adaugherity/7435890?permalink_comment_id=4132166#gistcomment-4132166

@joevt
Copy link

joevt commented May 6, 2022

@ibehnam manufacturer is the vendor ID. 4C2D hex = 19501 decimal
The number comes from using each letter as a 5 bit number ('A' = 1).

vendor=SAM
bytes=$(printf "$vendor" | xxd -p)
echo $(((0x${bytes:0:2} & 31) << 10 | (0x${bytes:2:2} & 31) << 5 | (0x${bytes:4:2} & 31)))

@ibehnam
Copy link

ibehnam commented May 6, 2022

@GetVladimir So I used that script on M1 and unfortunately it didn’t work. After running the script, putting the plist file in the said directory, and restarting, RDM still doesn’t show the HiDPI resolution.

@ibehnam
Copy link

ibehnam commented May 6, 2022

@ibehnam manufacturer is the vendor ID. 4C2D hex = 19501 decimal The number comes from using each letter as a 5 bit number ('A' = 1).

vendor=SAM
bytes=$(printf "$vendor" | xxd -p)
echo $(((0x${bytes:0:2} & 31) << 10 | (0x${bytes:2:2} & 31) << 5 | (0x${bytes:4:2} & 31)))

Oh this is useful! The script also gives the same number 19501, but it’s good to know how it’s calculated.

@ibehnam
Copy link

ibehnam commented May 6, 2022

I’ve seen in comments on other forums that HiDPI is disabled for external monitors. So it seems like futile to even try…

That said, Better Dummy and Switchresx have been helpful.

@aseevlx
Copy link

aseevlx commented May 10, 2022

I used this script to fix color issues on my Xiaomi Mi Curved display (connected to MacBook Pro 15 2018), but it's also removed extension block from original EDID and macOS stuck at the default refresh rate - 50Hz. It was a really painful experience after 100Hz or 144Hz.

I spent several days trying to fix this, and finally found a solution to increase refresh rate and have normal color at the same time.

You need to decode the base64-encoded data string from the patched EDID to binary data, pass that data to AW EDID Editor, add an extension block with desired resolution and refresh rate, then encode that binary to base64 and put it back into patched EDID.

I also wrote a blog post with detailed instructions, but it's only in my native language. Mention me if you need help, I will translate it.

@GetVladimir
Copy link

GetVladimir commented May 10, 2022

@aseevlx This is a pretty awesome solution, thank you for the heads-up and the workaround.

I've found your blog post (hopefully it's the correct one) and used Google Translate for a quick translation: https://blog-aseev-im.translate.goog/nastraivaiem-xiaomi-mi-curved-gaming-monitor-pod-macos/?_x_tr_sl=ru&_x_tr_tl=en&_x_tr_hl=en-US&_x_tr_pto=wapp

This process might be useful for setting other custom resolutions and workarounds too (on x86 based macs). Thanks again for sharing the solution

@xeroxoid
Copy link

@GetVladimir @shageevan awesome solution indeed.
As I was also stuck at 50Hz when using the custom EDID, I gave it a shot, but for some reason the edid.bin can not be read by AW EDID Editor, it said the file is corrupted.

for some reason the decoding did not work correctly (probably because I use a newer Ruby version ruby 2.7.4p191 so I just saved the edid string to a file i.e. base64.txt and run base64 --decode base64.txt > edid.bin instead. That worked and I could then read the file in AW EDID Editor.

All good, RGB mode on and 100Hz over HDMI working! Thanks.

@ibehnam
Copy link

ibehnam commented May 12, 2022

@aseevlx does this method also solve the problem of HIDPI on external monitors?

@aseevlx
Copy link

aseevlx commented May 12, 2022

@ibehnam I don't know about the HiDPI problem, sorry. The resolution of my main display is 3440x1440 and I don't have the problem of blurry fonts. But I think you can try to create another extension block with "supported" resolution in EW EDID Editor, but that's just my thoughts.

@aseevlx
Copy link

aseevlx commented May 12, 2022

@xeroxoid excellent, I'm very glad you also find this useful.

I also tried to decode the data using system base64 lib, but I saw that it cuts off some of the encoded binary data. So the size of the resulting file is also different: 532 bytes for the file created by the ruby script, and 128 bytes for the file resulting from decoding with system base64. So I haven't tested this approach, but it's very interesting that it works too.

@GetVladimir
Copy link

Hey team, just wanted to update you that with macOS 12.4, there seems to be native support for HiDPI on external monitors as well now, without additional modifications:

HiDPI

Source for the news: https://www.reddit.com/r/MacOS/comments/uvsdv8/did_apple_solve_the_hidpi_problem/

Ping @hanoii and @ibehnam who were asking about these issues

@ibehnam
Copy link

ibehnam commented May 24, 2022

Thanks @GetVladimir, this is good news coming from Apple. Although, as the reddit comments mentioned, Apple has only put ≤720p HiDPI resolutions (at least for my 2K monitor with 2560x1440). So, I still use BetterDummy to get by.

There's also a flickering issue with external displays which happens when the M1 mac wakes up from sleep. The solution is to re-plug the HDMI cable, or turn the monitor off and on again.

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