VESA Programming, where to start?

 
0
 

Hi,

I decided that my operating system needs some graphics. I have seen loads of tutorials on drawing pixels, and I have used some. I now want to use 32bit protected mode (before I was using real mode) and I can't find any tutorials or documentation on drawing with VESA without the bios.

Can anyone point me in the right direction? If I can plot a single pixel, without the bios, I will be happy. :)

Thanks in advance.

 
1
 

...Can anyone point me in the right direction? If I can plot a single pixel, without the bios, I will be happy. :)...

Since you're using 32-bit Protected Mode to program VBE (VESA BIOS Extensions), then you can program for LFB (Linear Frame Buffer). With LFB, you can write to video memory without having to worry about Bank Switching.

The following Wikipedia article contains useful links at the end with more information:
http://en.wikipedia.org/wiki/VBE

I learned how to program the VBE LFB from Charles Sandman's vbetest.c. The following link contains Sandman's vbetest.c source, as well as what seems to be an excellent background on the concepts behind VBE 2.0 LFBs, and DJGPP protected mode:
http://pages.cpsc.ucalgary.ca/~walpole/325/DJ_GRAPH.txt

Note that turning off protected memory in DJGPP is generally not a good idea since it could cause conflicts with 3rd party libraries.

Also note that it's better to adapt these concepts to a compiler such as OpenWatcom, which is free and uses 32-Bit Protected Flat Mode by default:
http://openwatcom.mirrors.pair.com/open-watcom-c-dos-1.9.exe


The calculations below are off the top of my head...

The generic calculation to plot a pixel follows:

BPP = (VBEModeInfoBlock.BitsPerPixel + 1) / 8;
Offset = (PixelY * VBEModeInfoBlock.BytesPerScanline) + (PixelX * BPP);
memcpy( VidMem + Offset, &Pixel, BPP );

Plotting a pixel in 256 color mode (8-BPP) follows:

Offset = (PixelY * VBEModeInfoBlock.BytesPerScanline) + PixelX;
((u8_t*)VidMem)[Offset] = (u8_t)Pixel;

Plotting a pixel in 32768/65536 color mode (15/16-BPP) follows:

Offset = (PixelY * VBEModeInfoBlock.BytesPerScanline) + (PixelX << 1);
((u16_t*)VidMem)[Offset] = (u16_t)Pixel;

Plotting a pixel in 16 million color mode (24-BPP) follows:

Offset = (PixelY * VBEModeInfoBlock.BytesPerScanline) + (PixelY * 3);
((u8_t*)VidMem)[Offset + 0] = (u8_t)PixelByte0;
((u8_t*)VidMem)[Offset + 1] = (u8_t)PixelByte1;
((u8_t*)VidMem)[Offset + 2] = (u8_t)PixelByte2;

Plotting a pixel in 4 billion color mode (32-BPP) follows:

Offset = (PixelY * VBEModeInfoBlock.BytesPerScanline) + (PixelY << 2);
((u32_t*)VidMem)[Offset] = (u32_t)Pixel;

Ah the memories :) Let me know if you need more information, and I'll write some code using OpenWatcom to demonstrate the important concepts.

 
0
 

Err.. realized that you asked in reference to an OS..

VBE 2.0 is simple to target, but VBE 3.0 would likely be better suited for an OS (assuming it's implemented consistently well across graphics cards).

VBE 3.0 at its core supports hardware page flipping, and provides a direct PMode32 interface. I haven't coded for VBE 3.0 though, so not sure of the pros and cons.

Your OS needs to be able to map physical memory to linear memory so that you can use VBEModeInfoBlock.PhysBasePtr. Your OS also needs to handle BIOS calls properly.

I'll post some VBE 2.0 code by the end of next week for DOS PM32, using OpenWatcom. Although it'll be for DOS, at least you will see what API calls your OS needs.

 
0
 

wow, I wasn't expecting such a good answer. Thanks, I am looking forward to the VBE 2.0 code ;)

 
0
 

The first part of the VBE 2.0 LFB demo is ready. Nothing exciting on the surface, but there's a lot going on behind the scenes.

The development environment I used was DOSBOX, which as you may know is a DOS emulator. The following link is to a zip file with all the files necessary to develop the VBE demos. The folder can be mounted in DOSBOX, and run. The files can be copied to a native, or emulated, DOS installation. Note, you'll need to provide an e-mail address, otherwise filehosting.org will make you download a client (which you don't want to do :P)...
VBE development environment

DEMO1.C sets VBE graphics mode 640x480 at depths of 8-BPP (256 colors), 15-BPP (32768 colors), 16-BPP (65536 colors), 24-BPP (16.8 million colors), 32-BPP (16.8 million colors with a padding byte).

I didn't have a chance to test the 24-BPP screen clear, but am reasonably confident that it works. The 24-BPP SetPixel should not have any issues though. By the third demo, I'll dig up an old computer and set it up for 24-BPP testing :)

Note that a real mode Seg:Ofs can be converted into a linear address as follows: LinAddr = (Seg * 16) + Ofs. This is valid for 32-bit Flat Protected Mode. Segmented 32-bit Protected Mode may require a couple of extra steps. According to the VBE spec, the extra steps include getting the base address of the program's data selector, then subtracting it by the Linear Mapped Physical Address.

Using VBE in 32-bit Protected Mode depends heavily on DPMI services. Your OS will need to provide equivalent services.

vbectx_t
This structure holds the required information needed to draw graphics. VBEDriverInfo_t and VBEModeInfo_t contain a lot of information that is typically only used once.

Of note are fields rshift, gshift, bshift, and ashift. These values are the number of LSBs that need to be shifted for a more correct RGB value. These values are non-zero in 15-BPP and 16-BPP display modes.

The rmask, gmask, bmask, and amask fields store bit masks in the exact position where the component lies in the encoded pixel. These fields are used in 15/16/24/32-BPP display modes. EncodePixel uses component masks to remove bits which overlap with other component bits. DecodePixel uses component masks to isolate specific component bits.

vbe_SetPal()/vbe_GetPal()
Under DOS the palette DACs interpret RGB component values as 6-bits. By writing 0xFF to port 0x3C6, the palette DACs interpret RGB component values as 8-bits. The catch, apparently, is that not all video cards support changing the palette DAC mask size. What I do instead is shift the LSB of each RGB component by 2. [7][6][5][4][3][2][1][0] -> [-][-][7][6][5][4][3][2]

demo1_Run8()
The display mode is set to 640x480x256 colors. As you already may know, RGB values are used indirectly, so each pixel is actually a color index into a palette. Setting two RGB values is the equivalent of encoding two pixels in higher bit depths.

demo1_Run15() and demo1_Run16()
The display mode is set to 640x480x32768 and 640x480x65536, respectively. 15-BPP and 16-BPP modes are run separately, however, both depths use two bytes per pixel. As a result, they can use the same graphics functions.

In the Real World, most people test for specific cases of RGB pixel formats, such as A1_R5_G6_B5, in order to mask by constants and shift by constants -as opposed to referencing a pointer, to retrieve a value, to store the value into a register, to finally manipulate the pixel.

demo1_Run24_32()
The display mode is set to 640x480x16.8M. If the bit depth is 24, then 24-BPP graphics functions are used. Otherwise, 32-BPP graphics functions are used. For some reason, VESA separated 15-BPP and 16-BPP modes, but not 24-BPP and 32-BPP modes. New display modes exist specifically 32-BPP, but they are graphics card specific since VESA stopped pre-defining video modes.


The basic process to use VBE 2.0+ LFB follows:
1) Get mode information and test a specific ModeAttributes bit to confirm whether or not LFB is supported.
2) Create an LDT selector, set the granularity and access rights to read/write, set the base address to the mapped linear address.
3) Map the physical address into a linear address.
4) Set the LDT selector base address to the LFB linear address.
5) Set display mode to specified LFB mode.
6) Use the LFB pointer like a data pointer.


With VBE 2.0+ LFB (Linear Frame Buffer), you only need the BIOS to set the display mode.

Hopefully, you'll find this information useful so far. I've always wanted to write a tutorial on VBE graphics, so please feel free to ask if you (or anyone reading this) has any questions.

The following links to references I used to write the demo:

Dr Dobb's Journal: Using the VESA BIOS 2.0 Linear Frame Buffer

VBE 3.0 Specification (hosted by 3rd party)

Inverse Reality: Setting the VGA Palette

Inverse Reality: Setting VESA Video Modes

Attachments VBE.H (6.45 KB)
#ifndef __VBE_H
#define __VBE_H

#include <stdint.h>
#include <stdlib.h>
#include <string.h>

  /*
   *  VBE Display Mode definitions
   */
  #define VBE_640x480x8  0x101
  #define VBE_640x480x15 0x110
  #define VBE_640x480x16 0x111
  #define VBE_640x480x24 0x112

  /*
   *  Bit Field definitions
   */
  // VBEModeInfo.ModeAttributes flags
  #define VBE_MA_MODEHW (((uint32_t)1) << 0)
  #define VBE_MA_HASLFB (((uint32_t)1) << 7)
  #define VBE_MA_HW3BUF (((uint32_t)1) << 10)

  // VBEModeInfo.MemoryModel flags
  #define VBE_MM_DCOLOR 6

  /*
   *  Simulate Real Mode Interrupt Register Structure
   */
  #pragma pack( push, 1 )
  struct _rmiregs_t
  {
    uint32_t edi;
    uint32_t esi;
    uint32_t ebp;
    uint32_t rsvd;
    uint32_t ebx;
    uint32_t edx;
    uint32_t ecx;
    uint32_t eax;
    uint16_t flags;
    uint16_t es;
    uint16_t ds;
    uint16_t fs;
    uint16_t gs;
    uint16_t ip;
    uint16_t cs;
    uint16_t sp;
    uint16_t ss;
  };
  typedef struct _rmiregs_t rmiregs_t;
  #pragma pack( pop )

  /*
   *  VBE Driver Info Structure
   */
  #pragma pack( push, 1 )
  struct _VBEDriverInfo_t
  {
    char     VBESignature[4];
    uint16_t VBEVersion;
    uint32_t OEMStringPtr;
    uint32_t Capabilities;
    uint32_t VideoModePtr;
    uint16_t TotalMemory;

    // VBE 2.0 extensions
    uint16_t OemSoftwareRev;
    uint32_t OemVendorNamePtr;
    uint32_t OemProductNamePtr;
    uint32_t OemProductRevPtr;
    uint8_t  Reserved[222];
    uint8_t  OemDATA[256];
  };
  typedef struct _VBEDriverInfo_t VBEDriverInfo_t;
  #pragma pack( pop )

  /*
   *  VBE Mode Info Structure
   */
  #pragma pack( push, 1 )
  struct _VBEModeInfo_t
  {
    uint16_t ModeAttributes;
    uint8_t  WinAAttributes;
    uint8_t  WinBAttributes;
    uint16_t WinGranularity;
    uint16_t WinSize;
    uint16_t WinASegment;
    uint16_t WinBSegment;
    uint32_t WinFuncPtr;
    uint16_t BytesPerScanline;

    // VBE 1.2+
    uint16_t XResolution;
    uint16_t YResolution;
    uint8_t  XCharSize;
    uint8_t  YCharSize;
    uint8_t  NumberOfPlanes;
    uint8_t  BitsPerPixel;
    uint8_t  NumberOfBanks;
    uint8_t  MemoryModel;
    uint8_t  BankSize;
    uint8_t  NumberOfImagePages;
    uint8_t  Reserved1;

    // VBE 1.2+ Direct Color fields
    uint8_t  RedMaskSize;
    uint8_t  RedFieldPosition;
    uint8_t  GreenMaskSize;
    uint8_t  GreenFieldPosition;
    uint8_t  BlueMaskSize;
    uint8_t  BlueFieldPosition;
    uint8_t  RsvdMaskSize;
    uint8_t  RsvdFieldPosition;
    uint8_t  DirectColorModeInfo;

    // VBE 2.0+
    uint32_t PhysBasePtr;
    uint32_t Reserved2; // OffScreenMemOffset;
    uint16_t Reserved3; // OffScreenMemSize;

    // VBE 3.0+
    uint16_t LinBytesPerScanline;
    uint8_t  BnkNumberOfImagePages;
    uint8_t  LinNumberOfImagePages;
    uint8_t  LinRedMaskSize;
    uint8_t  LinRedFieldPosition;
    uint8_t  LinGreenMaskSize;
    uint8_t  LinGreenFieldPosition;
    uint8_t  LinBlueMaskSize;
    uint8_t  LinBlueFieldPosition;
    uint8_t  LinRsvdMaskSize;
    uint8_t  LinRsvdFieldPosition;
    uint32_t MaxPixelClock;

    uint8_t  Reserved4[189];
  };
  typedef struct _VBEModeInfo_t VBEModeInfo_t;
  #pragma pack( pop )

  /*
   *  24-bit RGB Structure and Palette
   */
  #pragma pack( push, 1 )
  struct _rgb_t
  {
    uint8_t r;
    uint8_t g;
    uint8_t b;
  };
  typedef struct _rgb_t rgb_t;
  #pragma pack( pop )

  typedef rgb_t pal3_t[256];

  /*
   *  32-bit RGB Structure and Palette
   */
  #pragma pack( push, 1 )
  struct _rgba_t
  {
    uint8_t r;
    uint8_t g;
    uint8_t b;
    uint8_t a;
  };
  typedef struct _rgba_t rgba_t;
  #pragma pack( pop )

  typedef rgba_t pal4_t[256];

  /*
   *  Clip Rectangle
   */
  #pragma pack( push, 1 )
  struct _cliprect_t
  {
    uint32_t minx;
    uint32_t miny;
    uint32_t maxx;
    uint32_t maxy;
  };
  typedef struct _cliprect_t cliprect_t;
  #pragma pack( pop )

  /*
   *  VBE Select Mode Information
   */
  #pragma pack(push, 1)
  struct _vbectx_t
  {
    uint8_t*   lfb;
    uint32_t   lfbsize;
    uint16_t   lfbsel;
    uint8_t    bpp;
    uint8_t    rsvd;

    cliprect_t clip;

    uint32_t   width;
    uint32_t   height;
    uint32_t   linesize;

    uint32_t   rmask;
    uint32_t   gmask;
    uint32_t   bmask;
    uint32_t   amask;

    uint8_t    rshift;
    uint8_t    gshift;
    uint8_t    bshift;
    uint8_t    ashift;

    uint8_t    rpos;
    uint8_t    gpos;
    uint8_t    bpos;
    uint8_t    apos;
  };
  typedef struct _vbectx_t vbectx_t;
  #pragma pack(pop)

  /*
   *  DPMI Support Functions
   */
  uint32_t dpmi_AllocRealSeg( uint32_t p_size );
  void dpmi_FreeRealSeg( uint32_t* p_selseg );

  int dpmi_SimRealModeInt( uint8_t p_int, rmiregs_t* p_rmregs );

  uint16_t dpmi_AllocSel( void );
  void dpmi_FreeSel( uint16_t* p_sel );
  int dpmi_SetSelRights( uint16_t p_sel, uint16_t p_rights );
  int dpmi_SetSelBase( uint16_t p_sel, uint32_t p_linAddr );
  int dpmi_SetSelLimit( uint16_t p_sel, uint32_t p_limit );

  uint32_t dpmi_MapPhysicalAddress( uint32_t p_physAddr,
    uint32_t p_size );
  void dpmi_FreePhysicalAddress( uint32_t* p_linAddr );

  /*
   *  General System Support Functions
   */
  uint32_t sys_RM16ToFlat32( uint32_t p_RMSegOfs );

  /*
   *  VBE Support Functions
   */
  int vbe_Init( void );
  void vbe_Done( vbectx_t** p_ctx );

  int vbe_GetDriverInfo( VBEDriverInfo_t* p_drvInfo );

  int vbe_GetModeInfo( uint16_t p_mode, VBEModeInfo_t* p_modeInfo );

  /*
   *  VBE Display Functions
   */
  vbectx_t* vbe_SetMode( uint16_t p_mode );
  void vbe_ReleaseCtx( vbectx_t** p_ctx );
  void vbe_CloseMode( vbectx_t** p_ctx );

  vbectx_t* vbe_CreateBuf( vbectx_t* p_ctx,
    uint32_t p_width, uint32_t p_height );

  void vbe_SetClip( vbectx_t* p_ctx,
    int32_t p_minx, int32_t p_miny,
    int32_t p_maxx, int32_t p_maxy );

  void vbe_Capture( vbectx_t* p_display, vbectx_t* p_buf );
  void vbe_Flip( vbectx_t* p_display, vbectx_t* p_buf );

  /*
   *  VBE Pixel Format Functions
   */
  void vbe_DecodePixel( vbectx_t* p_ctx, uint32_t p_pixel,
    uint8_t* p_r, uint8_t* p_g, uint8_t* p_b );
  uint32_t vbe_EncodePixel( vbectx_t* p_ctx,
    uint8_t p_r, uint8_t p_g, uint8_t p_b );

  /*
   *  8-BPP Graphics Functions
   */
  void vbe_GetPal( vbectx_t* p_ctx, rgba_t* p_pal );
  void vbe_SetPal( vbectx_t* p_ctx, rgba_t* p_pal );

#endif
GFX.H (1.09 KB)
#ifndef __GFX_H
#define __GFX_H

  #include <stdint.h>
  #include "vbe.h"

  /*
   *  Graphics function pointer structure
   */
  struct _gfx_t
  {
    void (* Clear)( vbectx_t*, uint32_t );
    void (* SetPixel)( vbectx_t*, int32_t, int32_t, uint32_t );
  };
  typedef struct _gfx_t gfx_t;

  /*
   *  General functions
   */
  gfx_t* gfx_Create( vbectx_t* p_ctx );
  void gfx_Release( gfx_t** p_gfx );

  /*
   *  Buffer Clear functions
   */
  void gfx_Clear8( vbectx_t* p_ctx, uint32_t p_color );
  void gfx_Clear16( vbectx_t* p_ctx, uint32_t p_color );
  void gfx_Clear24( vbectx_t* p_ctx, uint32_t p_color );
  void gfx_Clear32( vbectx_t* p_ctx, uint32_t p_color );

  /*
   *  Set Pixel functions
   */
  void gfx_SetPixel8( vbectx_t* p_ctx,
    int32_t p_x, int32_t p_y, uint32_t p_pixel );
  void gfx_SetPixel16( vbectx_t* p_ctx,
    int32_t p_x, int32_t p_y, uint32_t p_pixel );
  void gfx_SetPixel24( vbectx_t* p_ctx,
    int32_t p_x, int32_t p_y, uint32_t p_pixel );
  void gfx_SetPixel32( vbectx_t* p_ctx,
    int32_t p_x, int32_t p_y, uint32_t p_pixel );

#endif
VBE.C (21.03 KB)
The attachment preview is chopped off after the first 10 KB. Please download the entire file.
#include <stdio.h>

#include "vbe.h"

  uint32_t vbe_selseg = 0;

  /*
   *  uint32_t dpmi_AllocRealSeg( p_size )
   *
   *  Purpose:
   *    Allocates p_size bytes of low memory,
   *    padded to a 16 byte boundary.
   *
   *  Returns:
   *    0 on error
   *    ((PMSelector << 16) | RMSegment) on success
   */
  uint32_t dpmi_AllocRealSeg( uint32_t p_size );
  #pragma aux dpmi_AllocRealSeg=\
  "  test    ebx, ebx"\
  "  jz      AllocRealSeg_Error"\
  "  cmp     ebx, 65535"\
  "  ja      AllocRealSeg_Error"\
  "  add     ebx, 15"\
  "  shr     ebx, 4"\
  "  mov     eax, 0x100"\
  "  int     0x31"\
  "  jc      AllocRealSeg_Error"\
  "  and     eax, 0x0000FFFF"\
  "  shl     edx, 16"\
  "  add     eax, edx"\
  "  jmp     AllocRealSeg_Exit"\
  "AllocRealSeg_Error:"\
  "  xor     eax, eax"\
  "AllocRealSeg_Exit:"\
  parm[ebx]\
  modify[ebx edx]\
  value[eax];

  /*
   *  void dpmi_FreeRealSeg( *p_selseg )
   *
   *  Purpose:
   *    Releases previously allocated low memory.
   *
   *  Returns:
   *    Nothing
   *
   */
  void dpmi_FreeRealSeg( uint32_t* p_selseg );
  #pragma aux dpmi_FreeRealSeg=\
  "  test    edi, edi"\
  "  jz      FreeRealSeg_Error"\
  "  mov     edx, [edi]"\
  "  push    edi"\
  "  shr     edx, 16"\
  "  mov     eax, 0x101"\
  "  int     0x31"\
  "  pop     edi"\
  "  mov     dword ptr [edi], 0"\
  "FreeRealSeg_Error:"\
  parm[edi]\
  modify[eax edx edi];

  /*
   *  int dpmi_SimRealModeInt( p_int, p_regs )
   *
   *  Purpose:
   *    Simulates a Real Mode Interrupt.
   *
   *  Returns:
   *    0 on error
   *    1 on success
   */
  int dpmi_SimRealModeInt( uint8_t p_int, rmiregs_t* p_rmregs );
  #pragma aux dpmi_SimRealModeInt=\
  "  push    es"\
  "  test    edi, edi"\
  "  jz      SimRealModeInt_Error"\
  "  and     ebx, 0x000000FF"\
  "  xor     ecx, ecx"\
  "  mov     eax, 0x300"\
  "  mov     dx, ds"\
  "  mov     es, dx"\
  "  int     0x31"\
  "  jc      SimRealModeInt_Error"\
  "  mov     eax, 1"\
  "  jmp     SimRealModeInt_Exit"\
  "SimRealModeInt_Error:"\
  "  xor     eax, eax"\
  "SimRealModeInt_Exit:"\
  "  pop     es"\
  parm[bl][edi]\
  modify[ebx ecx edx edi esi]\
  value[eax];

  /*
   *  uint16_t dpmi_AllocSel()
   *
   *  Purpose:
   *    Allocates one descriptor.
   *
   *  Returns:
   *    0 on error
   *    Selector on success
   */
  uint16_t dpmi_AllocSel( void );
  #pragma aux dpmi_AllocSel=\
  "  mov     eax, 0"\
  "  mov     ecx, 1"\
  "  int     0x31"\
  "  jnc     AllocSel_Exit"\
  "  xor     ax, ax"\
  "AllocSel_Exit:"\
  modify[ecx]\
  value[ax];

  /*
   *  void dpmi_FreeSel( *p_sel )
   *
   *  Purpose:
   *    Releases a descriptor.
   *
   *  Returns:
   *    Nothing
   */
  void dpmi_FreeSel( uint16_t* p_sel );
  #pragma aux dpmi_FreeSel=\
  "  test    edi, edi"\
  "  jz      FreeSel_Error"\
  "  mov     bx, [edi]"\
  "  mov     dword ptr [edi], 0"\
  "  mov     eax, 1"\
  "  int     0x31"\
  "FreeSel_Error:"\
  parm[edi]\
  modify[eax ebx];

  /*
   *  int dpmi_SetSelRights( p_sel, p_rights )
   *
   *  Purpose:
   *    Modifies access rights and type fields for the
   *    specified selector.
   *
   *  Returns:
   *    0 on error
   *    1 on success
   */
  int dpmi_SetSelRights( uint16_t p_sel, uint16_t p_rights );
  #pragma aux dpmi_SetSelRights=\
  "  mov     eax, 9"\
  "  int     0x31"\
  "  mov     eax, 0"\
  "  jc      SetSelRights_Error"\
  "  mov     eax, 1"\
  "SetSelRights_Error:"\
  parm[bx][cx]\
  value[eax];

  /*
   *  int dpmi_SetSelBase( p_sel, p_linAddr )
   *
   *  Purpose:
   *    Sets the base address for the specified selector.
   *
   *  Returns:
   *    0 on error
   *    1 on success
   */
  int dpmi_SetSelBase( uint16_t p_sel, uint32_t p_linAddr );
  #pragma aux dpmi_SetSelBase=\
  "  mov     edx, ecx"\
  "  shr     ecx, 16"\
  "  and     edx, 0xFFFF"\
  "  mov     eax, 7"\
  "  int     0x31"\
  "  jc      SetSelBase_Error"\
  "  mov     eax, 1"\
  "  jmp     SetSelBase_Exit"\
  "SetSelBase_Error:"\
  "  xor     eax, eax"\
  "SetSelBase_Exit:"\
  parm[bx][ecx]\
  modify[ecx edx]\
  value[eax];

  /*
   *  int dpmi_SetSelLimit( p_sel, p_limit )
   *
   *  Purpose:
   *    Sets the limit for the specified selector.
   *
   *  Returns:
   *    0 on error
   *    1 on success
   */
  int dpmi_SetSelLimit( uint16_t p_sel, uint32_t p_limit );
  #pragma aux dpmi_SetSelLimit=\
  "  mov     edx, ecx"\
  "  shr     ecx, 16"\
  "  and     edx, 0xFFFF"\
  "  mov     eax, 8"\
  "  int     0x31"\
  "  jc      SetSelLimit_Error"\
  "  mov     eax, 1"\
  "  jmp     SetSelLimit_Exit"\
  "SetSelLimit_Error:"\
  "  xor     eax, eax"\
  "SetSelLimit_Exit:"\
  parm[bx][ecx]\
  modify[ecx edx]\
  value[eax];

  /*
   *  uint32_t dpmi_MapPhysicalAddress( p_physAddr, p_size )
   *
   *  Purpose:
   *    Converts a physical address to a linear address.
   *
   *  Returns:
   *    0 on error
   *    Linear Address on success
   */
  uint32_t dpmi_MapPhysicalAddress( uint32_t p_physAddr,
    uint32_t p_size );
  #pragma aux dpmi_MapPhysicalAddress=\
  "  mov     ecx, ebx"\
  "  mov     edi, esi"\
  "  shr     ebx, 16"\
  "  and     ecx, 0xFFFF"\
  "  shr     esi, 16"\
  "  and     edi, 0xFFFF"\
  "  mov     eax, 0x800"\
  "  int     0x31"\
  "  jc      MapPhysicalAddress_Error"\
  "  shl     ebx, 16"\
  "  and     ecx, 0xFFFF"\
  "  mov     eax, ebx"\
  "  or      eax, ecx"\
  "  jmp     MapPhysicalAddress_Exit"\
  "MapPhysicalAddress_Error:"\
  "  xor     eax, eax"\
  "MapPhysicalAddress_Exit:"\
  parm[ebx][esi]\
  modify[ebx ecx edx esi edi]\
  value[eax];

  /*
   *  uint32_t dpmi_FreePhysicalAddress( *p_linAddr )
   *
   *  Purpose:
   *    Releases a previously mapped linear address.
   *
   *  Returns:
   *    Nothing
   */
  void dpmi_FreePhysicalAddress( uint32_t* p_linAddr );
  #pragma aux dpmi_FreePhysicalAddress=\
  "  test    edi, edi"\
  "  jz      FreePhysicalAddress_Error"\
  "  mov     bx, [edi + 2]"\
  "  mov     cx, [edi + 0]"\
  "  mov     dword ptr [edi], 0"\
  "  mov     eax, 0x0801"\
  "  int     0x31"\
  "FreePhysicalAddress_Error:"\
  parm[edi]\
  modify[eax];

  /*
   *  uint32_t sys_RM16ToFlat32( p_RMSegOfs )
   *
   *  Purpose:
   *    Converts a Real Mode Seg16:Ofs16 address
   *    into a Flat 32-Bit address.
   *
   *  Returns:
   *    (Seg16 << 4) + Ofs16
   */
  uint32_t sys_RM16ToFlat32( uint32_t p_RMSegOfs );
  #pragma aux sys_RM16ToFlat32=\
  "  mov     edx, eax"\
  "  and     eax, 0xFFFF0000"\
  "  and     edx, 0x0000FFFF"\
  "  shr     eax, 12"\
  "  add     eax, edx"\
  parm[eax]\
  modify[edx]\
  value[eax];

  /*
   *  int vbe_Init()
   *
   *  Purpose:
   *    Allocates low memory for VBE driver info, low memory
   *    for VBE mode info, and tests for VBE 2.0+.
   *
   *  Returns:
   *    0 on error
   *    1 on success
   */
  int vbe_Init( void )
  {
    VBEDriverInfo_t l_drv;

    if( vbe_selseg == 0 )
    {
      vbe_selseg = dpmi_AllocRealSeg(1024);
    }

    // Indirect revalidation of vbe_selseg
    return vbe_GetDriverInfo(&l_drv);
  }

  /*
   *  void vbe_Done( **p_ctx )
   *
   *  Purpose:
   *    Releases low memory, releases system resources used
   *    by VBE Context, and resets display mode.
   *
   *  Returns:
   *    Nothing
   */
  void vbe_Done( vbectx_t** p_ctx )
  {
    // Already checks for/sets to NULL
    vbe_CloseMode( p_ctx );

    // Already checks for/sets to NULL
    dpmi_FreeRealSeg( &vbe_selseg );
  }

  /*
   *  int vbe_GetDriverInfo( *p_drvInfo )
   *
   *  Purpose:
   *    Returns VBE driver info. Handles low memory.
   *    Validates for version VBE 2.0+.
   *
   *  Returns:
   *    0 on error
   *    1 on success
   */
  int vbe_GetDriverInfo( VBEDriverInfo_t* p_drvInfo )
  {
    char             l_vbe2Sig[4] = "VBE2";
    rmiregs_t        l_regs;
    VBEDriverInfo_t* l_di;
    char             l_drvName[128];

    if( vbe_selseg && p_drvInfo )
    {
      l_di = (VBEDriverInfo_t*)(((uint16_t)vbe_selseg) << 4);
      memset( l_di, 0, 1024 );
      memcpy( l_di, l_vbe2Sig, 4 );

      memset( &l_regs, 0, sizeof(l_regs) );
      l_regs.eax = 0x4F00;
      l_regs.es  = (uint16_t)vbe_selseg;
      l_regs.edi = 0;
      dpmi_SimRealModeInt( 0x10, &l_regs );

      memcpy( p_drvInfo, l_di, sizeof(VBEDriverInfo_t) );

      if( (((uint16_t)l_regs.eax) == 0x004F) &&
        (strncmp(p_drvInfo->VBESignature, "VESA", 4) == 0) &&
        (p_drvInfo->VBEVersion >= 0x200) )
      {
        p_drvInfo->OEMStringPtr =
          sys_RM16ToFlat32(p_drvInfo->OEMStringPtr);
        p_drvInfo->VideoModePtr =
          sys_RM16ToFlat32(p_drvInfo->VideoModePtr);

        p_drvInfo->OemVendorNamePtr =
          sys_RM16ToFlat32(p_drvInfo->OemVendorNamePtr);
        p_drvInfo->OemProductNamePtr =
          sys_RM16ToFlat32(p_drvInfo->OemProductNamePtr);
        p_drvInfo->OemProductRevPtr =
          sys_RM16ToFlat32(p_drvInfo->OemProductRevPtr);

        return 1;
      }
    }

    return 0;
  }

  /*
   *  int vbe_GetModeInfo( p_mode, *p_modeInfo )
   *
   *  Purpose:
   *    Returns specified VBE mode info. Handles low memory.
   *    Validates for LFB and 8/15/16/24/32-BPP.
   *
   *  Returns:
   *    0 on error
   *    1 on success
   */
  int vbe_GetModeInfo( uint16_t p_mode, VBEModeInfo_t* p_modeInfo )
  {
    rmiregs_t      l_regs;
    VBEModeInfo_t* l_mi;

    if( !(vbe_selseg && p_modeInfo) )
    {
      return 0;
    }

    // Check if mode list terminator was passed as parameter
    if( p_mode == 0xFFFF )
    {
      return 0;
    }

    l_mi = (VBEModeInfo_t*)((vbe_selseg & 0x0000FFFF) << 4);
    memset( l_mi, 0, 1024 );

    memset( &l_regs, 0, sizeof(l_regs) );
    l_regs.eax = 0x4F01;
    l_regs.ecx = p_mode;
    l_regs.es  = (uint16_t)vbe_selseg;
    l_regs.edi = 0;
    dpmi_SimRealModeInt( 0x10, &l_regs );

    if( ((uint16_t)l_regs.eax) != 0x004F )
    {
      return 0;
    }

    // Mode m
GFX.C (4.79 KB)
#include "gfx.h"

  gfx_t* gfx_Create( vbectx_t* p_ctx )
  {
    gfx_t* l_gfx;

    if( p_ctx == NULL )
    {
      return NULL;
    }

    l_gfx = (gfx_t*)calloc(1, sizeof(gfx_t));
    if( l_gfx == NULL )
    {
      return NULL;
    }

    switch( p_ctx->bpp )
    {
    case 8:
      l_gfx->Clear    = gfx_Clear8;
      l_gfx->SetPixel = gfx_SetPixel8;
      return l_gfx;

    case 15:
    case 16:
      l_gfx->Clear    = gfx_Clear16;
      l_gfx->SetPixel = gfx_SetPixel16;
      return l_gfx;

    case 24:
      l_gfx->Clear    = gfx_Clear24;
      l_gfx->SetPixel = gfx_SetPixel24;
      return l_gfx;

    case 32:
      l_gfx->Clear    = gfx_Clear32;
      l_gfx->SetPixel = gfx_SetPixel32;
      return l_gfx;
    }

    free( l_gfx );

    return NULL;
  }

  void gfx_Release( gfx_t** p_gfx )
  {
    if( p_gfx )
    {
      if( *p_gfx )
      {
        free( *p_gfx );
      }

      *p_gfx = NULL;
    }
  }

  void gfx_Clear8_asm( void* p_lfb,
    uint32_t p_lfbsize, uint32_t p_color );
  #pragma aux gfx_Clear8_asm=\
  "  test    edi, edi"\
  "  jz      Clear8_Error"\
  "  rep stosb"\
  "Clear8_Error:"\
  parm[edi][ecx][eax]\
  modify[edi];

  void gfx_Clear8( vbectx_t* p_ctx, uint32_t p_color )
  {
    if( p_ctx )
    {
      gfx_Clear8_asm( p_ctx->lfb, p_ctx->lfbsize, p_color );
    }
  }

  void gfx_Clear16_asm( void* p_lfb,
    uint32_t p_lfbsize, uint32_t p_color );
  #pragma aux gfx_Clear16_asm=\
  "  test    edi, edi"\
  "  jz      Clear16_Error"\
  "  rep stosw"\
  "Clear16_Error:"\
  parm[edi][ecx][eax]\
  modify[edi];

  void gfx_Clear16( vbectx_t* p_ctx, uint32_t p_color )
  {
    if( p_ctx )
    {
      gfx_Clear16_asm( p_ctx->lfb, p_ctx->lfbsize, p_color );
    }
  }

  void gfx_Clear24_asm( void* p_lfb,
    uint32_t p_lfbsize, uint32_t p_color );
  #pragma aux gfx_Clear24_asm=\
  "  test    edi, edi"\
  "  jz      Clear24_Error"\
  ""\
  "  bswap eax"\
  "  shr     eax, 8"\
  ""\
  "Clear24_Loop:"\
  "  mov     [edi], eax"\
  "  add     edi, 3"\
  "  sub     ecx, 3"\
  "  ja      Clear24_Loop"\
  "Clear24_Error:"\
  parm[edi][ecx][eax]\
  modify[ebx ecx edx edi];

  void gfx_Clear24( vbectx_t* p_ctx, uint32_t p_color )
  {
    if( p_ctx )
    {
      gfx_Clear24_asm( p_ctx->lfb, p_ctx->lfbsize, p_color );
    }
  }

  void gfx_Clear32_asm( void* p_lfb,
    uint32_t p_lfbsize, uint32_t p_color );
  #pragma aux gfx_Clear32_asm=\
  "  test    edi, edi"\
  "  jz      Clear32_Error"\
  "  rep stosd"\
  "Clear32_Error:"\
  parm[edi][ecx][eax]\
  modify[edi];

  void gfx_Clear32( vbectx_t* p_ctx, uint32_t p_color )
  {
    if( p_ctx )
    {
      gfx_Clear32_asm( p_ctx->lfb, p_ctx->lfbsize, p_color );
    }
  }

  void gfx_SetPixel8( vbectx_t* p_ctx,
    int32_t p_x, int32_t p_y, uint32_t p_pixel )
  {
    uint8_t* l_lfb;

    if( p_ctx )
    {
      if( p_ctx->lfb )
      {
        if( (p_x < p_ctx->clip.minx) || (p_y < p_ctx->clip.miny)
          || (p_x > p_ctx->clip.maxx) || (p_y > p_ctx->clip.maxy) )
        {
          return;
        }

        l_lfb = (uint8_t*)(p_ctx->lfb + (p_y * p_ctx->linesize) + p_x);

        *l_lfb = (uint8_t)p_pixel;
      }
    }
  }

  void gfx_SetPixel16( vbectx_t* p_ctx,
    int32_t p_x, int32_t p_y, uint32_t p_pixel )
  {
    uint16_t* l_lfb;

    if( p_ctx )
    {
      if( p_ctx->lfb )
      {
        if( (p_x < p_ctx->clip.minx) || (p_y < p_ctx->clip.miny)
          || (p_x > p_ctx->clip.maxx) || (p_y > p_ctx->clip.maxy) )
        {
          return;
        }

        l_lfb = (uint16_t*)(p_ctx->lfb + (p_y * p_ctx->linesize)
          + (p_x * 2));

        *l_lfb = (uint16_t)p_pixel;
      }
    }
  }

  void gfx_SetPixel24( vbectx_t* p_ctx,
    int32_t p_x, int32_t p_y, uint32_t p_pixel )
  {
    uint8_t* l_lfb;

    if( p_ctx )
    {
      if( p_ctx->lfb )
      {
        if( (p_x < p_ctx->clip.minx) || (p_y < p_ctx->clip.miny)
          || (p_x > p_ctx->clip.maxx) || (p_y > p_ctx->clip.maxy) )
        {
          return;
        }

        l_lfb = (uint8_t*)(p_ctx->lfb + (p_y * p_ctx->linesize)
          + (p_x * 3));

        l_lfb[0] = (uint8_t)(p_pixel >> 0);
        l_lfb[1] = (uint8_t)(p_pixel >> 8);
        l_lfb[2] = (uint8_t)(p_pixel >> 16);
      }
    }
  }

  void gfx_SetPixel32( vbectx_t* p_ctx,
    int32_t p_x, int32_t p_y, uint32_t p_pixel )
  {
    uint32_t* l_lfb;

    if( p_ctx )
    {
      if( p_ctx->lfb )
      {
        if( (p_x < p_ctx->clip.minx) || (p_y < p_ctx->clip.miny)
          || (p_x > p_ctx->clip.maxx) || (p_y > p_ctx->clip.maxy) )
        {
          return;
        }

        l_lfb = (uint32_t*)(p_ctx->lfb + (p_y * p_ctx->linesize)
          + (p_x * 4));

        *l_lfb = p_pixel;
      }
    }
  }
DEMO1.C (6.61 KB)
#include <stdio.h>
#include <string.h>

#include "vbe.h"
#include "gfx.h"

  char demo1_WaitKey( void );
  #pragma aux demo1_WaitKey=\
  "  xor     ax, ax"\
  "  int     0x16"\
  value[al];

  void demo1_Run8()
  {
    vbectx_t* l_ctx;
    int32_t   l_centerx;
    int32_t   l_centery;
    pal4_t    l_pal;

    l_ctx = vbe_SetMode(VBE_640x480x8);
    if( l_ctx )
    {
      vbe_GetPal( l_ctx, l_pal );

      l_pal[254].r = 128;
      l_pal[254].g = 64;
      l_pal[254].b = 32;

      l_pal[255].r = 64;
      l_pal[255].g = 128;
      l_pal[255].b = 255;
      vbe_SetPal( l_ctx, l_pal );

      gfx_Clear8( l_ctx, 255 );

      l_centerx = l_ctx->width / 2;
      l_centery = l_ctx->height / 2;

      gfx_SetPixel8( l_ctx, l_centerx - 2, l_centery + 0, 254 );
      gfx_SetPixel8( l_ctx, l_centerx - 1, l_centery + 0, 254 );
      gfx_SetPixel8( l_ctx, l_centerx + 0, l_centery + 0, 254 );
      gfx_SetPixel8( l_ctx, l_centerx + 1, l_centery + 0, 254 );
      gfx_SetPixel8( l_ctx, l_centerx + 2, l_centery + 0, 254 );
      gfx_SetPixel8( l_ctx, l_centerx + 0, l_centery - 2, 254 );
      gfx_SetPixel8( l_ctx, l_centerx + 0, l_centery - 1, 254 );
      gfx_SetPixel8( l_ctx, l_centerx + 0, l_centery + 0, 254 );
      gfx_SetPixel8( l_ctx, l_centerx + 0, l_centery + 1, 254 );
      gfx_SetPixel8( l_ctx, l_centerx + 0, l_centery + 2, 254 );

      demo1_WaitKey();

      vbe_CloseMode( &l_ctx );
    }
    else
    {
      printf( "VBE mode %#.4x not supported\n", VBE_640x480x8 );
      printf( "\n" );
    }
  }

  void demo1_Run15()
  {
    vbectx_t* l_ctx;
    int32_t   l_centerx;
    int32_t   l_centery;
    uint32_t  l_pixel;

    l_ctx = vbe_SetMode(VBE_640x480x15);
    if( l_ctx )
    {
      l_pixel = vbe_EncodePixel(l_ctx, 64, 128, 255);
      gfx_Clear16( l_ctx, l_pixel );

      l_centerx = l_ctx->width / 2;
      l_centery = l_ctx->height / 2;

      l_pixel = vbe_EncodePixel(l_ctx, 128, 64, 32);
      gfx_SetPixel16( l_ctx, l_centerx - 2, l_centery + 0, l_pixel );
      gfx_SetPixel16( l_ctx, l_centerx - 1, l_centery + 0, l_pixel );
      gfx_SetPixel16( l_ctx, l_centerx + 0, l_centery + 0, l_pixel );
      gfx_SetPixel16( l_ctx, l_centerx + 1, l_centery + 0, l_pixel );
      gfx_SetPixel16( l_ctx, l_centerx + 2, l_centery + 0, l_pixel );
      gfx_SetPixel16( l_ctx, l_centerx + 0, l_centery - 2, l_pixel );
      gfx_SetPixel16( l_ctx, l_centerx + 0, l_centery - 1, l_pixel );
      gfx_SetPixel16( l_ctx, l_centerx + 0, l_centery + 0, l_pixel );
      gfx_SetPixel16( l_ctx, l_centerx + 0, l_centery + 1, l_pixel );
      gfx_SetPixel16( l_ctx, l_centerx + 0, l_centery + 2, l_pixel );

      demo1_WaitKey();

      vbe_CloseMode( &l_ctx );
    }
    else
    {
      printf( "VBE mode %#.4x not supported\n", VBE_640x480x15 );
      printf( "\n" );
    }
  }

  void demo1_Run16()
  {
    vbectx_t* l_ctx;
    int32_t   l_centerx;
    int32_t   l_centery;
    uint32_t  l_pixel;

    l_ctx = vbe_SetMode(VBE_640x480x16);
    if( l_ctx )
    {
      l_pixel = vbe_EncodePixel(l_ctx, 64, 128, 255);

      gfx_Clear16( l_ctx, l_pixel );

      l_centerx = l_ctx->width / 2;
      l_centery = l_ctx->height / 2;

      l_pixel = vbe_EncodePixel(l_ctx, 128, 64, 32);
      gfx_SetPixel16( l_ctx, l_centerx - 2, l_centery + 0, l_pixel );
      gfx_SetPixel16( l_ctx, l_centerx - 1, l_centery + 0, l_pixel );
      gfx_SetPixel16( l_ctx, l_centerx + 0, l_centery + 0, l_pixel );
      gfx_SetPixel16( l_ctx, l_centerx + 1, l_centery + 0, l_pixel );
      gfx_SetPixel16( l_ctx, l_centerx + 2, l_centery + 0, l_pixel );
      gfx_SetPixel16( l_ctx, l_centerx + 0, l_centery - 2, l_pixel );
      gfx_SetPixel16( l_ctx, l_centerx + 0, l_centery - 1, l_pixel );
      gfx_SetPixel16( l_ctx, l_centerx + 0, l_centery + 0, l_pixel );
      gfx_SetPixel16( l_ctx, l_centerx + 0, l_centery + 1, l_pixel );
      gfx_SetPixel16( l_ctx, l_centerx + 0, l_centery + 2, l_pixel );

      demo1_WaitKey();

      vbe_CloseMode( &l_ctx );
    }
    else
    {
      printf( "VBE mode %#.4x not supported\n", VBE_640x480x16 );
      printf( "\n" );
    }
  }

  void demo1_Run24_32()
  {
    vbectx_t* l_ctx;
    int32_t   l_centerx;
    int32_t   l_centery;
    uint32_t  l_pixel;

    l_ctx = vbe_SetMode(VBE_640x480x24);
    if( l_ctx )
    {
      l_pixel = vbe_EncodePixel(l_ctx, 64, 128, 255);

      l_centerx = l_ctx->width / 2;
      l_centery = l_ctx->height / 2;

      if( l_ctx->bpp == 24 )
      {
        gfx_Clear24( l_ctx, l_pixel );

        l_pixel = vbe_EncodePixel(l_ctx, 128, 64, 32);
        gfx_SetPixel24( l_ctx, l_centerx - 2, l_centery + 0, l_pixel );
        gfx_SetPixel24( l_ctx, l_centerx - 1, l_centery + 0, l_pixel );
        gfx_SetPixel24( l_ctx, l_centerx + 0, l_centery + 0, l_pixel );
        gfx_SetPixel24( l_ctx, l_centerx + 1, l_centery + 0, l_pixel );
        gfx_SetPixel24( l_ctx, l_centerx + 2, l_centery + 0, l_pixel );
        gfx_SetPixel24( l_ctx, l_centerx + 0, l_centery - 2, l_pixel );
        gfx_SetPixel24( l_ctx, l_centerx + 0, l_centery - 1, l_pixel );
        gfx_SetPixel24( l_ctx, l_centerx + 0, l_centery + 0, l_pixel );
        gfx_SetPixel24( l_ctx, l_centerx + 0, l_centery + 1, l_pixel );
        gfx_SetPixel24( l_ctx, l_centerx + 0, l_centery + 2, l_pixel );
      }
      else
      {
        gfx_Clear32( l_ctx, l_pixel );

        l_pixel = vbe_EncodePixel(l_ctx, 128, 64, 32);
        gfx_SetPixel32( l_ctx, l_centerx - 2, l_centery + 0, l_pixel );
        gfx_SetPixel32( l_ctx, l_centerx - 1, l_centery + 0, l_pixel );
        gfx_SetPixel32( l_ctx, l_centerx + 0, l_centery + 0, l_pixel );
        gfx_SetPixel32( l_ctx, l_centerx + 1, l_centery + 0, l_pixel );
        gfx_SetPixel32( l_ctx, l_centerx + 2, l_centery + 0, l_pixel );
        gfx_SetPixel32( l_ctx, l_centerx + 0, l_centery - 2, l_pixel );
        gfx_SetPixel32( l_ctx, l_centerx + 0, l_centery - 1, l_pixel );
        gfx_SetPixel32( l_ctx, l_centerx + 0, l_centery + 0, l_pixel );
        gfx_SetPixel32( l_ctx, l_centerx + 0, l_centery + 1, l_pixel );
        gfx_SetPixel32( l_ctx, l_centerx + 0, l_centery + 2, l_pixel );
      }

      demo1_WaitKey();

      vbe_CloseMode( &l_ctx );
    }
    else
    {
      printf( "VBE mode %#.4x not supported\n", VBE_640x480x24 );
      printf( "\n" );
    }
  }

int main( int argc, char* argv[] )
{
  VBEModeInfo_t l_minfo;

  if( vbe_Init() == 0 )
  {
    printf( "ERROR: VBE driver not supported.\n" );

    return 0;
  }

  demo1_Run8();

  demo1_Run15();

  demo1_Run16();

  demo1_Run24_32();

  vbe_Done( NULL );

  return 0;
}
 
0
 

I have had a look at the code and it looks rather good but I have no idea how to compile them.

As OpenWatcom was mentioned, I assume that is the logical choice to compile them with but I have no idea how to use it.

My DOS skills are way out of practice. In fact I have only used DOS a few times before.

Please explain how to use OpenWatcom to compile the code files.

Thanks,
Kieran ;)

 
1
 

I have had a look at the code and it looks rather good but I have no idea how to compile them.

Right, sorry 'bout that! Attached is a zip file of the main source, the makefile is included. Also, there is a BMP and a GIF, those are for demo3.

The makefile is for convenience, but compiling is as simple as: wcl386 demo vbe gfx -q -q operates the compiler in silent mode, which keeps quiet until there is an error.

Attachments vbesrc.zip (55.71 KB)
 
0
 

Attached to this reply is a more recent vbesrc.zip file.

This release focuses on demo2, which shows driver and mode information. Don't be surprised if you see mode numbers such as 810E. Whatever display modes demo2 shows are valid.

To build, just type

wmake

The following have changed since the previous vbesrc.zip upload:
- Added stubs for FillRect, PutImage, and other functions
- Added missing comments to function implementations
- Added demo2.c and demo3.c
- Added image_t type
- Minor changes to cliprect_t structure
- Fixed minor bug in Clear functions (scaled down lfbsize according to rep stosX)
- Converted BMP file to PCX file
- Deleted BMP file and GIF file
- Tested on a PIII computer

Next up is demo3 which will be a graphics demo including filled rectangles (clipped), image blits (clipped), imaged loading (via PCX), simple pixel conversion (for loading images), and a general interface. With demo3, you will see how clipping a pixel differs from clipping a filled rectangle, and how it differs from clipping an image.

Attachments vbesrc.zip (32.61 KB)
 
0
 

Iret i just found this thread searching for information on VBE, and (though im on a mobile device and unable to read the source at this time) it seems awesome. Im in the same boat as the OP, trying to write an OS, and ive been looking for this information. Is there any chance you could do that tutorial you said youve wanted to do? It would be most appreciated by me and the many other people it will help (and im sure it will help many many people if its as detailed as your posts are). Thank you.

 
0
 

Is there any chance you could do that tutorial you said youve wanted to do?

When I complete these demos, definitely :)

 
0
 

I tested the VBE source in a virtual machine (VirtualBox) using FreeDOS. I dug up 2 computers, but they were 32-BPP.

So the 24-BPP clear function doesn't quite work, but I'm close. I converted Seg:Ofs real mode addresses to a linear address. It works under emulation, but doesn't work consistently on two old computers so I'll need to figure out a better way to access the Real Mode data. There may also be a miscalculation with TotalMemory, I multiplied by 64. Once I straighten out the Real Mode pointers, I will be able to verify the TotalMemory calculation.

The VBE code works flawlessly, it's based on tested code from a graphics library that I worked on a while back. The graphics code will work flawlessly. Sorry for the errors so far. I won't post anything else until the code is fully tested.

 
0
 

Thank you.

 
1
 

Just a quick update.

I've ironed out a couple of bugs, especially the available mode list being corrupted. Now, 2K of low memory is allocated: 1K for VBE Driver Info + 1K for Mode Info. Also, I rearranged the vbe_SetMode code a bit since for some reason 32-BPP modes didn't want to run.

Regarding the TotalMemory calculation:
- TotalMemory x 64 = Video Memory size in KB
- Total Memory x 65536 = Video Memory size in Bytes

I didn't realize until the previous release that 32-BPP modes don't run. I fixed that by setting the video mode first, then doing all the LFB set up after.

So far, 8/15/16/32-BPP modes work flawlessly. 24-BPP needs a minimal amount of work.

I don't really have a choice but to code 24-BPP under emulation. The demos have crashed where I needed them to under VirtualBox, which helps me find any bugs. When the 24-BPP code is stable under VirtualBox, it will be stable on hardware. I'm working on locating a video card that supports VBE 2.0, LFB, and has 24-BPP video modes.

 
0
 

Moderator: Please remove previous attachments in this thread with extensions C, H, and ZIP. They had bugs which could potentially cause confusion to readers of this thread.

Attached is the most recent source release. This release is fully tested, and obsoletes all previous releases I have attached. Kieran, hopefully this release will make up for my previous releases :/

To compile, simply run wmake from the VBE directory

The following have changed since the last release:
- Changed from DOS/4G stub to PMode/W stub in previous release makefile
- Changed from PMode/W to Causeway stub in current release makefile
- demo1 functions without error for 8/15/16/32-BPP VBE modes on real hardware, and under emulation
- demo1 functions without error for 24-BPP VBE modes under emulation, but should work flawlessly on real hardware (I am working on testing this and will follow up to confirm, when I eventually get a 24-BPP hardware set up)
- vbe_Init() now allocates 2K of low memory where 1K is for VBE Driver Info, and 1K is for VBE Mode Info
- demo2 available modes list is no longer corrupt
- Fixed vbe_SetMode() by re-arranging each major section such that the display mode is changed, the VBE selector is set up, and the VBE physical address is set up
- gfx_Clear24() implemented and tested
- gfx_FillRect24() implemented and tested
- Added stubs and partial functionality to draw/load images for next release
- Updated gfx_t structure to include FillRect and PutImage function pointers


I've decided to make two more releases before letting this thread rest:
- next: image loading, drawing and clipping in demo3
- last: generic API interfacing in demo4; self-sufficient demonstration for video mode changing, setting up the LFB, and drawing a pixel in demo5


After the last release, I will work on a tutorial and will follow up with a link.

Attachments vbesrc.zip (203.18 KB)
 
0
 

This stuff is amazing! I can't believe you have gone to this length to help someone :)

When you say:

The following have changed since the last release:
- Changed from DOS/4G stub to PMode/W stub in previous release makefile

Do you mean that you don't need DOS to run the code??

Thanks for all of the code. This is the best (although the only I've seen) tutorial on VESA. You could make a book and get some money from it ;)

Thanks iret!

 
0
 

This stuff is amazing! I can't believe you have gone to this length to help someone :)

No problem, I know what a pain it is to research VBE stuff (banked VBE included!).

Do you mean that you don't need DOS to run the code??

You actually do still need DOS, but now you don't need DOS/4GW :P PMode/W and Causeway are DOS Extender Stubs, which are embedded in the DOS Executable. So the executables will run standalone.

DOS was the only alternative to creating an OS (I'm not up to par for that yet :P).

Thanks for all of the code. This is the best (although the only I've seen) tutorial on VESA. You could make a book and get some money from it ;)

Thanks iret!

;)

 
0
 

You actually do still need DOS, but now you don't need DOS/4GW PMode/W and Causeway are DOS Extender Stubs, which are embedded in the DOS Executable. So the executables will run standalone.

DOS was the only alternative to creating an OS (I'm not up to par for that yet ).

I see, understandable ;)

I still need to learn a bit more about DOS. My skills have got a bit dusty (to say the least). I am sure I can adapt the code for my operating systems functions, or current lack of them ;)

Thanks again! :)

 
0
 

Hey iret,
I just wanted to thank you again for this. I know its months later, but i just rediscovered it and its helped me AGAIN. Haha.

Thanks

 
0
 

Hey iret,
I just wanted to thank you again for this. I know its months later, but i just rediscovered it and its helped me AGAIN. Haha.

Thanks

Cool :)

BTW, I haven't forgotten about the tutorial. I was stopped by a dumb bug in PCX loading (yeah.. I know), and then became really busy. Not sure exactly when, but I will pick this up again.

 
0
 

First, I know that this article has been dead for a while, but I'm not done yet :)

Still been really busy, but I needed a break so I'm on this again. Turns out the PCX bug was partially due to loading an 8-BPP file, when the file itself is 24-BPP. PCX is an obsolete and annoying format, but few others are as simple to decode (and still around).

I'll follow up when the next demo is ready, which will hopefully be within 2 weeks.

You
This article has been dead for over six months: Start a new discussion instead
Post:
Start New Discussion
Tags Related to this Article