VOGONS


VESA mode programming from real mode

Topic actions

Reply 40 of 77, by megatron-uk

User metadata
Rank Oldbie
Rank
Oldbie

Looks like my ET4000AX card doesn't have the VESA BIOS extensions 🙁

By default on my 286 system I get my warning screen about no supported VBE found and my code won't load (as expected on a non-VESA card).

If I load TL1VESA.COM (an ET3000/ET4000 VESA TSR) it loads and the MSDOS logo and initial progress bar and font display perfectly (hurrah!) but querying the vbe capabilities field seems to indicate that the DAC is fixed at 6bit. That could be an artifact of the TSR however, as my card has the Sierra highcolour/truecolour DAC chip.

I'll give my Trident card a try next.

My collection database and technical wiki:
https://www.target-earth.net

Reply 41 of 77, by megatron-uk

User metadata
Rank Oldbie
Rank
Oldbie

Ha! The Trident 9000b appears to have a VESA compatible BIOS - it runs without a TSR or univbe etc.

Both cards display the various images and UI elements correctly:

IMG20210202120808.jpg
Filename
IMG20210202120808.jpg
File size
160.26 KiB
Views
956 views
File comment
Tseng - with TL1VESA.COM
File license
CC-BY-4.0

With no VESA extensions present, the Tseng card gets my error text upon starting the application:

IMG20210202120727.jpg
Filename
IMG20210202120727.jpg
File size
237.23 KiB
Views
956 views
File comment
Tseng - no VESA
File license
CC-BY-4.0

The TL1VESA.COM TSR reports the following information and modes in the logging output as the application starts:

src/main.c.204	 Now initialising VESA graphics mode
src/gfx.c.63 gfx_Init() Initalising gfx mode
src/vesa.c.90 VESA BIOS queried successfully!
src/vesa.c.265 vesa_PrintVBEInfo() VESA BIOS information follows
VBE Signature: VESA˜
VBE Vendor: Tseng Labs ET4000
VBE Version: 258
SW Version: 23610
Vendor: 25409
Product: 28271
Version: 29285
Capabilities: 0
DAC Type: Fixed, 6bit
Total RAM: 1024KB
src/vesa.c.280 vesa_PrintVBEInfo() End of VESA BIOS information
----------
src/vesa.c.291 vesa_PrintVBEModes() VESA mode list follows
Mode 0: 100h
Mode 1: 101h
Mode 2: 102h
Mode 3: 103h
Mode 4: 104h
Mode 5: 105h
Mode 6: 106h
Mode 7: 108h
Mode 8: 109h
Mode 9: 10ch
Mode 10: 22h
Mode 11: 24h
Mode 12: 2ah
Mode 13: 2dh
Mode 14: 10dh
Mode 15: 5dh
Mode 16: 110h
Mode 17: 5fh
Mode 18: 113h
Mode 19: 10eh
Mode 20: 6dh
Mode 21: 111h
Mode 22: 6fh
Mode 23: 114h
Mode 24: 112h
src/vesa.c.300 vesa_PrintVBEModes() Found 25 VESA modes

The Trident card with the built-in VESA support reports the following:

src/main.c.204	 Now initialising VESA graphics mode
src/gfx.c.63 gfx_Init() Initalising gfx mode
src/vesa.c.90 VESA BIOS queried successfully!
src/vesa.c.265 vesa_PrintVBEInfo() VESA BIOS information follows
VBE Signature: VESAP
VBE Vendor: Copyright 1988-1991 TRIDENT MICROSYSTEMS INC.
VBE Version: 258
SW Version: 0
Vendor: 0
Product: 0
Version: 0
Capabilities: 0
DAC Type: Fixed, 6bit
Total RAM: 512KB
src/vesa.c.280 vesa_PrintVBEInfo() End of VESA BIOS information
----------
src/vesa.c.291 vesa_PrintVBEModes() VESA mode list follows
Mode 0: 170h
Mode 1: 171h
Mode 2: 100h
Mode 3: 101h
Mode 4: 103h
Mode 5: 104h
Mode 6: 102h
Mode 7: 6ah
Mode 8: 108h
Mode 9: 109h
Mode 10: 10ah
Mode 11: 10bh
Mode 12: 10ch
src/vesa.c.300 vesa_PrintVBEModes() Found 13 VESA modes

There's also a difference in behaviour in attempting to change the DAC mode via INT10 (both report 6bpp, fixed, but I thought it would be an interesting exercise to see what happens if I blindly attempt to programme it for 8bpp).

First, here's the Tseng card:

src/gfx.c.156	 gfx_Init() VESA BIOS indicates VGA DAC is fixed at 6bpp
src/gfx.c.157 gfx_Init() ... but let's try changing it anyway!
src/vesa.c.147 vesa_SetDAC() Setting VESA DAC mode 8bpp
src/vesa.c.164 vesa_SetDAC() Successfully set VESA DAC mode 8bpp
src/vesa.c.177 vesa_GetDAC() Checking VESA DAC mode for 8bpp
src/vesa.c.194 vesa_GetDAC() VESA DAC mode is 6bpp, this is WRONG!

It lets me call the INT10 function to set the DAC depth (and the return value in AX indicates success), but on re-reading the value back it remains at 6bpp.

The Trident card responds differently:

src/gfx.c.156	 gfx_Init() VESA BIOS indicates VGA DAC is fixed at 6bpp
src/gfx.c.157 gfx_Init() ... but let's try changing it anyway!
src/vesa.c.147 vesa_SetDAC() Setting VESA DAC mode 8bpp
src/vesa.c.158 vesa_SetDAC() Error, Unable to set VESA DAC mode 8bpp [return code 0x4f08]
src/gfx.c.162 gfx_Init() Unable to switch VGA DAC, defaulting to 6bpp

The code to set the DAC depth fails, as indicated by the value 0x4F08 returned in AX.

(Setting the VGA DAC to 8bpp) remains an interesting thought exercise until I can get a machine together where I can actually test my code path. I've got a PVI-486SP3 with the choice of a Voodoo3, Trio64 or Millenium II, so I'll have to fire that up to check that it works as expected on a switchable 6/8bpp VGA DAC.

The big positive is that my code works on real hardware (and my 286, at that!), so I'm fairly pleased so far.

My collection database and technical wiki:
https://www.target-earth.net

Reply 42 of 77, by megatron-uk

User metadata
Rank Oldbie
Rank
Oldbie

It's now almost to the point of working:

https://www.youtube.com/watch?v=tcPCqSUIEaY

- The background UI bitmap is copy-pasted from the PC-98 version, hence the PC9801 logo in the bottom right.
- No input code yet, so as soon as the menu interface is built and the browser pane populated I'm just doing a return();
- All of the small icons, checkboxes, pre-formatted text etc is loaded entirely in to base 640KB. Larger assets like the default UI background, scroll window backgrounds etc just have their headers loaded and then re-read from the disk, line-by-line as the page is refresh and redrawn. I've yet to see what the performance for this is like on my 286.

My collection database and technical wiki:
https://www.target-earth.net

Reply 43 of 77, by megatron-uk

User metadata
Rank Oldbie
Rank
Oldbie

Here's the current state:

progress4.png
Filename
progress4.png
File size
61.24 KiB
Views
938 views
File comment
Main UI and game selector pane
File license
CC-BY-4.0

Metadata loading works - any games that the application scrapes can also have a metadata file (launch.dat) in their directory, this is a simple ini-style file and can have the following entries:

[default]
name=Advanced Power Dolls 2
developer=Kogado Studio Inc.
midi_mpu=0
midi_serial=1
year=1996
genre=Strategy
images=cover.bmp,screen1.bmp,screen2.bmp,box.bmp
series=Power Dolls
start=game.exe
alt_start=config.exe

There's some minor graphical glitches in the output - I think I still have some drawing primitives (box/line/filled, etc) that are not cast to the correct integer types, but certainly all of the bitmap and bitmap font stuff is working spot on.

Next up is replacing the PC-98 specific keyboard handling with IBM PC alternatives. I don't imagine there will be much to change though.

My collection database and technical wiki:
https://www.target-earth.net

Reply 44 of 77, by jmarsh

User metadata
Rank Oldbie
Rank
Oldbie
megatron-uk wrote on 2021-02-02, 12:46:
[…]
Show full quote
src/vesa.c.147	 vesa_SetDAC() Setting VESA DAC mode 8bpp
src/vesa.c.164 vesa_SetDAC() Successfully set VESA DAC mode 8bpp

Does the call to set the palette width actually return 8 in BH? The standard says the call is still allowed to succeed if the requested width is higher than possible, just that the hardware will use the closest possible value (which will be returned in register BH).

I could probably add setting the palette width to DOSBox, it's already a variable but is always assigned a value of 6 with no code hooked up to adjust it.

Reply 45 of 77, by megatron-uk

User metadata
Rank Oldbie
Rank
Oldbie

I can certainly check that out. I'll try reading the value of BH when the call returns....

Edit: I can confirm that BH=6 after the following:

r.x.ax = 0x4F08;
r.h.bl = 0x00;
r.h.bh = 8;
int86(0x10, &r, &r);

AX=0x004F, indicating success, but clearly the hardware (or the VESA TSR in use by the Tseng Labs card) is changing it to 6bpp. The Trident card acts different, as the call fails; it does not return 0x004F.

I would dearly love to know where my long-lost CL-GD5428 got to in the last 6 years, as that would be another ISA card to test with. I can try some PCI cards (Trio, Virge, Millenium etc) on my 486, but that will take a day or two to clear out space and set it up.

My collection database and technical wiki:
https://www.target-earth.net

Reply 46 of 77, by pan069

User metadata
Rank Oldbie
Rank
Oldbie
megatron-uk wrote on 2021-02-02, 16:48:

I would dearly love to know where my long-lost CL-GD5428 got to in the last 6 years, as that would be another ISA card to test with.

I've got the VLB version of that card but unfortunately not in a position to test as everything is stored away atm 🙁

Reply 47 of 77, by Grzyb

User metadata
Rank Oldbie
Rank
Oldbie
megatron-uk wrote on 2021-02-02, 12:13:

If I load TL1VESA.COM (an ET3000/ET4000 VESA TSR) it loads and the MSDOS logo and initial progress bar and font display perfectly (hurrah!) but querying the vbe capabilities field seems to indicate that the DAC is fixed at 6bit. That could be an artifact of the TSR however, as my card has the Sierra highcolour/truecolour DAC chip.

HiColor doesn't imply that the DACs are 8-bit wide.
See eg. the Sierra HiColor RAMDAC series: SC11482 and SC11483 have 6-bit DACs, only the SC11484 has 8-bit.

TrueColor RAMDACs all have 8-bit DACs, of course, but I wouldn't be sure if the full width is always available in the palette modes.

Żywotwór planetarny, jego gnijące błoto, jest świtem egzystencji, fazą wstępną, i wyłoni się z krwawych ciastomózgowych miedź miłująca...

Reply 48 of 77, by megatron-uk

User metadata
Rank Oldbie
Rank
Oldbie

Sorry, it's a MUSIC MU9C4910, which is supposed to be 15/16/24bit:

IMG20210202214745.jpg
Filename
IMG20210202214745.jpg
File size
202.85 KiB
Views
888 views
File license
CC-BY-4.0

Anyway, it's not a major issue. Palette setting, whether 6bpp or 8bpp is working 'good enough'; it might be interesting to visit the possibility of 15/16bit modes in the future but it's not a priority right now (and I hate to think about throwing about twice the amount of pixel data in 'hi res' on a 286).

My collection database and technical wiki:
https://www.target-earth.net

Reply 49 of 77, by megatron-uk

User metadata
Rank Oldbie
Rank
Oldbie

Input now works, so I can scroll through the list of scraped games. Image loading of 8bpp bitmap files as listed in each games metadata file are also loaded,

Here's a real example of a screenshot as displayed in the interface for the title '3D Demon' (it's the first game in my folder, alphabetically, so its just easier to test metadata and image loading from the first item in the list - yes, yes, I know it's from BASS, but it's the first example I had at hand):

progress5.png
Filename
progress5.png
File size
151.62 KiB
Views
880 views
File license
CC-BY-4.0

However, compared to the performance on the PC-98, it's slow. Redraws of the browser pane (basically, any time you move the cursor) are excruciating... you can't just tap-tap-tap the up and down cursor keys; it's more like tap (1s), tap (1s) tap......

I'll have to do drop some timers in so that I can see where the bottleneck is.

Oh, and those issues I thought were gfx primitives operations going wrong aren't (the four thin horizontal lines in the image) - I think they are artifacts of the copy to the VGA memory windows since they seem to be at the end of each 64k section of the display. I suspect my logic isn't quite correct.

My collection database and technical wiki:
https://www.target-earth.net

Reply 50 of 77, by carlostex

User metadata
Rank l33t
Rank
l33t

OMG this is the answer to my prayers!! A DOS launcher that runs on DOS, loads metadata and shows screenshots!

A few suggestions:

- Allow to sort/filer by developer, year, genre, etc..;
- Allow for a game box cover screenshot as well (mobygames is a great source for these), thumbnails are tiny, not exceeding 10kb;
- Support at least 1000 games on the database;
- Option to run game and run setup;
- Option to prompt for parameters before game launch;

Reply 51 of 77, by megatron-uk

User metadata
Rank Oldbie
Rank
Oldbie
carlostex wrote on 2021-02-02, 23:17:
- Allow to sort/filer by developer, year, genre, etc..; - Allow for a game box cover screenshot as well (mobygames is a great s […]
Show full quote

- Allow to sort/filer by developer, year, genre, etc..;
- Allow for a game box cover screenshot as well (mobygames is a great source for these), thumbnails are tiny, not exceeding 10kb;
- Support at least 1000 games on the database;
- Option to run game and run setup;
- Option to prompt for parameters before game launch;

In order:

1. Genre and "game series" filtering is already in and working. Publisher and year would be trivial enhancements to add.

2. Already done.

3. Memory is the only limit. I need a way of counting available free memory while it is running, but each game 'object' in ram is a few hundred bytes, so I'd say at least 500 would be doable. My PC98 setup had about 300 titles in mostly the same codebase, but it was in protected mode and not hamstrung by 640k.

4. Already done. Choice of two start commands, defined in each games metadata file.

5. Hmmm... I did think about this, since the pc98 and x68k are very similar in terms of games with arguments to start. What most of those users seem to have settled on is writing a "start.bat" with the exe and any flags needed. Text entry in the interface is doable, but another world of complexity.

My collection database and technical wiki:
https://www.target-earth.net

Reply 52 of 77, by carlostex

User metadata
Rank l33t
Rank
l33t
megatron-uk wrote on 2021-02-02, 23:29:

3. Memory is the only limit. I need a way of counting available free memory while it is running, but each game 'object' in ram is a few hundred bytes, so I'd say at least 500 would be doable. My PC98 setup had about 300 titles in mostly the same codebase, but it was in protected mode and not hamstrung by 640k.

Each 'object' takes a few hundred bytes? Let's say each one is 333 bytes, you can fit 3 games in 1KB. Of course this depends how much RAM the rest of the program takes, and of course the actual size of each 'object', but yeah i think you should be able to do more than 500. Whatever above 500 is possible would be nice.

David Jason Carr's Launchbox was programmed in VisualBasic, which of course itself is a hog of a programming language and his program does around 330 games before crapping out. Your program is more complex, and so is the metadata too, but C is much more effective than VisualBasic, so you should win there. Some inline assembler would probably help making the program more efficient as far as RAM usage and speed too. I have no idea how competent those C compilers for DOS are.

Reply 53 of 77, by megatron-uk

User metadata
Rank Oldbie
Rank
Oldbie

This is the struct that defines a game:

typedef struct gamedata {
int gameid; // Unique ID for this game - assigned at scan time
char drive; // Drive letter
char path[65]; // Full drive and path name; e.g. A:\Games\FinalFight
char name[MAX_STRING_SIZE]; // Just the directory name; e.g. FinalFight
int has_dat; // Flag to indicate __launch.dat was found in the game directory
struct gamedata *next; // Pointer to next gamedata entry
} gamedata_t;

There's then a linked-list of all the games scraped from disk and created as one of those gamedata objects. The currently selected game may, or may not have metadata also available, which is then represented as:

typedef struct launchdat {
char realname[MAX_STRING_SIZE]; // A 'friendly' name to display the game as, instead of just the directory name
char genre[MAX_STRING_SIZE]; // A string to represent the genre, in case we want to filter by genre
int year; // Year the game was released
int midi; // Supports MIDI out
int midi_serial; // Supports MIDI serial out
char series[MAX_STRING_SIZE]; // Series name; e.g. Gradius, Streetfighter, etc.
char publisher[MAX_STRING_SIZE]; // The name of the publisher
char developer[MAX_STRING_SIZE]; // The name of the developer
char start[MAX_FILENAME_SIZE]; // Name of the main start file
char alt_start[MAX_FILENAME_SIZE]; // Name of an alternative start file (e.g a config utility)
char images[IMAGE_BUFFER_SIZE]; // String containing all the image filenames
} launchdat_t;

But, only one of those is loaded at a time. Same goes for any artwork/boxart; only one is loaded at a time. So as long as things don't go too crazy in terms of size of the exe file (it's ~360KB at present, including 256KB of data pre-allocating the video buffer) and don't load too many more artwork assets into memory (I have perhaps 60KB loaded at the moment - icons, buttons etc), there's probably ~200KB or thereabouts of the base 640KB remaining.

My collection database and technical wiki:
https://www.target-earth.net

Reply 54 of 77, by megatron-uk

User metadata
Rank Oldbie
Rank
Oldbie

Okay, got it up to 397 game entries and it works. At 500 it crashes. So with 640KB the limit is somewhere between the two.

I also need to figure out just where and why it crashes....

My collection database and technical wiki:
https://www.target-earth.net

Reply 55 of 77, by megatron-uk

User metadata
Rank Oldbie
Rank
Oldbie

Don't think I'm hitting an actual limit here - but when I exclude some of my game folders (D:\Advnture and D:\Misc) the application runs fine (with over 400 entries in the database). If I include them (even if excluding everything else) the interface locks up.

I suspect a possible directory name or similar issue somewhere in the parsing/display of the scraped-and-sorted entries, so as yet, I haven't hit an upper limit on the number of entries.

I'll have to do some digging in to the (lack of) performance as I've been adding some timers to various critical sections:

src/timers.c.24	 GFX Init                      :    55 ticks
src/main.c.231 Valid graphics mode found
src/timers.c.24 UI Init : 0 ticks
src/timers.c.24 Font Loading : 220 ticks
src/timers.c.24 UI Asset Loading : 1922 ticks
src/timers.c.24 Game Scraping : 2527 ticks
src/timers.c.24 Game Sorting : 9392 ticks
src/timers.c.24 Draw full UI buffer (-info) : 2746 ticks
src/timers.c.24 Draw full UI buffer (+info) : 2746 ticks
src/timers.c.24 Flip GFX buffer : 55 ticks
src/timers.c.24 Redraw New Game : 659 ticks
src/timers.c.24 Scroll Browser Down : 659 ticks
src/timers.c.24 Redraw New Game : 659 ticks
src/timers.c.24 Redraw New Game : 659 ticks

This is on Dosbox @ 0-frameskip and 3000 cycles and at my current maximum of 409 titles, so take the figures with a pinch of salt. Certainly the RAM to VGA flip is not the culprit (steady 55 clock ticks each time), but the scroll and redraw routine is hurting a lot.

My collection database and technical wiki:
https://www.target-earth.net

Reply 56 of 77, by megatron-uk

User metadata
Rank Oldbie
Rank
Oldbie

Ok, got a major speedup with the functions which redraw the newly selected game - from ~700-800 ticks to ~100.

One entire up/down cursor movement generated the following metrics:

For a game with artwork

src/timers.c.24	 - Clear artwork window        :   494 ticks
src/timers.c.24 - Lookup game : 0 ticks
src/timers.c.24 - Load metadata : 55 ticks
src/timers.c.24 - Process artwork list : 0 ticks
src/timers.c.24 - Update UI Info pane : 55 ticks
src/timers.c.24 - Display artwork : 220 ticks
src/timers.c.24 Redraw New Game : 824 ticks

For a game without artwork

src/timers.c.24	 - Clear artwork list          :     0 ticks
src/timers.c.24 - Clear artwork window : 549 ticks
src/timers.c.24 - Lookup game : 0 ticks
src/timers.c.24 - Update UI Info pane : 110 ticks
src/timers.c.24 - Display artwork : 0 ticks
src/timers.c.24 Redraw New Game : 659 ticks

Ouch, the clearing of the artwork window is expensive. Those routines do a few different things, setting and clearing some variables, but the main one being a call to my gfx_BoxFill() primitive, which paints a rectangle in a given colour.

I hadn't optimised it since writing it, and it was implemented as:

for(row = y1; row <= y2; row++){
for(col = x1; col <= x2; col++){
*vram = palette;
vram++;
}
vram += step;
}

There is a bit more complexity there, checking for negative dimensions, etc, but that's the gist of it. I've now replaced it with a call to memset() as follows:

for(row = y1; row <= y2; row++){
memset(vram, palette, size);
vram += stepsize;
}

That drops the time to move the cursor down a line, clear the artwork window and load the new data to the following:

src/timers.c.24	 Scroll Browser Down           :     0 ticks
src/timers.c.24 - Clear artwork list : 0 ticks
src/timers.c.24 - Clear artwork window : 55 ticks
src/timers.c.24 - Lookup game : 0 ticks
src/timers.c.24 - Update UI Info pane : 55 ticks
src/timers.c.24 - Display artwork : 0 ticks
src/timers.c.24 Redraw New Game : 110 ticks

110 ticks in total, and the clearing of the artwork window is ten times faster. Just a tenth of a second (based on a 1000 clock tick granularity) to move between rows.

My collection database and technical wiki:
https://www.target-earth.net

Reply 58 of 77, by pan069

User metadata
Rank Oldbie
Rank
Oldbie
megatron-uk wrote on 2021-02-03, 20:32:

Ouch, the clearing of the artwork window is expensive. Those routines do a few different things, setting and clearing some variables, but the main one being a call to my gfx_BoxFill() primitive, which paints a rectangle in a given colour.

Maybe I missed this in the thread, but how do you deal with the segmented frame buffer? I believe you had a buffer in internal memory that represents the entire screen (256Kb), the Watcom __huge buffer. But how do you copy to the screen? Isn't each of the video buffer segments located at 0xA000 and you need to switch segment? Also a segment might end in the middle of a scanline, right?

Reply 59 of 77, by megatron-uk

User metadata
Rank Oldbie
Rank
Oldbie
pan069 wrote on 2021-02-03, 21:04:
megatron-uk wrote on 2021-02-03, 20:32:

Ouch, the clearing of the artwork window is expensive. Those routines do a few different things, setting and clearing some variables, but the main one being a call to my gfx_BoxFill() primitive, which paints a rectangle in a given colour.

Maybe I missed this in the thread, but how do you deal with the segmented frame buffer? I believe you had a buffer in internal memory that represents the entire screen (256Kb), the Watcom __huge buffer. But how do you copy to the screen? Isn't each of the video buffer segments located at 0xA000 and you need to switch segment? Also a segment might end in the middle of a scanline, right?

Here's the gfx_Flip() function in full. It operates on the 256KB __huge array that I do all of my compositing, 'blits', sets, fills and clears into:

void gfx_Flip(){
// Copy a buffer of GFX_ROWS * GFX_COLS bytes to
// the active VRAM framebuffer for display.

unsigned short int window;
long int left;

// Set the vram pointer to the start of the buffer
vram = vram_buffer;

left = (long int) VRAM_END;

// for each window in the number of windows for this video mode
for(window = 0; window < windows_in_use; window++ ){

// set new window to be active
vesa_SetWindow(window);

// copy the block of pixels for this memory window
if (left > window_bytes){
if (GFX_VERBOSE){
printf("%s.%d\t gfx_Flip() Copying %ld bytes to window %d\n", __FILE__, __LINE__, window_bytes, window);
}
_fmemcpy(VGA, vram, window_bytes - 1);

left -= (window_bytes - 1);
} else {
if (GFX_VERBOSE){
printf("%s.%d\t gfx_Flip() Copying remaining %ld bytes to window %d\n", __FILE__, __LINE__, left, window);
}
_fmemcpy(VGA, vram, left);
}

// Increment the pointer to the vram buffer by the size of one video window
vram += (long int) (window_bytes);
};

// Reset vram buffer pointer position
vram = vram_buffer;
}

I'm not going to pretend that it's perfect... and I know that I still have a bug somewhere which is causing this when the buffer is copied to the 4 video memory segments:

progress6.png
Filename
progress6.png
File size
204.15 KiB
Views
779 views
File license
CC-BY-4.0

But, by and large, it's working, and the copy mechanism isn't proving to be a bottleneck (for my purposes, at least), at least compared to some of my other crummy code 😀

My collection database and technical wiki:
https://www.target-earth.net