Custom Resolutions on Intel Graphics

The Scenario

You've bought a nifty new laptop with the 945GM chipset, or built a Home Theater PC centered around the X3000 Graphics processor (G965).  Everything's gorgeous... until you try to hook it up to that new flat panel monitor, or to your new plasma TV.  The manual says its native resolution is 1440x900, or 1680x1050, or 1360x768, but those resolutions are not showing up as selectable in Display Properties.  What do you do to unlock the full resolution potential of your monitor ?

This has always been a problem, by the way... in years past, in order to cope with monitor/video card driver mismatches, specialized software such as EnTech's excellent PowerStrip utility had to be used for all graphics cards, especially if you had overscan/underscan issues.  In fact, I still recommend PowerStrip for overscan/underscan, and for people who just don't want to get down and dirty with their system in order to get better support of their monitor.

For those, however, with a little bit of time, or even those who are a little curious what's going on under the hood, I'm throwing together this page.

Which Intel Chipsets will this technique work on?

This trick should work with G35, G33, G31, G965, GM965, 945G/GM, and 915G/GM chipsets which use the 14.25.50 drivers or later.  Other chipsets are probably not supported unless they work with that driver or a newer one.  These should work on both WinXP and Vista; possibly Win2K and others, too, but to my knowledge no one has tried those.

What the heck is an EDID?

An EDID is a VESA data structure.

(What, that wasn't enough information for you?)

VESA is the association which establishes the standards for video monitors.  One of many things VESA has established over the years is an interoperability helper known as the Extended Display Identification Data.  Over VGA, DVI, HDMI, and probably UDI/DisplayPort too, a video driving device (video card, consumer electronics device) can query the monitor to see what it's capable of.  The monitor returns a block of data: the EDID.  A typical one looks like this:

Raw EDID base
00: 00 FF FF FF FF FF FF 00  10 AC 0D 40 51 58 4B 42
10: 2C 0F 01 03 80 26 1F 78  EE 11 45 A4 5A 4A A0 24
20: 14 50 54 A5 4B 00 71 4F  81 80 01 01 01 01 01 01
30: 01 01 01 01 01 01 30 2A  00 98 51 00 2A 40 30 70
40: 13 00 78 2D 11 00 00 1E  00 00 00 FF 00 54 36 31
50: 31 36 35 41 52 42 4B 58  51 0A 00 00 00 FC 00 44
60: 45 4C 4C 20 31 39 30 35  46 50 0A 20 00 00 00 FD
70: 00 38 4C 1E 51 0E 00 0A  20 20 20 20 20 20 00 95

You can get this information by making your video card ask your monitor for it; there are several utilities out there which will do this in Linux or Windows, but for now just take a look at the free-and-quite-useful MonInfo by EnTech.  Execute it with your monitor connected and you will get a load of information back which includes the EDID block.

Most of this information is uninteresting to us-- it includes information such as the standard resolutions/refresh rates the monitor supports, the name of the monitor vendor, what its max and min scan rates are, etc.  It's all in an obscure VESA spec somewhere, though a good deal of data can be found at the standard Wikipedia site for EDID.  What we care about is in one of up to four "Descriptor Blocks" starting at byte 54: in any or e Descriptor Blocks we can find a string of 18 bytes called the DTD, or Detailed Timing Descriptor.  See below for where they are located:

Raw EDID base
00: 00 FF FF FF FF FF FF 00  10 AC 0D 40 51 58 4B 42
10: 2C 0F 01 03 80 26 1F 78  EE 11 45 A4 5A 4A A0 24
20: 14 50 54 A5 4B 00 71 4F  81 80 01 01 01 01 01 01
30: 01 01 01 01 01 01 30 2A  00 98 51 00 2A 40 30 70
40: 13 00 78 2D 11 00 00 1E 00 00 00 FF 00 54 36 31
50: 31 36 35 41 52 42 4B 58  51 0A 00 00 00 FC 00 44
60: 45 4C 4C 20 31 39 30 35  46 50 0A 20 00 00 00 FD
70: 00 38 4C 1E 51 0E 00 0A  20 20 20 20 20 20 00 95

(sorry.  there used to be pretty colors available in the old Wiki.  Now we'll have to go with bold, italic, and underline)

Typically, the DTD is in the first Descriptor Block, but it can be in any of the four.  You can tell if the data is a DTD or not because the first two bytes will be nonzero.  In some cases, there may be more than one DTD listed because the monitor manufacturer has chosen to provide detailed timings for other modes-- possibly because they have an in-line scaler which works best with specific input timings.  Consider all of these for your use, but the most important one for our purposes is the one which matches the native resolution of your display.  In most cases (as in the example given), that will be the only one provided.  If there are more than one, the best way to decide which to use, if you know what your monitor's native resolution is supposed to be, is to do a brief decode of the DTD parameters:

30 2A 00 98 51 00 2A 40 30 70 13 00 78 2D 11 00 00 1E

(note: remember in all these discussions: bytes are numbered from 0, so when I refer to "byte 1", I'm actually talking about "2A" from the above)

In decoding this, byte 2 and the top of byte 4 together tell you the horizontal resolution, in hex:

0x500 = 1280

in this case.  Similarly, byte 5 and the top of byte 7 give you the vertical rez:

0x400 = 1024

So if there's any doubt which DTD we want, you can figure it out from the above.

How does a DTD interact with Intel Graphics drivers?

Driver software, like most other software in Windows, modifies the Windows registry to include various pieces of configuration information the program needs to always be able to find.  When you run setup.exe or whatever executable installs the new software, one thing which occurs is that one or more .INF files are parsed and used to determine which registry entries need to be created and modified.

In the Intel graphics drivers, the .INF files in question are:

XP: igxp32.inf

Vista 32: igdlh.inf

Vista 64: igdlh64.inf

Normally speaking, the Intel drivers seem to provide the standard list of resolutions: 640x480, 1024x768, even some "home theater" resolutions like 1920x1080 and 1280x720.  It's when you get away from the standards and into the more "interesting" panel displays and plasmas that you can't seem to get what you want out of the drivers by default.

Never fear, there is a workaround.  Many of Intel's OEMs (Dell, HP, Gateway, etc.) bundle their machines with monitors with "nonstandard" resolutions; since the drivers are so picky, how do these OEMs guarantee that their customers' machines run the right resolutions to provide the best display to the bundled monitors if Intel's drivers don't support them by default?

In the .inf files described above a mechanism for OEMs to include the DTDs for up to five specific monitor resolutions; this way, they can bundle a "customized" version of the Intel drivers (or provide it on their website) which will definitely support the monitor their customer bought from them (other monitors?  well, you're on your own for that, of course...).  I don't know that any OEM is actually using this mechanism, but it is there.  If these fields are filled, new resolutions miraculously become available.  And this is what we'll use.

How do I get my monitor to display properly?

Hack the .INF file.  You could track down which registry entry the drivers are populating and tweak it directly, too, but I try to stay away from direct registry editing as much as possible.  It's just a personal preference.

Download the latest drivers and extract them to some temporary directory.  Open the appropriate .INF file in a text editor and search for

HKR,, TotalDTDCount, %REG_DWORD%, 0

This registry entry says how many custom resolutions will be available.  As you can see, it's zero.  We don't like that.  Change it to 1 (or, if you're planning on extra resolutions besides the one, change it to 5).

HKR,, TotalDTDCount, %REG_DWORD%, 5

Underneath this is another set of entries:

HKR,, DTD_1,%REG_BINARY%, 01,1D,80,18,71,1C,16,20,58,2C,1A,00,00,00,00,00,00,86,37,01  ;1920x1080@60...Interlaced
HKR,, DTD_2,%REG_BINARY%, 01,1D,80,D0,72,1C,16,20,10,2C,1A,80,00,00,00,00,00,86,37,01  ;1920x1080@50...Interlaced
HKR,, DTD_3,%REG_BINARY%, 01,1D,00,BC,52,D0,1E,20,B8,28,25,40,00,00,00,00,00,04,37,01  ;1280x720@50....Non-interlaced
HKR,, DTD_4,%REG_BINARY%, 01,1D,00,72,51,D0,1E,20,6E,28,25,00,00,00,00,00,00,06,37,01  ;1280x720@60....Non-interlaced 
HKR,, DTD_5,%REG_BINARY%, 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00  ;Fifth DTD

Look familiar?  Perhaps not, but I'll tell you this: the first 18 bytes of each of those entries is a DTD, just like the one you got from the EDID, just comma delimited.  The last two bytes I have no clue about; I just leave them as the default (which, in this case, is 37,01).  Everything after the semicolon is a comment.  Fill in the first one with the EDID information you got from MonInfo (comma delimited) and save the file.  Now run setup.exe in the driver directory to install the Intel drivers.  In this case, your custom DTD should be included in the list of permitted resolutions (you may have to uncheck "Hide modes this monitor cannot display").  Voila!

Or so we hope.  One problem is that sometimes, the monitor manufacturer is full of it.  :)  Or they don't provide a DTD at all, but sometimes the wrong one is worse than none at all because at least when there's no data at all we know why it's not working.

Sometimes the EDID reports a good DTD and we insert it into the .INF file but it doesn't end up in the list of allowed resolutions after we go through the driver install.  This can happen for one of two reasons: the information we put in the .INF is not making it to the registry at all (some kind of setup glitch), or that particular resolution is explicitly prohibited in the VideoBIOS by the motherboard vendor.  I'm not sure why motherboard/laptop vendors would do this, but there's no question they do it, especially in laptops.

Try to check the first possibility by firing up the registry editor regedit (you should be able to do this on XP with Start | Run, typing "regedit" into the dialog box; Vista should be similar, but I'm not clear on specifics).  Once regedit is open, select Edit | Find, and search for "DTD".  Make sure all the DTD entries are the ones you put in the .INF fil to keep hitting F3 (Find Next) until you've exhausted all the DTD possibilities because the DTD data gets copied to several different places in the registry and just because it's right in one place doesn't mean it's right in another.  If the .INF data didn't make it into the registry properly, uninstalling drivers and re-installing ought to help.  If not, I've seen people roll back all the way to the barebones VGA drivers that Microsoft provides by default then reinstall from there because the registry just would not cooperate.

Another possibilty is to search "DTD_1" (if you would change this one in .INF) trough the registry and change manually one by one. Remember to change also TotalDTDCount! A nice job...

If the DTD data is correct in the registry but the resolution is still not available, it's a pretty good bet it's forbidden in the BIOS.  How do we get around this?  We cheat!  The BIOS contains the Mode Removal Table, and it has entries like "1600x1200, 60Hz" and "1400x1000, 50Hz".  But it doesn't say anything about 1592x1200, or 1392x1000, so those are allowed.  (Muahahahaha!  Can you feel the evil power you wield as we bypass this silly restriction?)  Ridiculous, really, and you'll lose 8 pixels on the sides of your screen, but the motherboard/laptop vendors are not known for their quick responses to requests that they change their BIOS for this issue.

So how to do this?  Recall that the DTD contains timing information related to the resolution you want:

30 2A 00 98 51 00 2A 40 30 70 13 00 78 2D 11 00 00 1E

where

0x500 = 1280

If I instead wanted 1272 to get around a restriction in the BIOS, I'd convert the 1272 value to hexadecimal, getting

1272 = 0x4F8

However, we also have to make another slight modification to make this work.  Since we've subtracted 8 pixels from the resolution, we need to add 8 pixels to the horizontal blanking interval (see the next section if you're curious what this is all about) so that the total of them remains the same.

30 2A F8 98 41 00 2A 40 30 70 13 00 78 2D 11 00 00 1E

The horizontal blanking interval is in the same format as the horizontal resolution, and is in bold above.  Thus:

0x198

We need to add 8, which gives us

0x1A0

Thus, we change the DTD to

30 2A F8 A0 41 00 2A 40 30 70 13 00 78 2D 11 00 00 1E

(leave the vertical resolution, in italics, alone)

Then put that in your .INF file and run setup, as explained before.   You won't get 1280x1024 for this example, but you will get 1272x1024.  It's annoying to throw away 8 pixels due to something stupid like this, but it will tide you over until your motherboard or laptop supplier gets around to fixing their VideoBIOS.

No EDID, or "Out of Range"

What if you're not getting an EDID when you run MonInfo?  Or what if you've tried all these techniques, and it's not the graphics driver which is being fussy-- it allows you to try the resolution, but you get a blank screen or an "Out of Range" error from your monitor?  If your monitor has no EDID data, or the data is wrong, your job is much more difficult, but all hope is not lost: you can try to hack one together.

Doing it from scratch: not recommended.  The best way to start is to use a Linux Modeline.  A working one, for your monitor.  Google the model of your monitor and "Modeline".  Unless your monitor is brand new or extremely obscure, it's likely someone, somewhere has used your monitor in Linux and has some usable the form of a Modeline.

A Modeline is the Linux way of specifying the monitor timing information for the X Window system, and it has a slightly different syntax than the DTD, but contains all the same information.  (Okay, most of the same information.)  I'm not going to go crazy with how video works, but we can use a brief digression on monitor timings and what they mean.

There are several parts to a monitor timing setup.  The number of active pixels is obvious; it's the number which can actually be colored during use, and we call it out when we say "1024x768".  That's 1024 pixels per line horizontally, and 768 lines vertically.  But that's not all there is to it.  In addition, there are the "blanking intervals" and the "sync pulse".  Without going into too much detail, the horizonal blanking interval is the time between when one line of active pixels ends and the next one begins.  It's like a carriage return for pixels.  In addition, the sync pulse occurs sometime during the blanking interval to tell the monitor to switch to the next line.  On the vertical side, the blanking interval is the time between screen refreshes (an entire screen is lit with pixels, then the blanking interval occurs, then the screen full of pixels is redrawn), and the sync pulse happens somewhere in there to tell the monitor to start at the top again.  On the horizontal side, the blanking and sync pulse location and width are given in number of pixels, and in the vertical direction it's number of lines.

You'll notice I used very specific terms like "sometime" and "somewhere" to describe where the sync pulses occur; that's because it varies from model to model, as does the width of the pulse, and the blanking interval as well.  All of these values must be specified to a video driving device in order for it to know how to send picture information to the monitor.  A DTD provides all this information, and so does a Modeline.  In order to construct a DTD for use with our Intel driver, we need to find out how to convert a Linux Modeline to DTD data.

Let's look at a Linux Modeline and take it apart:

Modeline................ "1280x1024" 108.000 1280 1328 1440 1688 1024 1025 1028 1066 +hsync +vsync

The quoted part is merely a label, 1280x1024.  Pixel resolution.  Duh.

Next is the pixel clock: 108.00 MHz.  This is essentially the number of pixels which could theoretically be drawn per second on the monitor, if you filled not only the active pixels but the blanking intervals/sync pulses as well.  Of course, we don't do that, but we do have to take those times (and the number of pixels we could be filling those times with) in order to write our timings.  We'll pass it along pretty much unaltered to the DTD (more on that later).

The next four numbers represent the horizontal timings:

1280 1328 1440 1688

First is the familiar number for horizontal active pixels: the number which actually are filled with image.  1280, but we knew that, right?  Second is the start of the sync pulse (1328), third is the end of the sync pulse (1440), and fourth is the end of the blanking interval (1688) before a new line of active pixels starts.

What happens in each horizontal line is that from pixel 1 to pixel 1280 we get picture drawn by the monitor.  After 1280 pixels have been drawn, the monitor doesn't draw anything (you can think of this as it drawing black pixels, if you like) for the next 48 pixels (1328 - 1280 = 48)-- this contains any blackspace you see on the right-hand side of your monitor image area.  At this point, the sync pulse begins: essentially, there is a time which the monitor takes to end one line and start on the next one, and this timeframe is the sync pulse.  Since we know ins and ends (1328 and 1440, repspectively), we know the sync pulse width (1440 - 1328 = 112).  Finally, the monitor draws black pixels again until it gets to 1688, so in this case it draws (1688 - 1440 =) 248-- this contains the blackspace you see on the left hand side of your monitor image area.  Then it starts from active pixel 1 again and repeats over and over and over until it gets to the bottom of the screen.

The key information we need to drive our monitor is: active pixels, length of the blanking interval, sync pulse location, and sync pulse width.  It's all there in the Modeline: active pixels is 1280, blanking interval is the whole shebang from 1281 to 1688, so 408, sync location is 48 pixels offset from the end of active image, and sync pulse width is 112.

hActive = 1280
hBlank = 408
hSync_offset = 48
hSync_width = 112

We've been talking about the horizontal resolution, here, but the vertical parameters are essentially the same (they deal in lines rather than pixels, but that's kind of irrelevant.  For vertical, therefore, using the same math, we get

vActive = 1024
vBlank = 42  (1066 - 1024)
vSync_offset = 1  (1025 - 1024)
vSync_width = 3 (1028 - 1025)

We have what we need, we just need to plug it into the DTD.  Reformatting it is annoying, but not insurmountable.

A good option could be using DTD Calculator, you can download it from Clever Site. Or maybe, use the "manual method":

The DTD first expects the pixel clock in units of 10kHz.  108.00 MHz = 10800 kHz, so that's easy enough.  However, DTD is in hexadecimal, so if you're crappy at dec to dex conversion (as I am) get out your handy-dandy calc.exe (aka Windows Calculator).  You had it in Scientific mode, right?  Make sure you've chosen Decimal, punch in 10800, then click Hex.  The calc window now displays 2A30 (10800 in hexadecimal).  Done, right?  Almost: just to make things interesting, DTD requires this be in reverse byte order, so your first two DTD bytes are

30 2A

Yay!  Progress!  Next, the DTD wants horizontal active pixels and horizontal blanking interval.  These, converted to hex are

hActive = 1280 = 500 (hex)
hBlank = 480 = 198 (hex)

The DTD uses the next three bytes to store these two values, but there are many ways to stuff six digits into three bytes.  Which to use?  It turns out you use the following encoding:

30 2A 00 98 51

It's kind of reverse-byte order, as seen in the pixel clock, but to save space both the top digits of each value are jammed together in the third byte.

Similarly, in the vertical direction we have

vActive = 1024 = 400 (hex)
vBlank = 42 = 02A (hex)

30 2A 00 98 51 00 2A 40

Eight bytes down, ten to go.  Next is the hSync_offset and hSync_width:

hSync_offset = 48 = 030 (hex)
hSync_width = 112 = 070 (hex)

and vSync_offset and vSync_width:

vSync_offset = 1 = 01 (hex) 
vSync_width = 3 = 03 (hex)

This fits into the next four bytes as follows:

30 2A 00 98 51 00 2A 40 30 70 13 00

Notice that while horizontal offset and width use a byte each, vertical offset and width are crammed together in a single byte.  The last byte here is the high 2 bits of horizontal sync offset together with the high 2 bits of horizonal sync width

0000 (bin) = 0 (hex)

for the first digit, the second digit is the  high 2 bits of&n tical sync offset together with the high 2 bits of vertical sync width

0000 (bin) = 0 (hex)

Which is confusing as heck, and so complex that I'm having to use combinations of italics and bold, but luckily the horizontal offset and width are usually <256 and the vertical is <16, so the final byte in this sequence is 00 more often than not.

Zero out the remaining bytes except the last one:

30 2A 00 98 51 00 2A 40 30 70 13 00 00 00 00 00 00

They include data on such things as actual physical size of the display in millimeters and borders, neither of which are used for our purposes.  The final byte relates to interlacing and sync, and is encoded as follows:

The first digit is 1 for progressive displays and 9 for interlaced.
The second digit is as follows for the sync profile:

-hsync -vsync     = 8
+hsync -vsync    = A
-hsync +vsync    = C
+hsync +vsync   = E

In this case, the Modeline is for progressive (as it is by default unless "interlaced" is specifically called out by the Modeline) and tells us the sync is +hsync +vsync, so we go with

1E

making our final DTD value

30 2A 00 98 51 00 2A 40 30 70 13 00 00 00 00 00 00 1E

Whew!  That was annoying.  Thankfully, you shouldn't have to do this again if you've received an honest-to-goodness working Modeline.  Comma delimit the DTD and plug it into your monitor driver .INF file as detailed in the previous section.

If you can't find a working Linux Modeline for your monitor, all hope is not lost, but I highly recommend you get PowerStrip, as mentioned before.  While it is theoretically possible to tweak these settings manually and get a good setup, in my opinion it's way too painful.

Who the heck are you and why are you doing this?

None of your business.  :)

Suffice it to say I am not affiliated with either Intel's chipset team or with EnTech (lest you think I am here to shill either product).  I am a fan of home theater and PCs and have encountered a number of people who have been trying to get their "non-standard" resolution monitor or TV working on an Intel graphics chipset, and since I figured out how to do this I've been letting people know on various forums and trying to help them through the process.  I figured one centralized location for these instructions was best, and this seemed like the right place to do it.

Of course, now that I have, it's entirely possible the Intel chipset software guys will come up with an easier way.  But who in their right mind would complain about that?


Got Questions?

Ask for advice in the User Community for Visual Computing forum (unmoderated).
Categories:
For more complete information about compiler optimizations, see our Optimization Notice.

Comments

Hello,

I deleted my post because I noticed this discussion was too old,
and I moved my post to
http://www.avsforum.com/t/947830/custom-resolution-tool-for-intel-graphics-easier-overscan-correction/1260#post_23796017


Hello everyone.....i buy

Hello everyone.....i buy Windows 8 and I'm Running on Windows 8 and i have a CRT Monitor (higher resolution 1024x768)...... I have some problems to run Metro Apps....please help me to create own resolution.....!!



Hi,
I have laptop with graphics card Mobile intel 4 series express chipset family and using LCD monitor x193w Acer. I have got 1440x900 but the text on screen still little blur.

Does anyone has the driver for win XP or how to solve this problem?

Thanks a lot.

Juani


Thanks a LOT for this post!! I managed to get my Dell Inspiron E1505/6400 working with a Samsung 2033SW screen using the "trick" above. What I don't understand is why you substracted 8 pixels to get around the BIOS restriction? I only substracted 1 (ie. 1599x900).

Thanks again!


To the author: Thank you so much for this incredibly detailed post. I managed to setup my E1405 Dell Inspiron with an Acer X203H at 1592 x 900 resolution (yes, had to use your 'trick' to get around the BIOS!).

Display is so much better now - once again, thanks for the wonderful post and for writing it in such a way that amateurs such as myself can still apply it with a little time and effort.


Hi, I have used this method to get the screen resolutions that I need, however I have the problem that the screen is letterboxing. This isnt a problem on a laptop I have, just with my Q35 Express Chipset. Is there a setting in the .inf file that will allow the image to be stretched or match the monitors viewing pane?

Cheers


Hi, I have Intel 915GM on my Laptop. I want connect it to my Plazma TV who support 1366x768 (WXGA) signal. But I dont have this resolution on my Notebook.

I tried edit igxp32.inf.
I rewrote HKR,, TotalDTDCount, %REG_DWORD%, 5
HKR,, DTD_5,%REG_BINARY%, and i insert "66,21,56,B0,51,00,1B,30,80,82,26,00,00,00,00,00,00,04" code, who i found for this resolution
on other forum. Then i wrote ;1366x768@60 ... I installed it, but when i restart my PC i could not found this Resolution.

Pls, Can anybody help me with it ?


Hi, Kerem!

I think you monitor displays that "Input not supported" because there is wrong screen refresh rate. Are you sure that you set pixel clock correctly? This parameter may be different at different screen resolution. Try to use this parameter from power strip at different screen resolution.
For example than you look this parameter at 1152 x 864 it will be satisfy for refresh rate about 75hz. And than you look pixel clock at 1280 x 720 it will be satisfy for refresh rate about 60hz. You need refresh rate about 60hz.


Hi Smith,
tried it with the correct string yesterday already. Nada : ( . I get a failure notice "Input not supported" . Thanx anyway.


Pages