问题
I am writing a DOS game framework to learn C better and a general interest in programming on old hardware (especially on the system I grew up with).
I am trying to implement a double buffer system but I am having trouble allocating a far pointer to a 320*200 array.
At first I was trying to use malloc but found out it can only allocate under 64kb. I read that you need to use farmalloc (malloc returns NULL) and it allocated correctly. However, when _fmemset or _fmemcpy is run.... the whole system freezes.
backBuffer = (unsigned char far*) farmalloc(64000);
when it is time to swap buffers I use
_fmemcpy(VGA, backBuffer, 64000);
Program is using the small memory model.
回答1:
Very interesting post, I'm also very fond of old hardware.
Have you tried compiling in medium or large models to check if the code runs correctly?
Are you sure the pointer to the VGA display memory is correctly initialized?
I remember that in those days, using a memory copy to swap screen buffers was painfully slow, not to mention that you had to wait for the vertical retrace period to begin copying memory. (I had a bare bones VGA card, so perhaps your hardware is better and the delay is more than acceptable).
If your are interested, I'd strongly advice you to read Michael Abrash's Mode-X columns.
Mode-X and its derivatives are alternative graphic modes first documented by Michael Abrash. Basically they were hacks to the 256 color 13H mode that you could activate by tweaking some registers in the VGA card.
Once activated, there were two great advantages:
- Four pages of display memory
- Square Pixels (In original ModeX that is 320x240), (a plotted circle will look like a circle, not an ellipse)
Implementing a double or even triple buffer was a breeze, as you could directly write to the inactive buffer and activating it simply involved changing a register in the vga card, no memcopy at all! (you still need to wait for vertical retrace, otherwise there's an ugly flicker)
The disadvantage is that this mode is harder to program, basically, with mode-X now a single memory address is mapped to four consecutive pixels, so, a single pixel write will actually alter four pixels at once. (this is great acceleration for polygon filler routines!).
If you want to alter a single pixel, then you have to setup a "pixel mask" (also a VGA card register) specifying which of the four pixels will be affected by the memory write, just before you plot the pixel.
This is slow if done naively, as every pixel plotted requires setting up a mask. Usually we intuitively tend to draw things left to right, top to bottom (because that's precisely how video memory is mapped on the VGA mode 13H), but us Mode-X programmers learned it is much faster to "rotate the paradigm", that is, we drew things top-to-bottom, left-to-right.
Why? because this allows us to modify the pixel mask just once for every column drawn! Here's some pseudocode:
Naive, intuitive programming
pixelptr = start of screen memory
foreach row
foreach column
adjust pixel mask
write pixel value
pixelptr+= 1 // advance pointer to next pixel to the left
next
next
Rotated mode of programming
[Edit1: added the missing step where pointer must be moved to top of next column]
[Edit2: correction, I was adding 320 to advance to the next row when in fact this should be divided by 4 since a consecutive increment of the video memory address will map to the group of next four pixels to the right of the previous, four-pixel group]
for each column
pixelptr = start of screen memory + current column index
adjust pixel mask // same mask applies to every pixel in the same column!
for each row
write pixel value
pixelptr += (320 / 4) // advance pointer to next pixel, to the bottom
next
next
All the involved steps and register addresses are detailed in the link to the Michael Abrash columns I provided. This is ancient stuff, but I bet you'll find it fascinating!
Cheers!
来源:https://stackoverflow.com/questions/12428345/need-help-allocating-a-far-pointer-on-borland-c-3-0