Message-ID: From: Shawn Hargreaves 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) Content-Type: text/plain; charset="iso-8859-1" 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.