So, I’m working on some game code for RETRO, and it looks like clearing and redrawing the screen on every tick is pretty slow and inefficient.
I know that in the pre-loaded pong clone, the game elements (the ball and the paddle) are “erased” by being drawn in black, then redrawn in their particular color, which results in less flicker overall, since less of the screen is being drawn to.
Is this the best pattern for erasing and drawing game elements, even if there may be dozens of elements on screen?
@ devhammer - You can potentially play around with the draw window so you only write a little bit. You could also erase only part of the shape, like if a rectangle moves 1px to the right, erase the left-most column of pixels, though it would complicate the code quite a bit.
Another optimization that may not have made it into the preloaded demo is only redrawing the element if its position has moved. You could also vary the refresh rates of certain elements: update the score once per second, a paddle ten times a second, a ball twenty times a second.
It’s hard to say what the best pattern might be, it’s usually a trade off between code complexity and size versus performance.
I’ll check it out, but I think the problem I’m having is trying to translate the game knowledge I bring from HTML5 Canvas to the more limited embedded world (and translating to C++).
In drawing on canvas, you generally erase and redraw the entire canvas for every frame, and since modern PCs and browsers are quite fast, there’s no real performance issue there. It’s quite plain, from the code I’ve written so far, that such an approach will not perform well on RETRO.
I’m storing the objects I’m drawing in a vector, and looping through them on each call to tick, and was initially just clearing the display and redrawing everything. I’m in the process of refactoring to just draw what’s new (or moved items) and eliminate the existing drawn item by redrawing it with black. My initial cut at that looks a lot nicer, though I’m also seeing the game crash completely after only a few seconds of tick being called. I’ll probably start another thread for that issue, though.
Agree on the trade-offs. One of the reasons I persist in embedded dev, despite it not being something I get paid to do, is that it challenges me to think harder than desktop or web dev in a number of ways.
Trying to figure out how best to handle the limited resources is a good challenge, even if it’s frustrating at times.
@ devhammer - Something else to keep in mind is that a big bottle neck is the display interface. Say the SPI is at 10MHz, that’s 1.25MB/s. With an entire screen taking up 41KB (1281602) that leaves you with 30FPS if you do nothing else. You can increase the clock, 20MHz would give you 60FPS, but you are still dedicating a lot of your time to sending data to the display.
which seems to indicate that the SPI frequency is tied to the CPU clock frequency.
I looked at the datasheet for the display controller (found here on the resources tab https://www.ghielectronics.com/catalog/product/425), but I don’t have the experience reading SPI specs to figure out what the max frequency the display would work with is.
I did test one of my projects (mod of the pong game) at 48Mhz, and it worked, but I didn’t see any real difference with just the paddle and ball. Still seeing a bit of repainting related distortion on both paddle and ball, even at 48Mhz.
I also tried it on the project where I’m drawing 20 or so rectangles on the screen, with similar results.
From my testing it looks like 48Mhz is the max that works…anything higher, and the refresh rate on the display drops precipitously.
@ devhammer - You’ll want to verify that the clock actually is at 48MHz though. There is usually a source clock which is divided to get the SPI clock. Given that it is always integer division, you will see a lot of rounding. Performance probably drops once you try to go higher because the the clock value or divider is overflowing and starting back closer to 0.
I want to say the N18 has a max SPI clock of 12 or 24MHz, but I’m not sure off of the top of my head.
Given that he’s running this on mBuino, I assumed that it should mostly “just work” on RETRO, but even after updating the pin assignments to match what the N18 driver uses, I’m just getting garbage on the display (odd pattern of white rectangles).
I’m going to keep playing with it since his driver has a few more features than the DisplayN18 driver, but wondered if anyone else had suggestions or a working example.
UPDATE - It helps a great deal if you actually check to make sure the API is the same before assuming it will work. The DisplayN18 driver version of fillRect uses x, y, width, height, while the LCD_ST7735 uses x1, y1, x2, y2. Once having corrected for that difference, everything’s working fine.