From: Eric Rudd 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 Content-Type: text/plain Content-Transfer-Encoding: 7bit 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 . 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