delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp/1996/09/30/23:27:43

From: Eric Rudd <rudd AT cyberoptics DOT com>
Newsgroups: comp.os.msdos.djgpp
Subject: Linear Frame Buffer Programming
Date: 30 Sep 1996 16:13:00 GMT
Organization: CyberOptics Corp
Lines: 95
Message-ID: <52oric$hop@hagar.cyberoptics.com>
NNTP-Posting-Host: rudd.cyberoptics.com
Mime-Version: 1.0
To: djgpp AT delorie DOT com
DJ-Gateway: from newsgroup comp.os.msdos.djgpp

There seem to be a lot of DJGPP users interested in writing directly to
video memory, and I am one of them.  For most users, SciTech Software's
UniVBE is probably the best solution, but there are copyright issues if I
place my programs up on the intranet at work, as well as the nuisance of
encapsulating each program within a batch file which loads the TSR,
launches the program, then finally unloads the TSR.  This whole issue will
eventually become moot, when cards with built-in VBE 2.0 support become
more prevalent, but for now the problems remain.

So I wrote a set of low-level routines which enable the linear frame
buffer and switch to the appropriate video mode.  The interface is similar
to the old "simple graphics library," LIBGR, from DJGPP v1.xx.  The
writing of the driver for my ET4000/W32p-based card at home was fairly
easy; the driver for the S3 cards we use at work was a bear, especially
enabling the 8-bit DAC mode, but I have finally arrived at reasonable
functionality.  I would make the code available, except that it's such a
brittle hack it's not really presentable in its present form.  I based
most of the card-specific code on the information that I gleaned from Finn
Thoergersen's VGADOC4B, with some additional information from Dietmar
Meschede's "S3UNIT3.ZIP":

ftp://x2ftp.oulu.fi/pub/msdos/programming/pmode/s3unit3.zip

I have several outstanding questions regarding this type of programming:

1. I am using near pointers to access the video memory.  I had been given
the impression that this effectively disables memory protection, but I
found that if I wrote so much as one byte beyond the limit requested from
DPMI, I got a page fault dump, which indicates that, at least on my
machine, memory protection is not entirely disabled.  I welcome this
protection, but am puzzled as to why it exists.  Short excerpts of the
relevant portions of the code, which is adapted from Charles W Sandmann's
VBETEST.C, follow:

   int _crt0_startup_flags = _CRT0_FLAG_NEARPTR | _CRT0_FLAG_NONMOVE_SBRK;
   .
   .
   .
   info.size = width*height*BytesPerPixel;
   info.address = (int) PhysBasePtr;
   if (__dpmi_physical_address_mapping(&info) == -1) {
      return 2;   /* Physical mapping of address PhysBasePtr failed. */
   }
   VideoBase = (void *) info.address;  /* Updated by above call */
   (char *) VideoBase += __djgpp_conventional_base;

I then access video memory by references like

   ((char *) VideoBase)[offset] = GrayValue;

2. On my home computer, if a program bombs while the linear frame buffer
is enabled, the DJGPP cleanup routines (wherever they are) do not reset
the video mode to anything useful, probably due to a deficiency in the
card's BIOS.  Thus, the dump goes off into the ether, and I have to re-run
the program with REDIR.EXE just in order to capture the error output. This
is manifestly inconvenient, and I wonder how best to deal with this
problem. (After a couple of such bombs, I got wise and wrote a short
command-line utility to reset the video mode, which I invoke by blindly
typing it in, as the screen flashes garbage.  This at least saves me from
re-booting.)  I have thought of three solutions, besides the obvious one
(get a new video card):

   1. Patch the cleanup code, so that it properly resets the video mode. 
      The problem with this approach is that I have no idea where the
      cleanup source code is, and the patch would probably have to be
      re-written for each new release of DJGPP.

   2. Write an interrupt-service routine that traps the calls to the video
      BIOS and performs the mode switch.  The problem with this, beyond the
      general problems of writing interrupt-service routines, is that I
      would have to deal with *every* BIOS call that came through.

   3. Write bullet-proof code that never crashes.  Alas, I'm a mere
      mortal, and this seems a bit beyond my reach.  Besides, the most
      bullet-proof code can be made to bomb simply by hitting
      <CNTL-BREAK>.

3. After allocating physical address space with

   __dpmi_physical_address_mapping(__dpmi_meminfo *_info);

it would seem logical to free it before exiting the program, by calling

   __dpmi_free_physical_address_mapping(__dpmi_meminfo *_info);

but I find this function listed only in the DPMI 1.0 spec, in spite of the
fact that the documentation in the DJGPP v2.00 file DPMI.H seems to
suggest it exists under DPMI 0.9.  I am calling it anyway, and there seem
to be no ill effects, even in a DOS box under Windows, but I don't know if
I am doing the right thing.

Has anyone out there dealt successfully with these problems?

-Eric Rudd

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019