• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

GML Help grasping buffers

Xer0botXer0

Senpai
Hi fellow game devs,

So basically Im just looking for information on buffers, because the manual doesn't explain it in a sense that makes sense to me, such as alignment and so on, now I somewhat get the idea, but what interests me is where did these people that seem so knowledgeable on buffers come from, because the manual certainly didn't make them that wise.

Is there any where I can read up on information that will help me better understand the concept of buffers and what not ?

On another note I've run into buffer related problems that the manual doesn't make me any wiser about.
 

TheouAegis

Member
The wise people most of the time learn through computer science classes. Basically a buffer is just a set of data that is any number of bytes long into which you can store data. Consider if you had an object that needed to create 20 variables. That would take up 1280 bits of memory because each variable takes up 64 bits. If you instead save those variables to a buffer, you could use up only as much memory as you actually require for those variables. So if each of those variables I was only at most eight bits in length, meaning it goes from 0 to 255, then you could write simply 160 bits worth of memory to the buffer. Now consider something like a 16-bit video game systems that has the Super Nintendo. You could write an 8-bit value to the memory, but the way the Super Nintendo was structured was it would read 16 bits of memory at a time. You could simulate that with buffers. You could write a series of 8-bit values to a buffer and then read the buffer back and 16-bit values. Why would you want to do that? That's up to you. I haven't messed with buffers myself, but it is possible looking at some speed test that I have seen that loading data from the buffer of a longer length than you require may actually be more beneficial in terms of speed.
 
Last edited:

Xer0botXer0

Senpai
That makes sense thank you. So if i put itin my own words, a buffer can use a dynamic amount of space set by the developer compared to a variable which is preset to # amount of bits depending on the variable data type ? Which means that if one uses variables no matter the amount of data within it its size will stay the same so space can be wasted in memory compared to using buffers?

If thats right so far, what is that offset alignment thing that buffers have ?
 

TheouAegis

Member
Suppose you have 4 variables:

a = 1
b = 335
c = -16
d = 2004

You could just write all those values as int32s, but you wouldn't be much better off than just using variables as normal. Instead, you could write (a) as a bool, (b) as unsigned 32bit, (c) as a signed 8bit, and d as whatever (without context, an unsigned 16bit would suffice). Now, I think a bool is automatically 8bit in a buffer, but not entirely sure.

Anyway, remember my example about 16 bit consoles like the SNES. The system could write numbers as either 8bit values or 16bit values depending on what the programmer wanted. So the memory could look like:

10 f0 24 28 64 a2 8b 40 24 08 0c

For now, let's just think of that as a buffer. If you wanted to read the 10th byte and just the 10th byte, you'd peek position 9, set the type to either buffer_u8 or buffer_s8, and read the byte there. So far, simple enough. Now let's say instead you want to read the 7th byte. You'd peek position 6, but the buffer type you use depends on what kind of data you want out of it. If you set the buffer type to buffer_u8, then the value you'd peek is 139; however, if you set the type to buffer_s8, the value you'd peek would be -117 because any byte with the highest bit set ($80 or larger) is negative when treated as signed.

Now let's ramp things up a bit. The SNES didn't read 1 byte at a time like the NES did, it read 2 at a time (hence it was a 16bit system). So in buffer terms, the buffer type for peeks was always buffer_u16. So if you wanted to read the 10th byte, the value peeked would be $080C (the system got around this by using 8bit registers, so it would read $080C but the programmer could still work with $08 and $0C separately if needed). When the programmer was ready to write a value back to the "buffer", he could write a single register as u8 or write the whole value as u16.

Now the important stuff. Let's go back to the first set of variables earlier in this post. Suppose you wrote them all as buffer_s16. Then the buffer would look like

01 00 4F 01 F0 FF D4 07

Suppose you wanted to get the value of (c) from the buffer. You remember that you used buffer_s16 as the type, but what position is (c)? It was your 3rd variable, but if you try to peek position 2 in the buffer, you'll get $014F. The position of (c) in the buffer is actually 4.

Now let's say you instead wrote to the buffer where (a) was bool, (b) was u16, (c) was s8, and (d) was we'll say u32. Now the buffer would look like

01 4F 01 F0 D4 07 00 00

Again, if you want to read (c) from the buffer, its position in the buffer this time around would be 3.

What happens if you use the wrong types, though? Suppose you used buffer_u8 for everything.

01 4F F0 D4

As you can see, the values stored in the buffer are quite different than what they should be.


The buffer types (fixed, grow, wrap) should be pretty straightforward, but I'll cover them real quick anyway. To help illustrate them, I'll refer to an emulator like FCEUX.

A fixed buffer is like the RAM - a limited amount is allocated to write values to. Once you filled up that memory, you have to decide when and where to overwrite anything.

A grow buffer is kind of like the game cartridge itself. The original NES games were like fixed buffers, but then companies started adding memory expansion chips to the cartridges to give them more memory to work with. This is kind of like what a grow buffer type is.

A wrap buffer is most easily comparable to a stack - a block of memory allocated for writing data sequentially, but once you reach the limit of the buffer, it resets the position back to 0 and any additional writes will overwrite the oldest entries. This is what happens when a "stack overflow" occurs and games crash.
 
Top