Cannot (m)alloc 64k block for a VGA double buffer

Developer's Forum, for discussion of bugs, code, and other developmental aspects of DOSBox.

Cannot (m)alloc 64k block for a VGA double buffer

Postby WhiteFalcon » 2018-9-10 @ 09:15

Not sure if this is the right place, but it has to be connected with DosBox. After more than 10 years I have come back to try DOS C (with a bit of asm) programming, remembering more than I expected. But I got stuck not far from the beginning - I can init the clasic mode 13h and put some pixels, yet when I try to allocate a 64000-byte pointer for double buffering, it wont let me.
My IDE of choice is Borland Turbo C++ 3.0 in DosBox 0.74, the project is now set to Large (1MB code, 1MB data). I even found snippets of my ages old code and it worked without a problem, now in DoxBox there is not enough memory, not even if I compile it and run from the command line. The gist of the code is this:

unsigned char *vga_buff;

vga_buff = (unsigned char *) malloc(320 * 200);

Allocating 320 * 190 seems to work though. Also, its recommended to get a piece of memory starting at offset 0x0000, how can I achieve that?
At the moment I have no means to test the code on an old DOS machine, but I am sure it used to simply work and now in DosBox it wont.
User avatar
WhiteFalcon
Newbie
 
Posts: 15
Joined: 2007-12-11 @ 12:17
Location: Prague, Czech Republic

Re: Cannot (m)alloc 64k block for a VGA double buffer

Postby ripsaw8080 » 2018-9-10 @ 09:48

Code: Select all
#include <alloc.h>

Try adding that to the top of your source file if you haven't already, as I think it's needed to get malloc() to use the chosen memory model.
User avatar
ripsaw8080
DOSBox Author
 
Posts: 4255
Joined: 2006-4-25 @ 23:24

Re: Cannot (m)alloc 64k block for a VGA double buffer

Postby Scali » 2018-9-10 @ 10:06

Note that in DOS, you are working with 16-bit segmented mode. This means that the memory model you choose affects how your malloc()-functions work.
Namely, if you use a tiny or small model, your malloc() will allocate 'near' memory, as in: memory in a single 64k data segment. In this case, malloc() will likely fail with a size of 64000 bytes, because there is not enough memory available.
In that case, you need a farmalloc() call (or _fmalloc() or whatever your compiler calls it).
If you want a memory block at offset 0, the easiest way is to use the DOS alloc functionality directly. It returns memory in paragraphs, giving you a base segment.
farmalloc() calls are generally wrappers around this functionality, and will return a normalized far-pointer, which usually boils down to a segment and an offset of 0.

As an aside, the most awesome way of double-buffering on VGA is using mode X or mode 0Dh (EGA 16-colour mode). This allows you to use multiple display pages in video memory, and performing a pageflip to switch buffers, rather than requiring an expensive copy operation.

My preferred way of using C in DOS is to take a small memory model, and manually managing any far memory I require.
Scali
l33t
 
Posts: 3606
Joined: 2014-12-13 @ 14:24

Re: Cannot (m)alloc 64k block for a VGA double buffer

Postby WhiteFalcon » 2018-9-10 @ 11:04

ripsaw8080 wrote:
Code: Select all
#include <alloc.h>

Try adding that to the top of your source file if you haven't already, as I think it's needed to get malloc() to use the chosen memory model.


Thanks, I tried that when testing farmalloc, for malloc it doesnt seem necessary though.

Scali wrote:Note that in DOS, you are working with 16-bit segmented mode. This means that the memory model you choose affects how your malloc()-functions work.
Namely, if you use a tiny or small model, your malloc() will allocate 'near' memory, as in: memory in a single 64k data segment. In this case, malloc() will likely fail with a size of 64000 bytes, because there is not enough memory available.
In that case, you need a farmalloc() call (or _fmalloc() or whatever your compiler calls it).


Thank you. I have always been unsure about the near/far memory so I have always used at least the large model that is supposed to make everything "far" when needed. I tried farmalloc explicitly too and it did not work either.

Scali wrote:If you want a memory block at offset 0, the easiest way is to use the DOS alloc functionality directly. It returns memory in paragraphs, giving you a base segment.
farmalloc() calls are generally wrappers around this functionality, and will return a normalized far-pointer, which usually boils down to a segment and an offset of 0.


Did not relalize that, will check the DOS functions. It boggles me that it really used to work on real DOS though, have to try it when I get to my classic old PC in a few weeks.

Scali wrote:As an aside, the most awesome way of double-buffering on VGA is using mode X or mode 0Dh (EGA 16-colour mode). This allows you to use multiple display pages in video memory, and performing a pageflip to switch buffers, rather than requiring an expensive copy operation.

My preferred way of using C in DOS is to take a small memory model, and manually managing any far memory I require.


Of course, I have read on the unchained mode a lot, but the simplicity of mode 13h is a big bonus. afaik, mode-x was used for games that needed fast fullscreen scrolling, in other cases it is not supposed to be faster (or not significantly) while being more difficult to manage. Have to check on it again.
User avatar
WhiteFalcon
Newbie
 
Posts: 15
Joined: 2007-12-11 @ 12:17
Location: Prague, Czech Republic

Re: Cannot (m)alloc 64k block for a VGA double buffer

Postby root42 » 2018-9-10 @ 11:42

Mode X and Y are already better as soon as you want to use double buffering. It’s really hard to imagine hiw slow the ISA bus actually is. Even without smooth scrolling, the page flipping feature usually makes those modes worthwile.
Soldering, retro game reviews and more on YouTube and Bonus videos
Me playing games on my 286 and on my Sega MD2 on Twitch
80286@12 MHz, 2 MiB RAM, Tseng ET4000 1 MiB, schlae AdLib, PC MIDI Card + SC55MkII, XT CF Lite, OSSC 1.6
User avatar
root42
Oldbie
 
Posts: 585
Joined: 2018-1-27 @ 13:23

Re: Cannot (m)alloc 64k block for a VGA double buffer

Postby Scali » 2018-9-10 @ 12:03

WhiteFalcon wrote:Thank you. I have always been unsure about the near/far memory so I have always used at least the large model that is supposed to make everything "far" when needed. I tried farmalloc explicitly too and it did not work either.


Yea, making everything 'far' (or 'huge') is a bruteforce way of using the full 640k memory (you still won't be able to take advantage of XMS or EMS this way). However, the code it generates is quite inefficient, because the compiler has to generate a lot of extra code to switch segments all the time. Pointer arithmetic will also be less efficient.

WhiteFalcon wrote:Of course, I have read on the unchained mode a lot, but the simplicity of mode 13h is a big bonus. afaik, mode-x was used for games that needed fast fullscreen scrolling, in other cases it is not supposed to be faster (or not significantly) while being more difficult to manage. Have to check on it again.


Yes, it is a bit complicated to use, because you cannot freely access all pixels on screen. You have to switch between the 4 planes. Depending on what kind of drawing operations you require, this may or may not be very complex or inefficient.
For example, Wolfenstein 3D renders everything in vertical columns. It can render these columns in any order. This means that you can easily render all columns for plane 0, then switch to plane 1, render all columns for plane 1, etc.
This makes it a very good fit.
Scali
l33t
 
Posts: 3606
Joined: 2014-12-13 @ 14:24

Re: Cannot (m)alloc 64k block for a VGA double buffer

Postby WhiteFalcon » 2018-9-10 @ 12:15

I am going to run it on a Pentium 75MHz so it would be fine, but it would be nice if I was able to run it on a, lets say, a 486DX/40 or similar machine too.

Scali wrote:Yea, making everything 'far' (or 'huge') is a bruteforce way of using the full 640k memory (you still won't be able to take advantage of XMS or EMS this way). However, the code it generates is quite inefficient, because the compiler has to generate a lot of extra code to switch segments all the time. Pointer arithmetic will also be less efficient.


Right, I remember having to write functions for XMS and calling the driver anytime I needed access to a particular bank, very slow.

Scali wrote:Yes, it is a bit complicated to use, because you cannot freely access all pixels on screen. You have to switch between the 4 planes. Depending on what kind of drawing operations you require, this may or may not be very complex or inefficient.
For example, Wolfenstein 3D renders everything in vertical columns. It can render these columns in any order. This means that you can easily render all columns for plane 0, then switch to plane 1, render all columns for plane 1, etc.
This makes it a very good fit.


Interesting, would you believe I actually BOUGHT the source code for Wolfenstein like 20 years ago on a 5 1/4 floppy disk? :-) From what I have read on mode-x, this really seems the way to go, draw from top-to bottom and then left-to right, unlike mode 13. The 320x240 resolution has its allures too so will give it a try again. But anyway, I have tried allocating memory using the DOS function and it still wont allocate 64000 bytes. Funnily enough, allocating 67200 bytes returns no error, which should not be possible if it crosses a segment boundary I assume.

Here is the function:

Code: Select all
void *MEM_Alloc(unsigned int size)
{
 int num_para;

 num_para = (size / 16) + 1;

   asm {
      mov ah, 0x48
      mov bx, [num_para]
      int 0x21
   }

   if (_FLAGS & 0x0001) return(NULL);

   return(MK_FP(_AX, 0x0000));
}


EDIT: Scali, I just found out you are the author of the nice tuts I read through some monts ago, on EGA and mode-x, thanks for those :)
User avatar
WhiteFalcon
Newbie
 
Posts: 15
Joined: 2007-12-11 @ 12:17
Location: Prague, Czech Republic


Return to DOSBox Development

Who is online

Users browsing this forum: No registered users and 0 guests