Page 1 of 1

Need fast tile-rendering

Posted: Thu Jan 24, 2019 6:33 am
by alko
15 frames per second by this code:

Code: Select all

#include <genesis.h>

int main()
{
    SYS_disableInts();

    VDP_setScreenWidth320();
    VDP_setScreenHeight224();

    SYS_enableInts();

    while (TRUE)
    {
        VDP_showFPS(TRUE);
        for (int y = 0; y < 28; y++) {
            for (int x = 0; x < 40; x++) {
                u16 tileIndex = random() % 16;
                VDP_setTileMapXY(PLAN_B, TILE_ATTR_FULL(PAL1, FALSE, FALSE, FALSE, tileIndex), x, y);
            }
        }
        VDP_waitVSync();
    }

    return 0;
}
Image


how to speed up rendering 40*28 tiles?

Re: Need fast tile-rendering

Posted: Thu Jan 24, 2019 8:05 am
by mix256
This will give you 30fps:

Code: Select all

    u16 tiles[40 * 28];
    while (TRUE)
    {
        VDP_showFPS(TRUE);
        for (int i = 0; i < 28 * 40; i++) {
            tiles[i] = TILE_ATTR_FULL(PAL1, FALSE, FALSE, FALSE, random() % 16);
        }
        VDP_setTileMapDataRect(PLAN_B, tiles, 0,0, 40,28);
        VDP_waitVSync();
    }
This is slightly faster. But still 30fps:

Code: Select all

    u16 tiles[28][40];
    while (TRUE)
    {
        VDP_showFPS(TRUE);
        for (int y = 0; y < 28; y++) {
            for (int x = 0; x < 40; x++) {
                tiles[y][x] = TILE_ATTR_FULL(PAL1, FALSE, FALSE, FALSE, random() % 16);
            }
            VDP_setTileMapData(VDP_PLAN_B, tiles[y], y * 64, 40, DMA_QUEUE);
        }
        VDP_waitVSync();
    }
With reservation that these might not do what I think they do, though. :)

EDIT: If you don't generate the tiles (random) you get over 200 fps on the last one.

Re: Need fast tile-rendering

Posted: Thu Jan 24, 2019 8:08 am
by tryphon
At least, use DMA (you put your tilemap data somewhere in RAM, and use DMA_queue() to transfer it).

Re: Need fast tile-rendering

Posted: Thu Jan 24, 2019 9:40 am
by Stef
The last method given by mix256 is almost the fastest, here is my code to reach 60 FPS (just a bit above it), i needed to simplify the random() method and use a longer map to do a single DMA transfer :

Code: Select all

static u16 rand();
static u16 seed = 0xB6CE;

int main()
{
    u16 tiles[64*28];

    while (TRUE)
    {
        u16 x, y;
        u16* dst;

        VDP_showFPS(FALSE);

        dst = tiles;
        for(y = 0; y < 28; y++)
        {
            for(x = 0; x < 40; x++)
                *dst++ = TILE_ATTR_FULL(PAL1, FALSE, FALSE, FALSE, rand() & 0xF);

            // bypass unused map area
            dst += 64-40;
        }

        // single DMA
        VDP_setTileMapData(VDP_PLAN_B, tiles, 0, 64*28, DMA_QUEUE);

        VDP_waitVSync();
    }

    return 0;
}

static u16 rand()
{
    seed = (seed << 1) ^ GET_HVCOUNTER;

    return seed;
}
Still i think it's better to accept 30 FPS here with a better random and smaller map :)

I've to admit i'm a bit surprised by the poor performance of the compiler here : filling a map with random value is taking a full frame, i'm certain we could achieve it in a much smaller time using good assembly code (less than half of the frame should be possible).

Re: Need fast tile-rendering

Posted: Thu Jan 24, 2019 2:33 pm
by Miquel
Accessing VDP during display time is slow since CPU is blocked until VDP has a free time slice.

Re: Need fast tile-rendering

Posted: Thu Jan 24, 2019 9:04 pm
by Stef
Here we take care of that of course... and still getting 60 FPS is definitely not easy, just to fill the map randomly.

Re: Need fast tile-rendering

Posted: Fri Jan 25, 2019 3:22 pm
by Chilly Willy
It's almost certainly the random function and the macro to put together the word. I'd pre-make the rest of the word, then just OR in the randomized value to store in ram. Make the random inline, and use the common shift-xor pseudo-random method to generate the random value.

Re: Need fast tile-rendering

Posted: Fri Jan 25, 2019 4:20 pm
by Stef
i think the code i posted is already quite minimal (we could replace the HV counter read just using xor-shift only operations for random) and normally GCC 6 isn't too bad at optimizing... but anyway yeah of course we can always push optimization a bit more (unrolling loop, inline all methods, pre-loading values in registers...) :D

Re: Need fast tile-rendering

Posted: Sat Jan 26, 2019 9:11 pm
by alko
Stef wrote: Thu Jan 24, 2019 9:40 am The last method given by mix256 is almost the fastest, here is my code to reach 60 FPS (just a bit above it), i needed to simplify the random() method and use a longer map to do a single DMA transfer :
How to convert this linear addressing to X Y coordinates?

Re: Need fast tile-rendering

Posted: Mon Jan 28, 2019 3:31 pm
by Miquel
Stef wrote: Thu Jan 24, 2019 9:04 pm and still getting 60 FPS is definitely not easy, just to fill the map randomly.
Here:
viewtopic.php?f=22&t=2892
I do exactly that, and while it takes an appreciable chunk of cpu time, still there is at least 50% of time free. Probably about 60-80%, I don't really remember.

But hey, ingenuity has been always the best friend of game developers; I can think of several options to produce the same effect with MUCH less cpu time. In fact, I can think of one with nearly no cpu time, just two calls to random() per frame. Some others are pretty obvious.

I'm beginning to see lots of "I told you so" on the headers, time to retreat. Have fun developing, that's the key.

Re: Need fast tile-rendering

Posted: Tue Jan 29, 2019 7:40 pm
by alko
I want to do tiled raycasting on SMD, but i'm not programmer.
Can anyone help me?

Image

Re: Need fast tile-rendering

Posted: Tue Jan 29, 2019 10:20 pm
by Sik
Look here? (you'd be drawing tiles instead of RGB pixels but the basic concepts apply)
https://lodev.org/cgtutor/raycasting.html

Re: Need fast tile-rendering

Posted: Wed Jan 30, 2019 6:51 pm
by alko
I saw this example
but for me it will be difficult remade math to limited variables fix16
And I still do not understand how to translate linear addressing of tiles into XY-coordinates

Re: Need fast tile-rendering

Posted: Thu Jan 31, 2019 3:27 pm
by Chilly Willy
Since you're raycasting, I imagine you want the other way around - convert the x/y coords from the ray into a tile address.

Let's assume you use a row-centric arrangement for your tiles to make the bitmap. I.e.,
0 1 2 ... 39
40 41 42...79
80
etc

Let's assume you use two pixels together as a single pixel to simulate more colors via blending side-by-side pixels. This also makes the drawing much easier as you're dealing with bytes instead of nibbles.

Then tiles are 4 bytes wide by 8 lines tall.

Tile_Pixel = (x&3) + (x&~3)*8 + (y&7)*8 + (y&~7)*4*40;

If you make the bitmap column-centric, you can derive the address in a similar manner.

EDIT: Of course, the fastest way to convert from coords to tile address is a simple look-up table. x and y aren't that big (128 or 160 by 224 or 240). I'd just use y<<8 + x as the index.