GP2X Fast Framebuffer Clear


dockthepod

Member
Joined
Jun 15, 2006
Messages
250
Hi, I've just got Rlyeh's Minimal Library working with my app but I'm wondering what's the fastest way to clear the framebuffer (in minlib, so maybe in upper 32?) and my depth buffer (my allocation) ? Memset seems pretty slow...
 
depends on the size of your frame buffer, but...

gp2x_blitter[0x4 >> 2] = 0x3030D40;
gp2x_blitter[0x0] = 1<<5; // Destination is 16 bpp
gp2x_blitter[0x8 >> 2] = 512; // Destination stride size in bytes
gp2x_blitter[0x20 >> 2] = 1 << 5 | 2 << 3; // Perform ROP with a 1bpp pattern
gp2x_blitter[0x24 >> 2] = 0xFFFF; // Setup the foreground and background colors for the pattern to be the same
gp2x_blitter[0x28 >> 2] = 0xFFFF; // so we don't actually have to upload a pattern image.
gp2x_blitter[0x2c >> 2] = (150 << 16) | (1024); // Height and width to blit
gp2x_blitter[0x30 >> 2] = (1<<8) | (1<<9 ) | 0xf0; // Fill from top left to bottom right

// Wait for blitter to be free, start it, and then wait for completion.
// Throw in some nop's so we don't saturate the address bus with polling requests.
// (normally you would do something else whilst the blitter was working)
while (gp2x_blitter[0x0034 >> 2] & 1)
{
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
}
gp2x_blitter[0x34 >> 2] = 1;
while (gp2x_blitter[0x0034 >> 2] & 1)
{
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
}

Is what I'd use for fairly large areas. It only works on the upper 32MB. Other techniques would be to saturate the bus as much as possible with STM instructions (works on all memory).

So the MMSP2 docs for more details on the registers. I use the above also for clearing parts of memory not to do with graphics.
 
Thanks squide, I'll give that a shot :) Why do you not use that for parts of mem NOT to do with graphics?
 
How many milliseconds would a blitter clear of a 320x240 pixel area in 16 bit color take?
A simple for loop with 32bit writes (and not 16bit!) over the screen area takes me ~0.8 ms (not too slow I think). Is the blitter faster and if yes by how much?
 
Trenki said:
How many milliseconds would a blitter clear of a 320x240 pixel area in 16 bit color take?
A simple for loop with 32bit writes (and not 16bit!) over the screen area takes me ~0.8 ms (not too slow I think). Is the blitter faster and if yes by how much?
Could you try doing that with two 16bit writes instead of one 32bit write, since you have it timed? I merged something from 16bits to 32bits once, and it didn't get faster at all. I expected it to, since the bus connection to SDRAM is supposed to be 32bits (and the memory destination wasn't in cache since it was never read). My only explanation was that consecutive entries on the write buffer were getting coalesced.

It'd also be interesting to see how much faster stm's are, if at all, for different word sizes. That'd fall under the same thing.

Sorry, that's pretty off topic, it's just been bothering me for a while. If they are being coalesced then I don't think your for loop will take much longer, depending on whether or not the CPU has extra latency in accessing RAM over the blitter. If it doesn't then the time needed to execute the control flow instructions would be overlapped by the write time thanks to the write buffer.

However, bear in mind that the blitter is asynchronous. It'd tie up the bus (meaning cache misses would take longer, and would also delay the overall speed of the blit) but you could still go on doing other things to a decent extent.
 
Last edited by a moderator:
Squidge said:
Squidge said:
I use the above also for clearing parts of memory not to do with graphics.
dockthepod said:
Why do you not use that for parts of mem NOT to do with graphics?
:blink: :wacko:

:lol: Whoops, double negative. I was wondering why you don't use that for graphics code, but then I realized that I read it wrong :) Please ignore.
 
Last edited by a moderator:
@Exophase: Doing 16bit writes instead of 32bit writes in the screen clear function makes my function take twice as much time (1.6ms).

Wheter 32bit writes will be faster heavily depends on the loop itself though. If you simply write a fixed value and do not do anything else in the loop it will be faster. But when I tried to do 32bit write instead of 16bit ones in my software renderer where there are also some computations for each pixel it got a lot slower than 16bit writes. That was probably because the compiler ran out of registers and loaded and stored values from/to the stack (I looked at the asm). It turns out the compiler is not always that great either because these lrd/str instructions were actually redundant. But even with manuall removing them 32bit writes were a tad slower than 16 bit writes (because of the computations).
 
Fastest way of clearing framebuffer is not to a clear it. Just make new frame over it. You realy want to show system a blank screen? She watches you!
 
Trenki said:
@Exophase: Doing 16bit writes instead of 32bit writes in the screen clear function makes my function take twice as much time (1.6ms).

Wheter 32bit writes will be faster heavily depends on the loop itself though. If you simply write a fixed value and do not do anything else in the loop it will be faster. But when I tried to do 32bit write instead of 16bit ones in my software renderer where there are also some computations for each pixel it got a lot slower than 16bit writes. That was probably because the compiler ran out of registers and loaded and stored values from/to the stack (I looked at the asm). It turns out the compiler is not always that great either because these lrd/str instructions were actually redundant. But even with manuall removing them 32bit writes were a tad slower than 16 bit writes (because of the computations).
My tests were in ASM and none of the register allocation issues you're suggesting applied (as you said GCC isn't really that good at it, not nearly as aggressive as I am).

The computations shouldn't actually make a difference unless there are a significant number of them between writes (say, probably over 10 cycles), or you don't have write buffering enabled, or the framebuffer lines are in cache (would only happen if you read them previously.. and the area was cached). Are you using mmuhack? If not write buffering won't be on for that region. If you don't have write buffering then what I speculated (coalescing) couldn't happen anyway.

If the memory is in cache by the time the rasterizer gets to it then you'll also not get benefits from doubling the writes. But if it isn't then you should, unless the additional computations adds many more cycles.

Did you double the writes per loop iteration in the 16bit vs 32bit test, or did you just double the loop iterations?
 
Last edited by a moderator:
Back
Top