I was reading this article by Raymond Chen where he mentioned this:
Most of the time, your code won’t care (there are just pixels out there that you aren’t using), but if you use the GetBufferedPaintBits function to obtain direct access to the bits, don’t forget to take the stride into account.
The word “stride” evoked a ton of memories where I used to track (laboriously) the dimensions of a bitmap. This was back in the days when I was fiddling with writing my own computer games and computer graphics. Specifically, I was working with the screen graphics buffer.
Double buffers, 8-bit colours and screen resolutions
What happens (happened?) is that for fast visuals, we need a decent frame rate, and 30 frames per second is fast enough to fool human eyes that we’re looking at smooth uninterrupted motion. Back in those days, computer monitors weren’t that advanced, so the double buffer trick was used. (Is it still used? I don’t know…).
The double buffer trick refers to having 2 sets of screen buffers. The first one is used to “blit” the contents onto the screen. I’m using blit as a verb too, but this will take too long to explain if I told the story of blitting too… While this blitting is being done, the pixels of the next frame is drawn on the second buffer. When the drawing of pixels is completed, this second buffer is used to blit to the screen.
When you force the program to use double buffering, the next frame is held until the buffer has the drawing completed. This is what “lag” means. The frame rate is sort of ignored, because only when the next frame is completely drawn, will the buffer contents be displayed. Usually this isn’t a problem because the pixel drawing for one frame is within 0.03333 seconds (based on 30 FPS). As you go for higher resolutions and more complex objects being drawn and more complex calculations being done (such as calculating hit points and bullet trajectories), this next-frame-drawing gets slowed down.
In code, what you have are 2 bitmaps in memory and 1 pointer (yay, pointers!). You actually point the pointer to either bitmap based on which bitmap’s contents are to be blit.
- First bitmap on screen, second bitmap drawing next frame, point to first bitmap.
- Second bitmap done drawing.
- Point to second bitmap.
- Draw next frame on first bitmap.
- Continue till application (most probably a game) is done.
“So what’s the stride got to do with this? And what’s a stride?”
Well, the thing is, when you request a bitmap from within your code, you might not get the exact dimensions you want. What you get is, as Raymond mentioned:
it only promises that the bitmap will be at least the size you requested.
So the bitmap given to you can be larger in size. And the larger size is based on the stride. I’ve not done a whole lot of research, and the following explanation is based on what I remember from those game-developing days. Let’s say the stride is 4 bytes. This means the memory size of the bitmap given to you will be in multiples of 4. … Uh, yeah, I think that’s about it.
If you ask for a bitmap with dimensions such that the projected final size memory is not in multiples of 4, you will be given a bitmap such that it is.
This “problem” is compounded by the fact that you also have to take care of the red, green and blue bytes (3 contiguous bytes for 1 pixel). Sometimes, there’s an alpha component. There’s also the 8-bit colour, where the first 2 bits are for red, next 3 bits are for green, and the final 2 bits are for blue. Not 1 byte for each colour component. (Just FYI, green has more bits because we can differentiate more shades of green than red or blue).
This is why you might find that in graphics programming, you are advised to have dimensions in multiples of 2. For example, your texture images used for mapping onto 2D planes and 3D objects should preferably have dimensions in powers of 2.
Wait, why powers of 2, and not just multiples of 2? I believe it has something to do with the texture mapping functions, because those functions don’t work well when the bitmap/image/texture argument doesn’t have dimensions with powers of 2. This is why I prefer to use square images at 128, 256 or 512 pixels. Mipmaps were used to alleviate this, but that’s another topic…
And the final complication? “What? There’s more?!?” Yes.
The bitmap you requested in code, the one where you might have to take note of the stride? That bitmap might have a different dimension than the screen dimension of the computer monitor. Computer monitors weren’t quite “standard” back then (I’m starting to feel old…). The computer monitor also has its own stride (I’m basing this on the memories of my research. Don’t just take my word for it). This means blitting pixels from a bitmap buffer to the screen isn’t quite so straightforward.
For example, if you’re working on a screen resolution of 800 by 600 pixels (yes, I know that’s like ancient. Work with me here…), and then you ask for a bitmap to represent that. Well, you might get a bitmap with dimensions 1024 by 768 pixels. Maybe it’s because it’s more memory efficient that way. 1024 = 2^10, and 768 = 2^9 + 2^8. Wait, now we have sums of powers of 2?!? I don’t know a whole lot about these things… I’m just trying to make a computer game…
So based on the above example, you have an “extra” width of 224 pixels (1024 – 800) and “extra” height of 168 pixels (768 – 600). So even if the stride is taken note of, the computer might just decide to throw you more memory space. Just for the heck of it.
The bitmap you request in code might have a different dimension than what you wanted. The computer monitor might have a different dimension to work with. You have to remember each pixel has a red, green, blue and even alpha component (each of which uses a byte of storage. Or not, in the case of 8-bit colours). Then you have to take note of the dimensions of the textures you’re using to map onto 2D/3D objects.
And none of that has very much to do with the “fun” part of game programming. You’re just trying to work with one image.
I hope you learnt something. Because I sure as heck don’t know what’s the point I was trying to make, other than bombard you with seemingly random pieces of information…