Game Design Game Development Geek / Technical

Freshly Squeezed Progress Report: Faster Dungeon Rendering At Last?

Last week, I reported I was optimizing the dungeon rendering code using a profiler for The Dungeon Under My House, my second Freshly Squeezed Entertainment project.

I continued optimizing, with an eye toward reducing the number of calculations that needed to occur when rendering the floors and ceilings, my main bottlenecks.

Sprint 2024-4: Pre-production and initialization

Planned and incomplete:

  • Render dungeon based on light levels

Two weeks ago, I reported that while I could light up the dungeon, it was too slow, but then I fixed a silly architectural representation issue that was slowing things down needlessly and it was much faster.

In the next week, I continued optimizing because while it was faster and rendering much more efficiently (and so uses fewer hardware resources and costs less electricity and saves battery usage on mobile devices), I wasn’t satisfied and wanted even more performance improvement.

The Dungeon Under My House - profiler output

Thanks to the use of an actual profiler, I could see the bottlenecks were specifically drawing the floors and ceilings, but I could also see that there wasn’t any one thing within those functions that was the bottleneck. There were a lot of different things that contributed to the slowness, and the main culprit was that so many pixels needed to be drawn each frame, each of which uses all of that processing capacity.

This past week, I got a late start on my game development efforts, but I managed to make some changes to draw pixels only when needed, which helped a lot, plus some other improvements.

At first, I thought I was going to need to draw the walls and doors and such to a buffer, then scan through the buffer to find pixels that weren’t drawn to yet, then draw the ceilings and doors for only those pixels.

But as I was working with SDL2’s textures, and textures by and large are not optimized to be read from, I was worried that this approach was going to be too slow even if I did cut down on the number of pixels I needed to process.

Instead, it turns out that I already had the information I needed when I drew the walls, so there was no need to read each pixel.

See, when I raycast walls, I keep track of the depth at each column. If I hit a wall, I know how far away from the camera it is.

This depth information was helpful for drawing things like doors and ladders around the existing walls, and it can now be helpful to draw the ceilings, which used to be drawn first and flood filled the background.

When I attempt to draw a ceiling pixel, I can check the projected distance associated with that pixel, compare it to the known depth of the wall, then draw only if the depth of the pixel is closer.

I was making many of my optimizations just for the drawCeilings() function, mainly so I can compare it to the drawFloors() function. Before optimization efforts started, those two functions looked very similar, so comparing their performance tells me if I am making actual improvements.

The Dungeon Under My House - profiler output

And it was an improvement, but it wasn’t as nice of an improvement as I was hoping for, mainly because the only calculations I skip are related to grabbing the texture and lighting data.

Many of the optimizations I did earlier were to move as much of the calculation out of the inner loop as I could, and I suppose now that the inner loop might be processed fewer times that it might make sense to move those calculations back, but I suspect the inner loop still does too much work and things will slow down again. After all, a smaller percentage of a lot of pixels is still a lot of pixels, relatively.

However, the profiler helped me to find that I was needlessly creating and deleting objects, so I did more inline calculations at the bottlenecks, and it helped get the performance of drawCeilings() significantly more efficient compared to drawFloors().

When I animate transitions normally, it feels very smooth, even without making the same kind of improvements to drawFloors() yet. However, if I increase the length of time to animate transitions, I can tell that my mouse cursor doesn’t render as often as when the screen is stationary.

It’s tolerable, I suppose, especially for this game which does not rely on real-time twitch muscles to play, and the mouse cursor isn’t relevant when playing on a mobile device, but I hate that it feels noticeably laggy at times.

That said, I should finish up my optimization work soon and move on to more game content work, such as creating a real dungeon level to replace the test dungeon I have come to know and love. The rest of the game needs attention, and I think I could spend forever on optimization code if I allow myself to.

Thanks for reading!

Want to learn when I release The Dungeon Under My House, or about future Freshly Squeezed games I am creating? Sign up for the GBGames Curiosities newsletter, and download the full color Player’s Guides to my existing and future games for free!

One reply on “Freshly Squeezed Progress Report: Faster Dungeon Rendering At Last?”

Comments are closed.