Skip to content

Instantly share code, notes, and snippets.

@flaki
Created January 30, 2018 06:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save flaki/969bc2f63b36210ce007deb93ceb4aff to your computer and use it in GitHub Desktop.
Save flaki/969bc2f63b36210ce007deb93ceb4aff to your computer and use it in GitHub Desktop.
Clouduboy perf timing demo for the Arduboy

Clouduboy perf timing demo

The interesting bits are:

game.custom({
  arduboy: `{ long now=millis()`
});

// and

game.custom({
  arduboy: `now=millis()-now; arduboy.fillRect(0,HEIGHT-8,WIDTH/2,8,BLACK); arduboy.setTextSize(1); arduboy.setCursor(0,HEIGHT-7); sprintf(_microcanvas_textbuffer,"%lums",now>>2<<2); arduboy.print(_microcanvas_textbuffer);};`
});

Drawing the large background text is MEGA slow (at size 3 we are blowing the frame budget on every frame):

  game.drawText("Sprite\nDemo", 0,0, 3);

Try changing the text size (last parameter), on size of 1 the main render loop takes 4ms, the size of 2 doubles the width/height of the draw image, and the loop render time inflates to 12ms. This is still inside the ~16ms that is required for 60 fps but at size of 3 this will take almost two complete frames to render (28ms).

Note:

The display of the ms value is currently rounded (see the now>>2<<2 part) that will introduce a small skew (those numbers are 3/4, 14/15 & 29/30 milliseconds, respectively). This may or may not be acceptable for some performance usecases, if these cause an issue the snippets can be modified to better reflect the actual results

Note 2:

Note the { an } (opening and closing curly braces) on the start/end of the two snippets. These make sure a new block scope is opened so now is defined as a new variable. This is needed to avoid scoping and variable redeclaration issues, but also require that you use the snippets in pairs.

#include <SPI.h>
#include <EEPROM.h>
#include <avr/pgmspace.h>
#include <Arduboy.h>
Arduboy arduboy;
// frame counter, 2-byte unsigned int, max 65536
unsigned int _microcanvas_frame_counter = 0;
// sprintf() textbuffer for drawText
char _microcanvas_textbuffer[32];
// global state machine
unsigned int _microcanvas_state;
// global current drawing color
unsigned int _microcanvas_fill_color = WHITE;
#define LENGTHOF(x) (sizeof(x) / sizeof(x[0]))
PROGMEM const unsigned char gfx_bats[] = {
/*16x6x2*/ 0x01, 0x0f, 0x0e, 0x1c, 0x38, 0x3c, 0x1b, 0x3e, 0x3e, 0x1b, 0x3c, 0x38, 0x1c, 0x0e, 0x0f, 0x01, 0x1c, 0x0e, 0x0c, 0x07, 0x0e, 0x0c, 0x1b, 0x3e, 0x3e, 0x1b, 0x0c, 0x0e, 0x07, 0x0c, 0x0e, 0x1c };
const byte GFX_BATS_WIDTH = 16;
const byte GFX_BATS_HEIGHT = 6;
const byte GFX_BATS_FRAMES = 2;
const byte GFX_BATS_FRAMESIZE = 16;
int x = 0;
int y = HEIGHT / 2;
int sx = 1;
int sy = 1;
int animation_speed = 8;
int c_sprite = 0;
void setup() {
_microcanvas_frame_counter = 0;
// cpuLoad() will only be 0 right after boot
if (!arduboy.cpuLoad()) arduboy.begin();
////// CUSTOM SETUP //////
}
void loop() {
if (!arduboy.nextFrame()) return;
++_microcanvas_frame_counter;
if (_microcanvas_frame_counter==60000) _microcanvas_frame_counter = 0;
////// LOOP CONTENTS TO FOLLOW //////
{ long now=millis();
if (arduboy.everyXFrames( animation_speed )) {
c_sprite = 1 - c_sprite;
}
x += sx;
y += sy;
if (x > (WIDTH - GFX_BATS_WIDTH) || x < 1) sx = -sx;
if (y > (HEIGHT - GFX_BATS_HEIGHT) || y < 1) sy = -sy;
arduboy.clear();
{
arduboy.setTextSize( 3 );
arduboy.setCursor( 0, 0 );
arduboy.print( "Sprite\nDemo" );
};
arduboy.drawBitmap( 0 + x, 2 + y, gfx_bats + GFX_BATS_FRAMESIZE*(c_sprite | 0), GFX_BATS_WIDTH, GFX_BATS_HEIGHT, BLACK );
arduboy.drawBitmap( 2 + x, 2 + y, gfx_bats + GFX_BATS_FRAMESIZE*(c_sprite | 0), GFX_BATS_WIDTH, GFX_BATS_HEIGHT, BLACK );
arduboy.drawBitmap( 1 + x, 1 + y, gfx_bats + GFX_BATS_FRAMESIZE*(c_sprite | 0), GFX_BATS_WIDTH, GFX_BATS_HEIGHT, WHITE );
now=millis()-now; arduboy.fillRect(0,HEIGHT-8,WIDTH/2,8,BLACK); arduboy.setTextSize(1); arduboy.setCursor(0,HEIGHT-7); sprintf(_microcanvas_textbuffer,"%lums",now>>2<<2); arduboy.print(_microcanvas_textbuffer);};;
////// END OF LOOP CONTENTS //////
arduboy.display();
}
#include <SPI.h>
#include <EEPROM.h>
#include <avr/pgmspace.h>
#include <Arduboy.h>
Arduboy arduboy;
// frame counter, 2-byte unsigned int, max 65536
unsigned int _microcanvas_frame_counter = 0;
// sprintf() textbuffer for drawText
char _microcanvas_textbuffer[32];
// global state machine
unsigned int _microcanvas_state;
// global current drawing color
unsigned int _microcanvas_fill_color = WHITE;
#define LENGTHOF(x) (sizeof(x) / sizeof(x[0]))
PROGMEM const unsigned char gfx_bats[] = {
/*16x6x2*/ 0x01, 0x0f, 0x0e, 0x1c, 0x38, 0x3c, 0x1b, 0x3e, 0x3e, 0x1b, 0x3c, 0x38, 0x1c, 0x0e, 0x0f, 0x01, 0x1c, 0x0e, 0x0c, 0x07, 0x0e, 0x0c, 0x1b, 0x3e, 0x3e, 0x1b, 0x0c, 0x0e, 0x07, 0x0c, 0x0e, 0x1c };
const byte GFX_BATS_WIDTH = 16;
const byte GFX_BATS_HEIGHT = 6;
const byte GFX_BATS_FRAMES = 2;
const byte GFX_BATS_FRAMESIZE = 16;
int x = 0;
int y = HEIGHT / 2;
int sx = 1;
int sy = 1;
int animation_speed = 8;
int c_sprite = 0;
void setup() {
_microcanvas_frame_counter = 0;
// cpuLoad() will only be 0 right after boot
if (!arduboy.cpuLoad()) arduboy.begin();
////// CUSTOM SETUP //////
}
void loop() {
if (!arduboy.nextFrame()) return;
++_microcanvas_frame_counter;
if (_microcanvas_frame_counter==60000) _microcanvas_frame_counter = 0;
////// LOOP CONTENTS TO FOLLOW //////
{ long now=millis();
if (arduboy.everyXFrames( animation_speed )) {
c_sprite = 1 - c_sprite;
}
x += sx;
y += sy;
if (x > (WIDTH - GFX_BATS_WIDTH) || x < 1) sx = -sx;
if (y > (HEIGHT - GFX_BATS_HEIGHT) || y < 1) sy = -sy;
arduboy.clear();
{
arduboy.setTextSize( 3 );
arduboy.setCursor( 0, 0 );
arduboy.print( "Sprite\nDemo" );
};
arduboy.drawBitmap( 0 + x, 2 + y, gfx_bats + GFX_BATS_FRAMESIZE*(c_sprite | 0), GFX_BATS_WIDTH, GFX_BATS_HEIGHT, BLACK );
arduboy.drawBitmap( 2 + x, 2 + y, gfx_bats + GFX_BATS_FRAMESIZE*(c_sprite | 0), GFX_BATS_WIDTH, GFX_BATS_HEIGHT, BLACK );
arduboy.drawBitmap( 1 + x, 1 + y, gfx_bats + GFX_BATS_FRAMESIZE*(c_sprite | 0), GFX_BATS_WIDTH, GFX_BATS_HEIGHT, WHITE );
now=millis()-now; arduboy.fillRect(0,HEIGHT-8,WIDTH/2,8,BLACK); arduboy.setTextSize(1); arduboy.setCursor(0,HEIGHT-7); sprintf(_microcanvas_textbuffer,"%lums",now>>2<<2); arduboy.print(_microcanvas_textbuffer);};;
////// END OF LOOP CONTENTS //////
arduboy.display();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment