Mode13 - 110x88x256

I have put together my first proper screen mode. Currently I hove not looked into adapting any of the current functions to work with it, so I can only add pixels manually for the moment.

I’m not sure if the way I am updating the screen is the fastest it can be, if anyone can have a look and see if it can be faster that would be great.

[code]
void Pokitto::lcdRefreshMode13(uint8_t * scrbuf, uint16_t* paletteptr) {

write_command(0x20); write_data(0); // x
write_command(0x21); write_data(0); // y
write_command(0x22); // pixel data mode

int t=0;
for(int y=0; y<110; y++){
    for(int x=0; x<88; x++){
        write_data(paletteptr[scrbuf[t]]);
        write_data(paletteptr[scrbuf[t++]]);
    }
    t = 88*y;
    for(int x=0; x<88; x++){
        write_data(paletteptr[scrbuf[t]]);
        write_data(paletteptr[scrbuf[t++]]);
    }
}

}[/code]

Anyway, you can grab the code from here -
https://github.com/spinalcode/mode13

There are a few edits to the core code, I hope Jonne can join these so that people can start using this new screen mode.

I have changes the palette size to 256 from 16, I hope this doesn’t break other code.

It’s also a nice coincidence that it’s mode 13, it’s both the 13th mode in the pokitto core and it mirrors the old MS-DOS mode 13h, which was half the screen resolution at 8bit colour.

4 Likes

Did you work on the putpixel and other primitive support for this mode also?

1 Like

I have no way to test it out, but this might be a bit faster:

void Pokitto::lcdRefreshMode13(uint8_t * scrbuf, uint16_t* paletteptr) {
int savet;
uint16_t wdata;   
 write_command(0x20); write_data(0); // x
write_command(0x21); write_data(0); // y
write_command(0x22); // pixel data mode

int t=0;
for(int y=0; y <110; y++){
    savet = t;
    for(int x=0; x < 88; x++){
        wdata = (paletteptr[scrbuf[t++]];
        write_data(wdata);
        write_data(wdata);
    }
    t = savet;
    for(int x=0; x < 88; x++){
        wdata = (paletteptr[scrbuf[t++]];
        write_data(wdata);
        write_data(wdata);
    }
}
}

You could also cut out the x variable entirely, but this would decrease the readability of the routine…

catsfolly

Your box is going out today

2 Likes

I’m struggling to get the pixel routines working

I have tried to implement 8bit pixels into the drawing functions, but it doesn’t seem to be working. Initially I was trying to follow how the ‘print’ functions work, but there is an awful lot there to try to follow. I thought a simple addition

    #elif POK_COLORDEPTH == 8
    uint16_t i = y*width + x;
    m_scrbuf[i] = color;

to the pixel functions would have fixed it, but I get nothing.

[edit]
Also, is Pokitto::lcdRefreshMode13 the main bottleneck to the framerate, or are there other changes that can be made? If you set game.display.rotatePalette(10); instead of 1, you can clearly see the screen updating, I would have thought it should be faster than that…

are you compiling offline or online? i wonder if optimization is on

Offline, I’ll try online, see if it makes a difference.

In the offline, check project settings to see if optimization -O3 for C/C++ files is on. Due to the “loopy” nature of the screen refresh, optimization makes a BIG difference in speed

Should not be. Something is not right if you see the screen updating.

EDIT: I am very busy with the shipments right now, but I love the Mode13 idea and I will work on this with you to make it right.

1 Like

it *looks faster when compiled online, but I haven’t implemented an fps counter, so I can’t be sure.

1 Like

By default, online compiler is optimizing with -Os setting

I have just updated, I have the pixels working and as a result anything using drawpixel should work. I tested drawRect, drawCircle, drawLine and drawChar. Oddly, drawChar works but print doesn’t I was sure print used drawchar…

2 Likes

I was testing direct pixel routines, it seems I might be running too fast. Is there no way to wait for vblank/hblank? According to the screen documents there is at least an internal signal being used but didn’t see anything about that pin being connected externally.

No way. Hblank/Vblank is only relevant to RGB mode on this controller.

Use a __nop(); before switching back to command mode (look at writeData)

The best I’m able to get is 13-15fps. Surely I should be able to do better?

Isn’t Pokitto currently limited to 15 fps in all modes?

I don’t think so, not in mode13 anyway, I’ve set it to 60.
Although setting the frameRate to 1 or 2 is making no difference to the running speed. That’s what I get for messing with the update routines.

  1. Take a look at how mode2 refresh works. -
    A. your code can be made 2x more efficient with a simple tweak: you are reading the same source pixel values twice in two separate for loops. Look at how I first create a scanline buffer and then blast it out twice
    B. contrary to popular belief, for loops are not efficient. You have to “unroll” your loops. Write_data is a tiny bit of code. Instead of for looping through all pixels, you should write 10x pixels (at least) inside one loop and then loop 10x less. The difference is big.

  2. Fps. Currently it is limited @20fps just because it was easier to get the simulator to somewhat match the speed of hardware that way. This limitation will be removed. Secondly, the timing mechanism is not accurate enoug to get a good fps reading. You have to average over a long time. This will also be fixed.

2 Likes

This is what I’m currently using and it’s still only getting 11-12fps…

void Pokitto::lcdRefreshMode13(uint8_t * scrbuf, uint16_t* paletteptr, uint8_t offset){

    uint16_t wdata;
    write_command(0x20); write_data(0); // x
    write_command(0x21); write_data(0); // y
    write_command(0x22); // pixel data mode

    uint8_t scanline[88];

    int t=0;
    for(int y=0; y <110; y++){

        for(int x=0; x < 88; x++){
            scanline[x]=(scrbuf[t++]+offset)&255;
        }

        for(int x=0; x < 88;){
            wdata = paletteptr[scanline[x++]]; write_data(wdata); write_data(wdata);
            wdata = paletteptr[scanline[x++]]; write_data(wdata); write_data(wdata);
            wdata = paletteptr[scanline[x++]]; write_data(wdata); write_data(wdata);
            wdata = paletteptr[scanline[x++]]; write_data(wdata); write_data(wdata);
            wdata = paletteptr[scanline[x++]]; write_data(wdata); write_data(wdata);
            wdata = paletteptr[scanline[x++]]; write_data(wdata); write_data(wdata);
            wdata = paletteptr[scanline[x++]]; write_data(wdata); write_data(wdata);
            wdata = paletteptr[scanline[x++]]; write_data(wdata); write_data(wdata);
        }
        for(int x=0; x < 88;){
            wdata = paletteptr[scanline[x++]]; write_data(wdata); write_data(wdata);
            wdata = paletteptr[scanline[x++]]; write_data(wdata); write_data(wdata);
            wdata = paletteptr[scanline[x++]]; write_data(wdata); write_data(wdata);
            wdata = paletteptr[scanline[x++]]; write_data(wdata); write_data(wdata);
            wdata = paletteptr[scanline[x++]]; write_data(wdata); write_data(wdata);
            wdata = paletteptr[scanline[x++]]; write_data(wdata); write_data(wdata);
            wdata = paletteptr[scanline[x++]]; write_data(wdata); write_data(wdata);
            wdata = paletteptr[scanline[x++]]; write_data(wdata); write_data(wdata);
        }
    }

}