How to drive high-resolution displays

I’ve recently become in possession of a 4K (3840 pixels x 2160 pixels) 144Hz monitor to bask in the high DPI glory and to never be looking at poorly aliased fonts ever again. In my head all that I needed to worry about is if my GPU will be able to push these many pixels and if the monitor actually arrived. But when it did arrive another problem was born, with my RTX 3060 graphics card I was only able to set the resolution to 4K @ 60Hz using my trusty HDMI cable and switching it to the one it came in the box didn’t change anything. In the process of solving this problem a rat hole opened up that I got swallowed by but after leaving it there is some information that is worth sharing.

Some basic information, the monitor in question is LG 27GN950 its specs can be found here, the most important information for later are the actual connectors on the back of the monitor: HDMI2.0 and DisplayPort 1.4. Now we need to calculate two simple numbers that will help me explain what the problem even is and both of those numbers are bandwidth. According to Wikipedia:

bandwidth is the maximum rate of data transfer across a given path

It’s obvious right? In order for the monitor to display anything it needs data to display, graphics programmer would describe this data as a frame buffer. This frame buffer has a size to it and it needs to be sent to the monitor at a certain frequency with updated information. If we know the resolution and the refresh rate we know everything*. The frame buffer is going to be a two dimensional array of pixel color values, each of them is going to be 24 bits (8 bit per channel x 3 channels) and the size of each array dimensions is horizontal pixel count and vertical pixel count. This information needs to be sent to the monitor the same amount of times as the number declaring the monitor’s refresh rate. Finally, let’s compute the two values I mentioned above and other ones that will become useful later:

Bandwidth for 4K @ 144Hz = 3840 * 2160 * 24 * 144 = 28.66 GB/s
Bandwidth for 4K @ 120Hz = 3840 * 2160 * 24 * 120 = 23.88 GB/s
Bandwidth for 4K @ 60Hz = 3840 * 2160 * 24 * 60 = 11.94 GB/s
Bandwidth for 4K @ 30Hz = 3840 * 2160 * 24 * 30 = 5.97 GB/s

Wow, okay, we need to be able to send 12 GB of data every second to the monitor to even get 60Hz refresh rate at 4K and a staggering 28.5 GB of data (which is more data then I have RAM in my system) every second to get 144Hz. Let’s bring the most important table in all of this blog post, the maximum bandwidth for each video connector standard as provided by Wikipedia

Standard Maximum Bandwidth
HDMI 1.0 - 1.2a 4.95 Gbit/s
HDMI 1.3 - 1.4b 10.20 Gbit/s
HDMI 2.0 - 2.0b 18.00 Gbit/s
HDMI 2.1 - 2.1a 48.00 Gbit/s
DisplayPort 1.0 - 1.1a 10.80 Gbit/s
DisplayPort 1.2 - 1.2a 21.60 Gbit/s
DisplayPort 1.3 - 1.4a 32.40 Gbit/s
DisplayPort 2.0 - 2.1 80.00 Gbit/s

The game is simple, if the maximum bandwidth for a given standard is higher then the actual bandwidth that we calculated we are allowed to set a given resolution with a given refresh rate. Like I mentioned above, the monitor has HDMI 2.0 port, and looking at the maximum bandwidth of that port we can see that it’s 18 GB/s so it will work with the refresh rate of 60Hz but it’s not able to do 144Hz since it not able to send 28 GB/s. But see, I’m lying to you, just like everybody else when they say that DisplayPort(DP) 2.0 is 80 GB/s. There is an additional step, the reason for that is it’s not the actual data bandwidth, only the signaling bandwidth, let me introduce the big boy table.

Standard Maximum Bandwidth Encoding Scheme Actual data bandwidth
HDMI 1.0 - 1.2a 4.95 Gbit/s TDMS 3.96 Gbit/s
HDMI 1.3 - 1.4b 10.20 Gbit/s TDMS 8.16 Gbit/s
HDMI 2.0 - 2.0b 18.00 Gbit/s TDMS 14.40 Gbit/s
HDMI 2.1 - 2.1a 48.00 Gbit/s 16b/18b 42.00 Gbit/s
DisplayPort 1.0 - 1.1a 10.80 Gbit/s 8b/10b 8.64 Gbit/s
DisplayPort 1.2 - 1.2a 21.60 Gbit/s 8b/10b 17.28 Gbit/s
DisplayPort 1.3 - 1.4a 32.40 Gbit/s 8b/10b 25.92 Gbit/s
DisplayPort 2.0 - 2.1 80.00 Gbit/s 128b/132b 77.37 Gbit/s

Before you get scared I’ll explain everything. The Maximum Bandwidth column shows the specification limit for the amount of actual bits sent and received in a second over the wire. If you were to middle man this connection and dump literal bit values you would see garbage and the amount of data would be too big. The reason for that is clock sync, in order for any listener to have a synchronized clock with the sender in any digital communication channel we need to meddle with the data. Let’s say that the source sends you 100 zeroes in a row, because the destination can not guarantee that it’s clock didn’t drift, it is possible for the receiver to decode 99 zeroes or 101 zeroes - in other words: bad times. In order to synchronize the clocks there needs to be a change eventually from zero to one or from one to zero, let’s say that we built a clock that we are confident in, and it is going to correctly decode 3 unchanging bits. Great, but we still want to send all zeroes sometimes so how do we do it? Let’s send for example 8 bits of information but encode it using a mapping to a 10 bit value, since we have more bits we can choose values that do not have long runs of unchanging values. So after we send those 10 bits the actual information stored in those 10 bits is only 8 bits, now you might start to suspect something because there is some inefficiency. In the table we can see many so called schemes denoted as mb/nb where n > m, our example could we written down as 8b/10b, so 8 bits encoded as 10 bits. Okay, but what does that mean? It means that the values we calculated before are the required bandwidth of data or in other words it’s the amount of data we need to send. But each scheme is sending more data over the wire then the data we asked it to send. Because of that to do the actual comparison we check if the maximum signaling bandwidth times the efficiency of the encoding scheme is greater then the required data bandwidth! The actual maximum number of data that can be sent is stored in the last column, the one we care about. No more lies, I promise.

Building on that we can see the following: the monitor uses HDMI 2.0 and over that interface only 14.4 GB/s of data can be sent. Inferring from that, only 4K @ 60Hz is going to work and we would need another 15 GB/s of data bandwidth to make 4K @ 144Hz work. We have two options, either somehow install an HDMI2.1 module in the monitor or switch over to DP. Right now you might be panicking as was I when the realization came, my laptop does not have a DP port, what it does have is two USB-C ports. But wait, my work provides me with a USB-C docking station, more precisely a ThinkPad USB-C Dock Gen 2, it’s not Thunderbolt enabled which I knew because my Ryzen equipped laptop somehow managed to drive a Full HD display at 60Hz without any problems. It would be really stupid to add two display ports to a docking station if it somehow wasn’t able to send a DP signal over that USB-C interface (I’m not going to comment how DisplayLink is the worst tech ever). Enter DisplayPort Alternate Mode (DP-AltMode), since the pin out for a USB-C plug and a DP plug is very similar, we can send a video signal over a USB-C wire, that’s how monitors work via USB-C, they do not, they communicate using DP protocol over a USB-C interface. There is some specifics that I’m not going into for brevity and because it’s really boring. Lo and behold if we read into the specification of that docking station we can see that it supports DP-AltMode, so now we know how the dock is able to drive this Full HD display through that dock. What’s even better is the fact that the specification for the dock says “DisplayPort 1.4”, so my reaction was “USB-C ALL THE THINGS AT ONCE, 4K @ 144 Hz HERE I COME”. I connect the new monitor to the dock and I get the ability to run only at 4K @ 60Hz with my personal laptop, my work laptop that I only wanted to push 4K @ 60Hz is only able to do 4K @ 30Hz. There is a problem somewhere in the chain.

Let’s go deeper into DisplayPort and focus on my personal laptop, the DisplayPort standard that my graphics card supports is version 1.4. As I’ve shown, that version is able to achieve theoretical maximum data bandwidth of almost 26 GB/s which is not quite 144Hz but 120Hz is fitting into that range so let’s choose that as our current goal. That data bandwidth has another asterisk on it, is the sum of all maximum of four lanes working in transmission mode called High Bit Rate 3 (HBR3). Two new things appear, lanes and transmission modes. The latter is easy to explain, it’s basically the speed at which data is going to be sent over a lane, just internalize this: the maximum data bandwidth is divided by four and that’s the transmission’s mode maximum bandwidth - nothing new, just fragmentation. A lane on the other hand is the actual pair of differential cables that is going to carry that signal, just like in Ethernet cables, in each DisplayPort cable are 4 lanes which are carried by 8 actual physical wires. Now, remember when I said that USB-C is very similar to DisplayPort? It also has only four high speed differential pairs (there is a fifth differential pair, but it’s not high speed and it’s mainly used for USB2.0). Well, that dock has other ports on it apart from DisplayPort, like USB3.0 interfaces - those have to use high speed lanes to fulfil the specification on being able to send 5 GB/s. I’m highly certain that what happens is only two lanes are actually allocated to DisplayPort and the rest is used for USB3.0. That happens even if zero things are connected to any of the USB ports present on the dock. We can calculate if I’m right

Personal laptop with DP 1.4: (26 GB/s / 4 lanes) * 2 lanes = 13 GB/s
Work laptop with DP 1.2: (17 GB/s / 4 lanes) * 2 lanes = 8.5 GB/s

Everything works out perfectly, 13 GB/s is enough for 4K @ 60Hz which needs 12 GB/s and 8.5 GB/s is enough for 4K @ 30Hz which needs 6 GB/s. So until someone from Lenovo can confirm that, it’s only a theory but a working theory with the population n = 2. Going back to trying to run the display at 120Hz, what can be done? We need four lanes, and in order to get them we need a cable USB-C <-> DisplayPort, I bought this one. After plugging the DisplayPort into the monitor and USB-C directly into my personal computer I get the ability to run 4K @ 120Hz and my work laptop now supports 4K @ 60Hz. Great success!

Now what about that 144Hz that I mentioned? In theory and in practice there is not enough bandwidth for that to happen, we would have to reduce the amount of data we send over the wire. Reduction of data size is commonly known as compression and DisplayPort version 1.4 introduces Display Stream Compression (DSC). It’s a visually lossless (meaning you cannot perceive the difference between compressed and uncompressed) algorithm that has to be supported by your graphics card in order to work. It has a ratio of compression equal to 3:1, meaning we only send 8 bits per pixel instead of 24 bits. Every calculation we did before is now trivial to expand and determine the maximum supported refresh rate at a given resolution. For example using DisplayPort version 1.4, we can maximally squeeze 4K @ 120Hz, multiply it by 3 and we get 4K @ 360Hz which is bananas! If you want to read up on the specifics check out the actual spec. Now there might be a question in the minds of some of the people in the reading audience that goes something like: “Why didn’t DSC work over the docking station?”. That is a great question, and I have the answer right here: I don’t know. The best I can do is speculate and presume that it’s something to do with the firmware of the docking station itself. I’ve asked Lenovo and if they answer I’ll let you know. For now, I’m happy that I got what I wanted from the beginning which is 4K @ 144Hz.

[*] We also need to know how many bits are used to represent a single pixel, in 98% of cases it’s 8 bits per channel or 24 bits per pixel. This number increases as we dive into HDR land where it’s common to see 10 or 12 bits per channel which is 30 and 36 bits per pixel respectively. If you want other “bit depths” as they’re called, just substitute 24 to the number of bits that will represent your pixel in the following calculations.