VESA Video Modes: Difference between revisions

From OSDev.wiki
Jump to navigation Jump to search
[unchecked revision][unchecked revision]
Content added Content deleted
(Add note on return values)
(added source tags)
Line 7: Line 7:
;INT 0x10, AX=0x4F00
;INT 0x10, AX=0x4F00
: Get Controller Info. This is the one that returns the array of all supported video modes.
: Get Controller Info. This is the one that returns the array of all supported video modes.
<source lang="c">
<pre>
struct vbeControllerInfo {
struct vbeControllerInfo {
char signature[4]; // == "VESA"
char signature[4]; // == "VESA"
Line 20: Line 20:
v86_bios(0x10, {ax:0x4f00, es:SEG(vib), di:OFF(vib)}, &out);
v86_bios(0x10, {ax:0x4f00, es:SEG(vib), di:OFF(vib)}, &out);
if (out.ax!=0x004f) die("Something wrong with VBE get info");
if (out.ax!=0x004f) die("Something wrong with VBE get info");
</pre>
</source>


;INT 0x10, AX=0x4F01
;INT 0x10, AX=0x4F01
: Get Mode Info. Call this for each member of the mode array to find out the details of that mode.
: Get Mode Info. Call this for each member of the mode array to find out the details of that mode.


<source lang="c">
<pre>

struct vbeModeInfo {
struct vbeModeInfo {
word attributes;
word attributes;
Line 51: Line 50:
short reserved2;
short reserved2;
};
};
</pre>
</source>


;INT 0x10, AX=0x4F02: Set Video Mode. Call this with the mode number you decide to use.
;INT 0x10, AX=0x4F02: Set Video Mode. Call this with the mode number you decide to use.
Line 63: Line 62:
Here's a sample code, assuming you have a VirtualMonitor already ... Basically, you will scan the 'modes list' referenced by the vbeInfoBlock.videomodes[] and then call 'get mode info' for each mode. You can then compare width, height and colordepth of each mode with the desired one.
Here's a sample code, assuming you have a VirtualMonitor already ... Basically, you will scan the 'modes list' referenced by the vbeInfoBlock.videomodes[] and then call 'get mode info' for each mode. You can then compare width, height and colordepth of each mode with the desired one.


<source lang="c">
<pre>

UInt16 findMode(int x, int y, int d)
UInt16 findMode(int x, int y, int d)
{
{
Line 108: Line 106:
return best;
return best;
}
}
</pre>
</source>


==See Also==
==See Also==

Revision as of 05:08, 10 July 2009

VESA stopped assigning codes for video modes long ago -- instead they standardized a much better solution: you can query the video card for what modes it supports, and query it about the attributes of each mode. In your OS, you can have a function that you call with a desired width, height, and depth, and it returns the video mode number for it (or the closest match). Then, just set that mode

VESA Functions

You'll want to look in the VESA VBE docs for these functions: All VESA functions return 0x4F in AL if they are supported and use AH as a status flag, with 0x00 being success. This means that you should check that AX is 0x004F after each VESA call to see if it succeeded.

INT 0x10, AX=0x4F00
Get Controller Info. This is the one that returns the array of all supported video modes.
struct vbeControllerInfo {
   char signature[4];             // == "VESA"
   short version;                 // == 0x0300 for VBE 3.0
   short oemString[2];            // isa vbeFarPtr
   unsigned char capabilities[4];
   short videomodes[2];           // isa vbeFarPtr
   short totalMemory;             // as # of 64KB blocks
};

vbeInfoBlock *vib = dos_alloc(512);
v86_bios(0x10, {ax:0x4f00, es:SEG(vib), di:OFF(vib)}, &out);
if (out.ax!=0x004f) die("Something wrong with VBE get info");
INT 0x10, AX=0x4F01
Get Mode Info. Call this for each member of the mode array to find out the details of that mode.
struct vbeModeInfo {
  word attributes;
  byte winA,winB;
  word granularity;
  word winsize;
  word segmentA, segmentB;
  VBE_FAR(realFctPtr);
  word pitch; // bytes per scanline

  word Xres, Yres;
  byte Wchar, Ychar, planes, bpp, banks;
  byte memory_model, bank_size, image_pages;
  byte reserved0;

  byte red_mask, red_position;
  byte green_mask, green_position;
  byte blue_mask, blue_position;
  byte rsv_mask, rsv_position;
  byte directcolor_attributes;

  dword physbase;  // your LFB address ;)
  dword reserved1;
  short reserved2;
};
INT 0x10, AX=0x4F02
Set Video Mode. Call this with the mode number you decide to use.

Will it work with Bochs?

For VBE to work in Bochs you need the "VGABIOS-lgpl" BIOS and have a version of Bochs that was compiled with the --enable-vbe option... See Vesa Information in Bochs thread for more info. Also read about Bochs Graphics Adaptor.

How to pick the mode I wish ?

Here's a sample code, assuming you have a VirtualMonitor already ... Basically, you will scan the 'modes list' referenced by the vbeInfoBlock.videomodes[] and then call 'get mode info' for each mode. You can then compare width, height and colordepth of each mode with the desired one.

UInt16 findMode(int x, int y, int d)
{
  struct vbeControllerInfo *ctrl = (ControllerInfo *)0x2000;
  struct vbeModeInfo *inf = (ModeInfo *)0x3000;
  UInt16 *modes;
  int i;
  UInt16 best = 0x13;
  int pixdiff, bestpixdiff = DIFF(320 * 200, x * y);
  int depthdiff, bestdepthdiff = 8 >= d ? 8 - d : (d - 8) * 2;

  strncpy(ctrl->signature, "VBE2", 4);
  intV86(0x10, "ax,es:di", 0x4F00, 0, ctrl); // Get Controller Info
  if ( (UInt16)v86.tss.eax != 0x004F ) return best;

  modes = (UInt16*)REALPTR(ctrl->VideoModePtr);
  for ( i = 0 ; modes[i] != 0xFFFF ; ++i ) {
      intV86(0x10, "ax,cx,es:di", 0x4F01, modes[i], 0, inf); // Get Mode Info

      if ( (UInt16)v86.tss.eax != 0x004F ) continue;

      // Check if this is a graphics mode with linear frame buffer support
      if ( (inf->attributes & 0x90) != 0x90 ) continue;

      // Check if this is a packed pixel or direct color mode
      if ( inf->memory_model != 4 && inf->memory_model != 6 ) continue;

      // Check if this is exactly the mode we're looking for
      if ( x == inf->XResolution && y == inf->YResolution &&
          d == inf->BitsPerPixel ) return modes[i];

      // Otherwise, compare to the closest match so far, remember if best
      pixdiff = DIFF(inf->Xres * inf->Yres, x * y);
      depthdiff = (inf->bpp >= d)? inf->bpp - d : (d - inf->bpp) * 2;
      if ( bestpixdiff > pixdiff ||
          (bestpixdiff == pixdiff && bestdepthdiff > depthdiff) ) {
        best = modes[i];
        bestpixdiff = pixdiff;
        bestdepthdiff = depthdiff;
      }
  }
  if ( x == 640 && y == 480 && d == 1 ) return 0x11;
  return best;
}

See Also

Threads