Speed up print()?

Is there any way to improve the performance of the print command?

After printing like 3 rows of text (21 characters wide) the drawing performance really starts to suffer.

I know the print command is intensive as it has to go grand grab each letter from memory and draw it individually. But, which part of that process is what is actually the majority of the performance hit? Is it the fact that it is just making 21x3 independent draw calls? That doesn’t seem right because it can draw plenty of sprites, so is it having to go and grab everything from memory?

Anyways, I’m wonder if it’s possible to prepare a full string and print it to an image buffer, so that printing that string is only one draw call?

I know one “manually” solve this would just create my own pixel match equivalent of the printed text in mspaint, and import it as a bitmap… but is there any way to do this at run/compile time within the code?

Don’t clear the screen and print one character at a time if you can.

If that’s not an option convert font to spritesheet and draw them as sprites.

Yoo could also make bitmaps of the complete lines and only draw the partial line with text

1 Like

This is what I want to do, but I’d prefer to not recreate them on my pc.

Lol is there a pipe command in c++?

arduboy.print() | imgBuffer

just take a screenshot of the emulator and resize and edit that

2 Likes

Good suggestion, still makes me sad.

1 Like

Theoretically it’s completely possible to ‘draw’ image data into RAM and then copy the RAM buffer to the main screen buffer, but there’s no built-in functions for doing it, you’d have to ‘borrow’ and rewrite the ones from the library so they write to a provided buffer instead of the screen buffer.

@Mr.Blinky’s suggestion of not clearing the screen is by far the easiest solution.
If you need to clear other parts of the screen then you can use the rectangle fill functions, or Sprites::drawOverwrite.

Not clearing the screen works, it just means more extra work to determine what should be active or not.

Drawing the bitmaps just means replacing some print functions.

Hmm do I want to do my extra work in photoshop or text editor? hmmm

Ah ok, that was kind of my question, it would be neat if it existed hint

Nah but that could probably be it’s own helper library.

Actually I realized for my implementation so long as I am overwriting the white block with a black block, I can just forego blanking the screen after the first line is drawn since nothing needs to be deleted.

The main reason it doesn’t is because it’s usually not very useful.

Usually any time spent drawing to a buffer would be better spent drawing directly to the frame buffer.
Doing enough work that it needs to be split over multiple frames is quite unusual.

Slow-printing the text isn’t much work, it’s just a matter of maintaining an index into the text and incrementing it once per frame until it reaches the end.
(Bear in mind that the cursor should still be in the right place at the next frame as long as it hasn’t been changed.)

E.g.

if(textIndex < textLength)
{
	arduboy.write(pgm_read_byte(&text[textIndex]));
	++textIndex;
}

And your blinking cursor would be something like:

arduboy.fillRect(arduboy.getCursorX(), arduboy.getCursorY(), 16, 16, blinkCursor ? WHITE : BLACK);

if(arduboy.everyXFrame(5))
	blinkCursor = !blinkCursor;

What exactly is that makes printing the characters so much slower than drawing bitmaps?

Or is it just my perception? I feel like we can draw 50 bitmaps at the same time without a performance hit so why should print be all that different?

I just ran the hex on my arduboy and noticed the slowdown. It’s easier to notice on hardware.

I was thinking, do you use a delay to print the next character? if so you could also use the millis counter to count passed millis for a steady

1 Like

Nah it’s set at 60fps and trying to print as fast as it can.

I take that back, it prints every other frame.

I might be able to do it based on millis but that would have to happen before the frame counter which would cause other problems.

I’m gonna do partial screen updates… after lunch.

each character is drawn one pixel at a time:

  for (uint8_t i = 0; i < 6; i++ )
  {
    line = pgm_read_byte(bitmap++);
    if (i == 5) {
      line = 0x0;
    }

    for (uint8_t j = 0; j < 8; j++)
    {
      uint8_t draw_color = (line & 0x1) ? color : bg;

      if (draw_color || draw_background) {
        for (uint8_t a = 0; a < size; a++ ) {
          for (uint8_t b = 0; b < size; b++ ) {
            drawPixel(x + (i * size) + a, y + (j * size) + b, draw_color);
          }
        }
      }
      line >>= 1;
    }
  }
1 Like

The drawPixel serialization seems to be due to size>1 support; for size=1, the code could reuse the bitmap draw code plus a separate “draw separator” line. but that’s at the cost of code size since right now, the drawChar() function doesn’t know if you’re using Sprite or SpriteB and might pick incorrectly.

1 Like

Ah! Ok this is starting to ring a bell, I think we covered this very early on in Arduboy production, I think I remember seeing a fast print function that someone made come to think of it that spit the whole bitmap out at a time.

Could we do that, add a fastPrint() function that can only print at size 1?

The bigger issue is being able to print at any location not just on even byte boundaries in the display buffer.

The bottom line is that there’s been pretty much no one asking for faster text rendering. It’s the kind of specialty thing that you would write within your sketch for your own needs, or create a separate library for. Cluttering up the library with rarely used functions tends to make things more confusing.

The current drawChar() function could possibly improved for speed but I wouldn’t want it to result in increased program size because, again, for most people size is more important than speed.

image

If you want to restrict yourself to only being able to print with the Y coordinate being a multiple of 8 (0, 8, 16, 24 …) and also restrict to size 1, a custom fast drawChar() function should be pretty simple to write. The font array in the library is public access.