Faster 320x240 graphics

Posted on
  • Hi,

    I just had an idea for faster 320x240 graphics. I don't know if anyone's interested but:

    The problem is that 320x240x16bpp is way too big to fit into RAM, so when you're writing each pixel has to be sent over pretty much one at a time. Not only that but you probably don't care about all 16 bits and would be happy with a few less.

    What if you could store the data at a lower bit depth and expand it up as you sent it to the display? Well, you can...

    The code below converts 1bpp graphics into 16bpp, one line at a time.

    var g = Graphics.createArrayBuffer(16,16,1);
    g.drawLine(0,0,15,15);
    
      // convert ABCDEFGH into AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHH
    function expand(b) { 
      return (((b&0x11)*0x000F00F)&0x000F000F) |
             (((b&0x22)*0x0078078)&0x00F000F0) |
             (((b&0x44)*0x03C03C0)&0x0F000F00) |
             (((b&0x88)*0x1E01E00)&0xF000F000);
    }
    
    function flip() {
      var w = g.getWidth()>>3; // 8 bit, 1 BPP
      var h = g.getHeight();
      var b;
      for (var y=0;y<h;y++) {
        b = new Uint32Array(new Uint8Array(g.buffer,y*w,w)).map(expand);­ // 1 bit to 4 bit
        b = new Uint32Array(new Uint8Array(b.buffer)).map(expand); // 4 bit to 16 bit
        console.log(b);
        //spi.write(b.buffer);
      }
    }
    
    flip();
    

    It's not that fast right now - it's only a proof of concept - but the 'expand' function could be a bit of inline assembler which would help matters no end.

    The other option is to add something to Espruino itself - specifically SPI.write already has the ability to specify {data: ..., count:#} as an argument. What if you could also specify {data: g.buffer, fromBits:2, toBits:16, : lookup:[0,255,65280,65535]}, then you could actually do palletted graphics?

    Having said all that, g.fillRect is currently going as fast as possible - so if that is running too slow for you then this wouldn't help I'm afraid.

  • Actually even using the code above with assembler, it's still too slow at 320x240. It's probably because map insists on creating a new ArrayBuffer for each call.

    Looks like building it into Espruino itself is probably the only way forward then. I guess the functionality would be handy too (especially as E.toArrayBuffer can take the {data: ..., count:#} argument too).

  • ...slipped my attention... when working something like this a while ago, I was expecting this to happen under the hood... But as you mentioned earlier, speed is not only defined by the processing but also by the communication to the graphics display. With a serial connection a slowdown is noticed. Further more, the API matters as well: the 262K colors / 2Bytes per pixel saves a byte, but makes the processing in a high(er-)level language a pain, and more so when working off the source: it's convenient for the app to provide the color in an 3-byte/3-number RGB format, but has its cost. These cost are especially high when controlling the pixels from the application one by one vs. passing on a command that does a lot of pixels with a given color.

    Would the expand() not be a perfect candidate for the now available assembler?

  • Would the expand() not be a perfect candidate for the now available assembler?

    In a way, however as you couldn't allocate a buffer big enough for everything you'd still have to send the pixels in chunks. Having it built-in to 'write' could save that overhead.

    Another option that would make the assembler easier is something like E.mapInPlace(to,from,mapFn). Of course if JS had an in-place version of map you wouldn't need any of this either :(

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

Faster 320x240 graphics

Posted by Avatar for Gordon @Gordon

Actions