#71885 - tonkinfash - Wed Feb 15, 2006 2:39 am
I've just gotten to grips with the basics of GBA coding and I then proceeded to create a simple bouncing ball program just to get to grips with double-buffering in mode 4.
The program works, but the framerate is less than 1/sec!
I'm not at my PC right now so I can't post code, but the logic goes:
Code: |
initialise variables.
while (1)
blit.
wait for vblank.
flip.
logic for ball/screen edge collisions on y axis.
do the same for the x axis.
end |
The waiting for the V blank is done with a simple while loop.
Any ideas?
#71887 - nmain - Wed Feb 15, 2006 3:08 am
make sure, if using C, you're treating vcount as a volatile memory location.
#71896 - tonkinfash - Wed Feb 15, 2006 5:32 am
Here's an update:
The main logic is thus:
Code: |
while (1)
{
clearBuffer_M4 ();
blit_8x8_M4 (x, y, ball);
x += xVel;
y += yVel;
if ((xVel > 0) && (x >= (SCR_WIDTH - 8)))
xVel = -xVel;
else if ((xVel < 0) && (x <= 0))
xVel = -xVel;
if ((yVel > 0) && (y >= (SCR_HEIGHT - 8)))
yVel = -yVel;
else if ((yVel < 0) && (y <= 0))
yVel = -yVel;
VBlankWait ();
flipBuffers ();
} |
The blitter code:
Code: |
void blit_8x8_M4 (short x, short y, unsigned char *image)
{
short xx, yy;
for (yy = 0; yy < 8; yy++)
for (xx = 0; xx < 8; xx++)
setPixelM4 (x + xx, y + yy, image [xx + (yy << 3)]);
} |
The buffer clear code:
Code: |
inline void clearBuffer_M4 (void)
{
unsigned short i;
unsigned short *wordAlias = VIDEO_BUFFER;
for (i = 0; i < 19200; i++)
*wordAlias++ = 0x0000;
} |
V blank wait:
Code: |
inline void VBlankWait (void)
{
while (*SCANLINE_CTR < 160);
} |
Set pixel:
Code: |
inline void setPixelM4 (short x, short y, unsigned char col)
{
unsigned short *offset = VIDEO_BUFFER + (((y * SCR_WIDTH) + x) >> 1);
if (x & 1)
{
*offset &= 0x00ff;
*offset |= (col << 8);
}
else
{
*offset &= 0xff00;
*offset |= col;
}
}
|
Hope this helps. I optimised a little and the FPS is around 3-5 f/sec. If I comment out the clear function then it runs much faster so I'm guessing that the main bottleneck is there. I don't really know how to make it any more efficient though...
EDIT: I changed the clear code so that it writes 32 bits at a time and it's now at about 10 f/s. Better, but still unacceptable.
#71923 - Cearn - Wed Feb 15, 2006 10:06 am
Use DMA or CpuFastSet for copying or clearing large areas. Should speed things up to about take about 1/3 of a vblank. And don't ever, ever, EVER use shorts as loop indices. See tonc:dma for an example of how to make a DMA clear routine.
Is there any particular reason you're not using tiled modes or sprites? If you did that there wouldn't be any need to clear and blit so much, which is where most of your cycles are going now.
Also, your VBlankWait is wrong. Well, it does wait until the VBlank, but if your VBlank routines are small (which it isn't here, but in case it were), you'd still be inside the VBlank when the next call to VBlankWait happens, which clears immediately. For a proper vsync, first wait till vcount is over, then wait till vcount is 160 again. Or use the VBlankIntrWait interrupt, but learn about interrupts first.
Depending on the definition of VIDEO_BUFFER, the drawing routines may be off as well: if it's a pointer to the current backbuffer that's fine, but if it's a static pointer to 0x0600:0000, there's no point in flipping pages because the second one is always empty.
______
P.S.
The mode 4 rectangle drawer is one of the best ways of showing what you can do in terms of speed by simply changing the algorithm a bit. I did a few tests on this a long time back, and this is what I found:
Inlining the pixel plotter: 3x speedup
A using u32 or use fills where possible: 8.6x
Using an optimized filler: 2x
So that's a 45x increase in speed with a few simple changes. Actually, I think it should even be better because I still used small rectangles for the tests, meaning that the overhead for u16/u32 fills is still high. Depending on your compiler flags --if you're not compiling as thumb code (-mthumb) or have optimizations (-O1, -O2, -O3) off-- you may lose another factor 1.5. Also, using shorts as indices instead of ints costs another 20% or so.
#71927 - tonkinfash - Wed Feb 15, 2006 11:39 am
I was building up to sprites (hence being a beginner) but assumed that the hardware would be able to handle simple double-buffered graphics.
As you can see, all of my small routines are inline.
Of course the flip function swaps buffers (quicker than the version I found off the Net, too):
Code: |
inline void flipBuffers (void)
{
// A sneaky trick to swap buffers:
(unsigned int) VIDEO_BUFFER ^= (unsigned int) 0x0000A000;
toggleRegisterBit (REG_DC, DC_FLIP);
} |
And changing the registers to volatile does nothing.
Thanks for the help - guess I'm forced to learn sprites...
#71930 - Cearn - Wed Feb 15, 2006 12:18 pm
tonkinfash wrote: |
I was building up to sprites (hence being a beginner) but assumed that the hardware would be able to handle simple double-buffered graphics. |
Fraid not. Not unless you want to heavily optimize things. The GBA is simply too slow to really make much use of bitmap modes. They're nice for introductory purposes, but it's best to learn about tile modes as soon as you can.
tonkinfash wrote: |
As you can see, all of my small routines are inline. |
I know, but things won't actually be inlined unless you have optimizations switched on. The demos in most tutorials do not have that; nor do they mention that it's best to compile with '-mthumb-interwork -mthumb'. Which is why I mentioned it.
tonkinfash wrote: |
Of course the flip function swaps buffers (quicker than the version I found off the Net, too):
Code: | inline void flipBuffers (void)
{
// A sneaky trick to swap buffers:
(unsigned int) VIDEO_BUFFER ^= (unsigned int) 0x0000A000;
toggleRegisterBit (REG_DC, DC_FLIP);
} |
|
Then you've not been looking in the right places, as I wrote about that trick nearly two years ago :P The thing that threw me was that you were using all-caps for VIDEO_BUFFER, which is usually reserved for #defined constants rather than variables.
tonkinfash wrote: |
And changing the registers to volatile does nothing. |
Yes it does, just not in terms of speed. Your VblankWait() routine waits till the vcount reaches a certain value. But because the vcount is not altered inside the loop (how could it; it's read only after all) the GCC optimizer will perform the check outside of the loop, and your program would lock up. That's the reason for the volatile. You also need volatile if you want to make a function for filling with DMA or CpuFastSet.
tonkinfash wrote: |
guess I'm forced to learn sprites... |
Hardware sprites aren't so bad. In fact, it's probably a lot easier, and definitely faster, than having to take care of everything by hand.
#71960 - poslundc - Wed Feb 15, 2006 5:21 pm
Cearn wrote: |
Fraid not. Not unless you want to heavily optimize things. The GBA is simply too slow to really make much use of bitmap modes. They're nice for introductory purposes, but it's best to learn about tile modes as soon as you can. |
Based on the large number of people that seem to stop reading at the chapters on bitmap modes, convinced that those modes are right for their purposes, I wonder if tutorials wouldn't be better off talking about the tile modes before the bitmap modes, or giving a caveat when explaining the bitmap modes that they are not very useful for most actual game designs. Maybe something could be added to the FAQ about it.
Dan.
#71964 - Cearn - Wed Feb 15, 2006 6:04 pm
poslundc wrote: |
Based on the large number of people that seem to stop reading at the chapters on bitmap modes, convinced that those modes are right for their purposes. |
It's not just that people stop after reading about bitmap modes, tutorials stop after them, or add tile modes as an afterthought. So how are the readers suposed to know?
poslundc wrote: |
I wonder if tutorials wouldn't be better off talking about the tile modes before the bitmap modes, or giving a caveat when explaining the bitmap modes that they are not very useful for most actual game designs. |
Not sure if 'before' is preferable as the bitmap modes will be more familiar to new users and helps the transition, but a big fat caveat would be nice. I'll make tonc's bigger, see if that helps. [sigh]But even if I do and tepples adds it to the FAQ, not sure how much that would help: we still have people #including data and doing all sorts of unruly things as well because of tutorials that haven't been updated in ages but still continue to be popular[/sigh]. Maybe resurrecting the bad habits thread, or a summary of it? Or a simple, short list of dos and don'ts somewhere, with links to explanations. While the FAQ is great, it's sometimes difficult to find something particular even if you do know what you're looking for. On that note, would it be possible to put
wishful thinking wrote: |
READ THE FAQ
(yes, the whole thing. It's for your own good.) |
in the registration confirmation message in big angry red letters? Or would that be rude :P
sorry for the hijack, tonkinfash, just thinking out loud here.
#71967 - ScottLininger - Wed Feb 15, 2006 6:28 pm
poslundc wrote: |
I wonder if tutorials wouldn't be better off talking about the tile modes before the bitmap modes, or giving a caveat when explaining the bitmap modes that they are not very useful for most actual game designs. |
Bitmap modes are so much easier to learn. I think they're the natural starting point. It allows beginners to get *something* displaying on their gameboy, which is such a kick that it hooks you for life. (At least that's how it happened for me.)
A caveat is a nice idea. However, anyone who *tries* to make an action game in bitmap mode will quickly realize the limitations.
On that subject... there are plenty of turn-based or text-based games where mode 4 (or even 3) is perfectly okay, so we shouldn't make the blanket statement that tile modes are the only ones worth exploring.
-Scott
-Scott
#71971 - poslundc - Wed Feb 15, 2006 7:11 pm
Cearn wrote: |
It's not just that people stop after reading about bitmap modes, tutorials stop after them, or add tile modes as an afterthought. So how are the readers suposed to know? |
I'm not aware of any popular tutorials that don't give adequate coverage to tile modes. They do tend to treat them as a more "advanced" subject, though. I think it's the kind of discussion that could be well-suited to the overview chapters that first introduce the learners to the different modes available, although who knows if most beginners even read those chapters.
ScottLininger wrote: |
Bitmap modes are so much easier to learn. I think they're the natural starting point. It allows beginners to get *something* displaying on their gameboy, which is such a kick that it hooks you for life. (At least that's how it happened for me.) |
I dunno, for me, I very nearly skipped the sections on bitmap modes entirely when I started with the Pern tutorials. Now I may be exceptional for realizing the obvious benefits to using tiles, but I think the GBA is pretty misleading when it comes to its bitmap capabilities. It is probably difficult for a beginner who is unfamiliar with the specifications and seeing familiar PC features like buffer-swapping to fathom how stark the limitations are of what you can do in those modes, given the limited RAM and processor speed.
Would it be helpful if tutorials taught sprites before backgrounds? That would give learners early exposure to tile-based drawing, to perhaps ease them into background maps more naturally. Then maybe bitmapped backgrounds could become the afterthought.
ScottLininger wrote: |
A caveat is a nice idea. However, anyone who *tries* to make an action game in bitmap mode will quickly realize the limitations. |
If they were realizing them, the issue wouldn't be manifesting itself in the forums as frequently as they seem to. ;-)
There seems to be a lot of inertia created in a lot of beginners who get started using bitmap modes, plan out their whole RPG or whatever using them, and then show an awful lot of reluctance to be coaxed over to the tile modes.
Quote: |
On that subject... there are plenty of turn-based or text-based games where mode 4 (or even 3) is perfectly okay, so we shouldn't make the blanket statement that tile modes are the only ones worth exploring. |
That's true. But we can empirically tell that the overwhelming majority of beginners are interested in creating the kinds of games that are best suited for tile modes. (Either that or full-3D games, which is a whole different problem.)
Dan.
#71985 - tepples - Wed Feb 15, 2006 9:14 pm
poslundc wrote: |
I wonder if tutorials wouldn't be better off talking about the tile modes before the bitmap modes |
That's one reason why I suggest exploring with AGBTTY, because most programmers are likely to be familiar with C's stdout and/or conio or curses, which are similar in principle to the tile mode of an NES, Super NES, Game Boy, GBA, or Nintendo DS.
ScottLininger wrote: |
Bitmap modes are so much easier to learn. I think they're the natural starting point. It allows beginners to get *something* displaying on their gameboy |
So does AGBTTY's Hello World example.
Quote: |
there are plenty of turn-based or text-based games where mode 4 (or even 3) is perfectly okay |
Yet Advance Wars still runs in tile mode.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.
#72180 - tonkinfash - Thu Feb 16, 2006 10:35 pm
Of course I'm not claiming to be the sole inventor of the XOR buffer-flip technique. But I did conceive it for myself - independently of any book or tutorial. ;)
Beforehand, the SCANLINE_CTR was not set to volatile and ran fine. Changing it seems to have made no difference.
I'm a fairly decent programmer - I used to write DOS games (back in the day), where bitmap modes are much more practical.
And I realise that caps are reserved for #define macros - that's how they started off but then I realised it would be more practical to have them as variables (but I didn't bother renaming them).
How do you turn on the optimisations for GCC?
I will start to look into tile modes for sure, though.
Last edited by tonkinfash on Thu Feb 16, 2006 10:57 pm; edited 2 times in total
#72184 - Cearn - Thu Feb 16, 2006 10:52 pm
tonkinfash wrote: |
Of course I'm not claiming to be the sole inventor of the XOR buffer-flip technique. But I did conceive it for myself - independently of any book or tutorial. ;) |
So did I ^_^. But tonc is pretty much the only place which shows it, so I know where you hadn't been and I'm not above a little occasional advertising.
tonkinfash wrote: |
I'm a fairly decent programmer - I used to write DOS games (back in the day), where bitmap modes are much more practical. |
But for older consoles this isn't the case. AFAIK, there aren't even bitmap modes for the NES, SNES and GB. Probably not for the SMS and Genesis either.
tonkinfash wrote: |
How do you turn on the optimisations for GCC? |
-Ox, where x=1, 2 or 3. Some other useful flags can be found here and in the manuals. Be sure to compile with '-mthumb-interwork -mthumb' too. And if you're not already using it, start using devkitPro.
#72187 - tonkinfash - Thu Feb 16, 2006 11:04 pm
I changed my makefile (DevKitAdvance) to use the -o3 switch and it just gave me 2 pages of errors claiming multiple definitions of various things.
#72188 - poslundc - Thu Feb 16, 2006 11:06 pm
tonkinfash wrote: |
I changed my makefile (DevKitAdvance) to use the -o3 switch and it just gave me 2 pages of errors claiming multiple definitions of various things. |
Capital "O".
Dan.
#72189 - tonkinfash - Thu Feb 16, 2006 11:11 pm
It is.
#72190 - Cearn - Thu Feb 16, 2006 11:16 pm
tonkinfash wrote: |
I changed my makefile (DevKitAdvance) ... |
Switch to devkitPro. DKA has been dead for, what, 3 years now? devkitPro/devkitArm is the better toolchain. Depending no your download speed, it shouldn't take very long to make the transition.
tonkinfash wrote: |
... to use the -o3 switch and it just gave me 2 pages of errors claiming multiple definitions of various things. |
beaten by Dan (again *grumble*), but yes, upper case. If that doesn't help you may have bigger problems. You aren't #including files with code or data are you. The multiple definition this is usually a dead giveaway? (Just making sure. Most non-tonc tutorials do this and even you seem to know a thing or two about proper coding procedures, I still have to ask this)
#72191 - tonkinfash - Thu Feb 16, 2006 11:21 pm
Oops, I admit I did put a few essential one-line functions in an h file. It's a bad habit but these were functions that were inline and very short so they may as well have been macros (at least that's my flawed rationale ;) ).
#72192 - Cearn - Thu Feb 16, 2006 11:31 pm
For inline functions, use 'static inline' or 'extern inline' instead of just 'inline'. At least if you're using C and not C++. GCC man: inline. GCC is quirky that way. Of course, that's the GCC 4.0.2 manual; I don't know what DKA's version is, but it might not even be up to 3.
#72196 - poslundc - Thu Feb 16, 2006 11:57 pm
Cearn wrote: |
beaten by Dan (again *grumble*) |
Checking forums at just the right moment + brevity = sweet victory ;-)
Dan.