delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp/2000/01/04/12:27:19

Message-ID: <F77915E7F086D31197F4009027CC81C917B595@probe-2.as-london.acclaim.com>
From: Shawn Hargreaves <SHargreaves AT acclaimstudios DOT co DOT uk>
To: djgpp AT delorie DOT com
Subject: Re: Allegro, VESA - help
Date: Tue, 4 Jan 2000 15:43:57 -0000
MIME-Version: 1.0
X-Mailer: Internet Mail Service (5.5.2650.21)
Reply-To: djgpp AT delorie DOT com

sl writes:
> I'm writting my own GFX lib and the VESA 1.2 spec is beginning to
> really piss me off :)

It's a great piece of literature :-) But don't take it too seriously:
a surprising number of production drivers don't follow it quite 
exactly, so even once you get your code working 'correctly', then you
have all the fun of trying to find workarounds for drivers that don't
agree with your definition of what 'correct' means :-)

> According to the VESA spec, Memory Windows can be moved by increments
> called WinGranularily. These windows move across Memory Banks.. Now,
> according to this model, I could have a memory window spanning multiple 
> banks and there is no indication that BankSize=WinGranularity*1024.. 

The modeinfo WinGranularity field is in Kb, so the granularity in
bytes is WinGranularity*1024. This is indeed not necessarily the same
as the total bank size, which is specified (again in Kb) by the 
WinSize field. In practice these days you will almost always find
that both fields are exactly 64kb, but some cards (particularly 
Cirrus) have 4k or 16k granularity and 64k banks, while others
(I think old Tridents) have 64k granularity and 128k banks), and old
ATI cards often had only 32k granularity and bank size. This is
certainly something that you need to handle.

> However, everywhere I look (included in DJGPP's sample VESA code and 
> Allegro itself) I see this assumption being made..

Certainly not in Allegro! What other sample code did you see it in?

In the VESA article from the djgpp User's Guide, I gave an example
pixel plotting function as:

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

      set_vesa_bank(bank_number);

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

That does indeed ignore the WinSize field, working entirely from the
WinGranularity value, but that's ok because it just always uses
whatever bank location comes closest to the pixel being drawn, ie.
the one that will give the smallest possible offset within the bank.
The only assumption being made here is that WinGranularity must
be smaller than WinSize, which obviously has to be true (if it wasn't,
there would be some parts of the screen that were impossible to
access).

The potential inefficiency in that code lies where banks overlap
(ie. WinGranularity is smaller than WinSize), so you may have several 
possible bank/offset combinations that can access the same pixel.
Choosing the smallest offset is fine for plotting a single pixel, but
would cause some redundant bank switches if you were filling a larger
shape that straddles several banks. Allegro handles this in a more
sophisticated way, precomputing a table of which bank to use for 
each scanline (see the _make_bitmap() function in graphics.c), but
even that is less efficient than if you considered each drawing 
primitive individually, and decided where to put the bank divisions
for each specific case. That gets hairy, though, so I didn't attempt
it.

Allegro actually makes another simplification of the banking system:
it requires that bank switches not occur in the middle of a scanline.
That hugely simplifies all the drawing code, and is no problem on
cards with overlapping banks, but it means that for cards where the
banks don't overlap, I have to fiddle with the screen dimensions to
avoid a switch coming in the wrong place. That's why on some cards,
even when you ask for a 640x480 screen, Allegro will actually set
a 1024 pixel wide virtual display. Wastes video memory for the sake
of much simpler and faster drawing code.

> Furthermore, according to the VESA specs, BankSize=0 under certain modes
> (640x400x8bit being one of them, which I am using to do my testing).

I don't have the 1.2 spec here to check, but the 2.0 spec doesn't say
that. It does say that WinGranularity is undefined if bit 0 of the
WinAttributes field is not set, which means that you aren't in a 
banked mode at all. But I've never seen that for anything other than
standard VGA resolutions, which you might as well set using stock
VGA calls: the Allegro VESA driver will fail to set such modes. Even
for something like 640x400, that would fit entirely into a single 64k
bank, you still need to switch banks if you want to access offscreen
video memory, eg. for page flipping. So these are still implemented
as banked modes: you just don't need to change the bank settings 
very often.

Another note while I'm here: watch out for the WinAAttributes and
WinBAttributes fields: these are important. You can always write
to Window A, but depending on their contents reading may come from
Window A, Window B, or both, and on some cards the read bank is
set individually (and may even be mapped at a different location 
in memory) to the write bank. Only a problem if you want to read 
data back from the screen, but a lot of VESA code gets this stuff 
wrong, which causes problems on cards with separate read/write banks.


	Shawn Hargreaves.

- Raw text -


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