I’ve needed to draw pixel art (think Stardew Valley or Terraria) at a larger scale and can think of a few different approaches to this problem, so I decided to run some benchmarks. Project will be included if anybody can think of additional optimizations.
In this test I’m going to draw an 8x8 graphic at 32x, so 256x256. Before timing anything, I generate a two dimensional array of randomized colors. I run each test 1000 times and take the average. All the tests produce the correct results, timing is the only interesting part here. The Xojo version I’m using is 2025r2.1.
The first test uses FillRectangle to draw each “pixel” as a 32px rectangle.
The second test uses RGBSurface to set all 65,536 pixels individually.
The third test creates an 8x8 picture, sets all 64 pixels with RGBSurface, then uses DrawPicture to draw it scaled up on another picture.
These are all pretty fast operations, so measurements are in microseconds. Results are somewhat surprising. Except for test 2, that was always going to be the worst performer.
Platform
FillRectangle
RGBSurface
RGBSurface + DrawPicture
Mac
71.36
5503.65
208.88
Windows
102.98
11839.47
84.12
This topic is really just for discussion / sharing of knowledge. It looks like my best option is a platform-specific implementation.
Well… nevermind. There’s definitely some sort of performance improvement from running the test multiple times and/or in sequence.
If I retry with a single execution, and each launch only runs a single test, the results are dramatically different:
Platform
FillRectangle
RGBSurface
RGBSurface + DrawPicture
Mac
171.08
5516.58
306.58
Windows
11515.30
10517.40
11839.60
I’m not sure exactly what to attribute the difference to, though I suspect memory allocation. I think a clear takeaway though is that Windows drawing performance is terrible.
I do, but I can’t find which function you’re talking about. Google finds the FileMaker version just fine, but nothing for Xojo. I’m sure it’s there, I just don’t know which I’m looking for.
I’ve added a 10ms delay between execution in an attempt to let memory clear out. This seems to produce more accurate results, but I still can’t say I know with confidence exactly what this effect I’m seeing is. The tests are now triggered one at a time using buttons on the window.
I added the PixmapShape version and alternate bit depth. Neither made any meaningful difference.
Platform
FillRectangle
RGBSurface
RGBSurface + DrawPicture
PixmapShape
Mac
518.22
6239.92
1101.63
1079.36
Windows
117.87
10520.23
103.82
109.37
Assuming these results are accurate (I have my doubts) it seems like FillRectangle is the best choice. But I doubt these results because the Windows results blow the Mac results out of the water, contrary to the last test. And I’ve spent so much time in Xojo that I know Windows drawing is slower. The 10ms between executions is likely pointless on Windows.
Thanks. Looks like I don’t have that plugin loaded, so it’ll have to wait for another time to test its performance. My gut says if I try to create the 8x8 Xojo picture, then create a GMImageMBS from that, resize it, and convert back to the Xojo picture, performance won’t be better. There’s too many conversions there. However, if I learn how to draw the 8x8 to a new GMImageMBS directly instead of converting from the Xojo picture, that has more potential.
Good question. Yes, they are dynamic. That’s why I generate that stuff inside the loop. I do use caching but I’m really trying to test the performance of generating a picture to add to the cache.
But that gives me an idea. It may be more performant to built a sprite sheet first and draw pieces of that into the individual tile pictures.