Google Answers Logo
View Question
 
Q: Acessing VESA graphics via DJGPP, to run under WinXP ( No Answer,   4 Comments )
Question  
Subject: Acessing VESA graphics via DJGPP, to run under WinXP
Category: Computers > Programming
Asked by: gan-ga
List Price: $30.00
Posted: 25 Oct 2002 15:09 PDT
Expires: 02 Nov 2002 12:51 PST
Question ID: 89896
Preamble..

A novice C programmer, I'm trying to figure out how to use VESA
graphics, via the C language, using the DJGPP compiler, under Windows
XP.

I assembled the below code from the DJGPP website's VESA graphics help
page. When compiled using the 2.03 version of the compiler, it runs
absolutely fine on Windows 95, producing a 640 by 480 display of
randomly & evenly distributed pixels, with a short text message. Under
Windows XP, however, the pixel field is split into a series of
horizontal bands, and the text message doesn't appear.

If I recompile the code for higher resolutions again, say, 1024 by
768, the executable _still_ runs fine in 95, but gets worse in XP -
nothing but a black screen being displayed, with (on my monitor) a
seemingly monitor-produced warning 'invalid signal'.

I understand XP, 2000 & NT are similar in that none are DOS-based, and
that they also treat memory protection differently than the 9x series
of Microsoft OSes. For instance, when programming VGA mode 13hex
(see: http://www.brackeen.com/home/vga/basics.html ), I discovered I
couldn't access video memory directly with 'near pointers' - I had to
change to using 'far pointers' to get things working under XP, that
previously were ok under '9x.

The code I've posted below represents my unsuccessful attempts so far,
to get pixel-plotting to work under VESA on XP, using DJGPP. Can you
provide links to information as to how I can modify my code to work
under XP, or even suggest a specific change in the code?

Thanks.






/* assembled from "Guide: VESA graphics modes" at:  */
/* http://www.delorie.com/djgpp/doc/ug/graphics/vesa.html */










#include <stdio.h>
#include <dos.h>
#include <math.h>
#include <pc.h>
#include <keys.h>
#include <sys/farptr.h>
#include <go32.h>
#include <dpmi.h>
#define SCREEN_WIDTH        640
#define SCREEN_HEIGHT       480
#define NUM_COLORS          256

int i;
int x;
int y;
int color;

/* make sure that a VESA driver is present, and retrieve a copy of the
VESA information structure */

   typedef struct VESA_INFO
   { 
      unsigned char  VESASignature[4]     __attribute__ ((packed));
      unsigned short VESAVersion          __attribute__ ((packed));
      unsigned long  OEMStringPtr         __attribute__ ((packed));
      unsigned char  Capabilities[4]      __attribute__ ((packed));
      unsigned long  VideoModePtr         __attribute__ ((packed));
      unsigned short TotalMemory          __attribute__ ((packed));
      unsigned short OemSoftwareRev       __attribute__ ((packed));
      unsigned long  OemVendorNamePtr     __attribute__ ((packed));
      unsigned long  OemProductNamePtr    __attribute__ ((packed));
      unsigned long  OemProductRevPtr     __attribute__ ((packed));
      unsigned char  Reserved[222]        __attribute__ ((packed));
      unsigned char  OemData[256]         __attribute__ ((packed));
   } VESA_INFO;



/* call VESA function 0x4F00 to fill it with information about the
current driver. */
/*Because VESA was designed as a real mode API for use by 16 bit
programs, */
/*this data must be transferred via a buffer in conventional memory
with the */
/*dosmemput() and dosmemget() functions: see the DPMI chapter for
details of this. */
/*The function below will copy the VESA driver information into a
global VESA_INFO */
/*structure, returning zero on success or -1 if anything goes wrong
(ie. no driver is available). */



 VESA_INFO vesa_info;


   int get_vesa_info()
   {
      __dpmi_regs r;
      long dosbuf;
      int c;

      /* use the conventional memory transfer buffer */
      dosbuf = __tb & 0xFFFFF;

      /* initialize the buffer to zero */
      for (c=0; c<sizeof(VESA_INFO); c++)
	 _farpokeb(_dos_ds, dosbuf+c, 0);

      dosmemput("VBE2", 4, dosbuf);

      /* call the VESA function */
      r.x.ax = 0x4F00;
      r.x.di = dosbuf & 0xF;
      r.x.es = (dosbuf>>4) & 0xFFFF;
      __dpmi_int(0x10, &r);

      /* quit if there was an error */
      if (r.h.ah)
	 return -1;

      /* copy the resulting data into our structure */
      dosmemget(dosbuf, sizeof(VESA_INFO), &vesa_info);

      /* check that we got the right magic marker value */
      if (strncmp(vesa_info.VESASignature, "VESA", 4) != 0)
	 return -1;

      /* it worked! */
      return 0;
   }










/*Information about a particular mode can be obtained in a similar way
to the main VESA information block,
 but using function 0x4F01 with a different structure, eg: */

   typedef struct MODE_INFO
   {
      unsigned short ModeAttributes       __attribute__ ((packed));
      unsigned char  WinAAttributes       __attribute__ ((packed));
      unsigned char  WinBAttributes       __attribute__ ((packed));
      unsigned short WinGranularity       __attribute__ ((packed));
      unsigned short WinSize              __attribute__ ((packed));
      unsigned short WinASegment          __attribute__ ((packed));
      unsigned short WinBSegment          __attribute__ ((packed));
      unsigned long  WinFuncPtr           __attribute__ ((packed));
      unsigned short BytesPerScanLine     __attribute__ ((packed));
      unsigned short XResolution          __attribute__ ((packed));
      unsigned short YResolution          __attribute__ ((packed));
      unsigned char  XCharSize            __attribute__ ((packed));
      unsigned char  YCharSize            __attribute__ ((packed));
      unsigned char  NumberOfPlanes       __attribute__ ((packed));
      unsigned char  BitsPerPixel         __attribute__ ((packed));
      unsigned char  NumberOfBanks        __attribute__ ((packed));
      unsigned char  MemoryModel          __attribute__ ((packed));
      unsigned char  BankSize             __attribute__ ((packed));
      unsigned char  NumberOfImagePages   __attribute__ ((packed));
      unsigned char  Reserved_page        __attribute__ ((packed));
      unsigned char  RedMaskSize          __attribute__ ((packed));
      unsigned char  RedMaskPos           __attribute__ ((packed));
      unsigned char  GreenMaskSize        __attribute__ ((packed));
      unsigned char  GreenMaskPos         __attribute__ ((packed));
      unsigned char  BlueMaskSize         __attribute__ ((packed));
      unsigned char  BlueMaskPos          __attribute__ ((packed));
      unsigned char  ReservedMaskSize     __attribute__ ((packed));
      unsigned char  ReservedMaskPos      __attribute__ ((packed));
      unsigned char  DirectColorModeInfo  __attribute__ ((packed));
      unsigned long  PhysBasePtr          __attribute__ ((packed));
      unsigned long  OffScreenMemOffset   __attribute__ ((packed));
      unsigned short OffScreenMemSize     __attribute__ ((packed));
      unsigned char  Reserved[206]        __attribute__ ((packed));
   } MODE_INFO;


   MODE_INFO mode_info;


   int get_mode_info(int mode)
   {
      __dpmi_regs r;
      long dosbuf;
      int c;

      /* use the conventional memory transfer buffer */
      dosbuf = __tb & 0xFFFFF;

      /* initialize the buffer to zero */
      for (c=0; c<sizeof(MODE_INFO); c++)
	 _farpokeb(_dos_ds, dosbuf+c, 0);

      /* call the VESA function */
      r.x.ax = 0x4F01;
      r.x.di = dosbuf & 0xF;
      r.x.es = (dosbuf>>4) & 0xFFFF;
      r.x.cx = mode;
      __dpmi_int(0x10, &r);

      /* quit if there was an error */
      if (r.h.ah)
	 return -1;

      /* copy the resulting data into our structure */
      dosmemget(dosbuf, sizeof(MODE_INFO), &mode_info);

      /* it worked! */
      return 0;
   }

















/*
information can easily be obtained from the main VESA information
block.
This contains a list of all the possible modes that are supported by
the driver,
so you can write a little routine that will loop through all these
modes,
retrieving information about each one in turn until it finds the one
that
you are looking for. For example:
*/







   int find_vesa_mode(int w, int h)
   {
      int mode_list[256];
      int number_of_modes;
      long mode_ptr;
      int c;

      /* check that the VESA driver exists, and get information about
it */
      if (get_vesa_info() != 0)
	 return 0;

      /* convert the mode list pointer from seg:offset to a linear
address */
      mode_ptr = ((vesa_info.VideoModePtr & 0xFFFF0000) >> 12) + 
		  (vesa_info.VideoModePtr & 0xFFFF);

      number_of_modes = 0;

      /* read the list of available modes */
      while (_farpeekw(_dos_ds, mode_ptr) != 0xFFFF) {
	 mode_list[number_of_modes] = _farpeekw(_dos_ds, mode_ptr);
	 number_of_modes++;
	 mode_ptr += 2;
      }

      /* scan through the list of modes looking for the one that we
want */
      for (c=0; c<number_of_modes; c++) {

	 /* get information about this mode */
	 if (get_mode_info(mode_list[c]) != 0)
	    continue;

	 /* check the flags field to make sure this is a color graphics mode,
	  * and that it is supported by the current hardware */
	 if ((mode_info.ModeAttributes & 0x19) != 0x19)
	    continue;

	 /* check that this mode is the right size */
	 if ((mode_info.XResolution != w) || (mode_info.YResolution != h))
	    continue;

	 /* check that there is only one color plane */
	 if (mode_info.NumberOfPlanes != 1)
	    continue;

	 /* check that it is a packed-pixel mode (other values are used for
	  * different memory layouts, eg. 6 for a truecolor resolution) */
	 if (mode_info.MemoryModel != 4)
	    continue;

	 /* check that this is an 8-bit (256 color) mode */
	 if (mode_info.BitsPerPixel != 8)
	    continue;

	 /* if it passed all those checks, this must be the mode we want! */
	 return mode_list[c];
      }

      /* oh dear, there was no mode matching the one we wanted! */
      return 0; 
   }











/* ready to actually select a VESA graphics mode and start
drawing things onto the screen. This is done by calling function
0x4F02 with a
mode number in the BX register, eg: */


   int set_vesa_mode(int w, int h)
   {
      __dpmi_regs r;
      int mode_number;

      /* find the number for this mode */
      mode_number = find_vesa_mode(w, h);
      if (!mode_number)
	 return -1;

      /* call the VESA mode set function */
      r.x.ax = 0x4F02;
      r.x.bx = mode_number;
      __dpmi_int(0x10, &r);
      if (r.h.ah)
	 return -1;

      /* it worked! */
      return 0;
   }









/* The SVGA video memory is located at physical address 0xA0000, the
same as in mode 13h,
but there is one small problem with this: there simply isn't enough
room for it all
to fit there! The original DOS memory map only included space for 64k
of video memory
between 0xA0000 and 0xB0000, which is fine for a 320x200 resolution
but nowhere near
enough for a 640x480 screen (that takes up 300k of framebuffer space,
and higher
resolutions need even more). The SVGA hardware designers solved this
problem by
using a banked memory architecture, where the 64k VGA memory region is
treated as
a sliding window onto the larger expanse of real video memory inside
your card.
To access an arbitrary location on the SVGA screen you must first call
VESA function
0x4F05 to tell it which bank you want to use, and then write to a
memory location
within that bank. You can set the bank with the function: */





   void set_vesa_bank(int bank_number)
   {
      __dpmi_regs r;

      r.x.ax = 0x4F05;
      r.x.bx = 0;
      r.x.dx = bank_number;
      __dpmi_int(0x10, &r);
   }

/* Using this, a simple putpixel function can be implemented as: */

   void putpixel_vesa_640x480(int x, int y, int color)
   {
      int address = y*640+x;
      int bank_size = mode_info.WinGranularity*640;
      int bank_number = address/bank_size;
      int bank_offset = address%bank_size;

      set_vesa_bank(bank_number);

      _farpokeb(_dos_ds, 0xA0000+bank_offset, color);
   }













main()
{
printf("Test routine for figuring out VESA graphics in Win 9x/XP, 640
by 480 res and up.\n");
printf("Compiling using DJGPP v2.03\n");
printf("\nPress a key to begin.\n\n");
getkey();
if (get_vesa_info() == -1)
   {
   printf("\nFailed to get VESA info.\nPress a key to exit.\n");
   getkey();
   exit(-1);
   }
   else
   {
   if (get_vesa_info() == 0)
      {
      printf("\nFound VESA info.\nPress a key to continue.\n");
      getkey();
      if (find_vesa_mode(640, 480) != 0)
         {
         printf("\nFound 640 by 480 mode.\nPress a key for
demo...\n");
         printf("\nYou should see a uniform field of pixels, and an
exit text message.\n");
         printf("\nIf no exit message appears, just hit any key to get
out....\n");
         getkey();
         set_vesa_mode(640, 480);
         for(i=0;i<10000;i++)
            {
            x=rand()%SCREEN_HEIGHT;
            y=rand()%SCREEN_WIDTH;
            color=rand()%NUM_COLORS;
            putpixel_vesa_640x480(x,y,color);
            }
         printf("\nOK. Press a key to exit\n");
         getkey();
         exit(-1);
         }
         else
         {
         printf("\nFailed to find 640 by 480 mode.\nPress a key to
exit.\n");
         getkey();
         exit(-1);
         }
      }
   }
}
Answer  
There is no answer at this time.

Comments  
Subject: Re: Acessing VESA graphics via DJGPP, to run under WinXP
From: arcadesdude-ga on 25 Oct 2002 16:00 PDT
 
Have you tried running the program in 95/98 Compatibility mode?
It's probably not as simple as that, but you never know...
Subject: Re: Acessing VESA graphics via DJGPP, to run under WinXP
From: gan-ga on 25 Oct 2002 16:36 PDT
 
Arcadesdude-ga, I tried your suggestion, but no, still the same
display. The compatibility settings I tried were Windows 95 / 256
colours.

Thanks for your ideas :)
Subject: Re: Acessing VESA graphics via DJGPP, to run under WinXP
From: davidmaymudes-ga on 25 Oct 2002 17:41 PDT
 
Have you considered using DirectDraw instead?  I'm pretty sure you'll
have a hard time getting this to work under Windows NT/2000/XP.  In
general, DOS programs that try to access hardware directly don't tend
to work on WinXP.
Subject: Re: Acessing VESA graphics via DJGPP, to run under WinXP
From: majortom-ga on 25 Oct 2002 18:59 PDT
 
I haven't tried DJGPP in years and years, so I installed it on my XP
box
just to see what would happen with your code. My experience was even
worse than yours; I got the garbled display and no keystroke other
than alt-ENTER would get me out again. 

I have found conflicting claims on the web; some say VESA is much
better
in XP than in NT or 2K, others repeat the conventional wisdom that DOS
emulation is not the strong point of any NT-descended OS (NT, 2K, XP).
I suspect that the deciding issue may be the VESA support available
for your particular video hardware in XP. Mine has less than yours!
Attempts to run 'vgatest.exe', for example, succeed only for non-VESA,
vanilla VGA capabilities. Other XP users report varying degrees of
better luck with it.

Good luck to you.

Important Disclaimer: Answers and comments provided on Google Answers are general information, and are not intended to substitute for informed professional medical, psychiatric, psychological, tax, legal, investment, accounting, or other professional advice. Google does not endorse, and expressly disclaims liability for any product, manufacturer, distributor, service or service provider mentioned or any opinion expressed in answers or comments. Please read carefully the Google Answers Terms of Service.

If you feel that you have found inappropriate content, please let us know by emailing us at answers-support@google.com with the question ID listed above. Thank you.
Search Google Answers for
Google Answers  


Google Home - Answers FAQ - Terms of Service - Privacy Policy