Menu
Grend's Dev Blog
  • Advancement Plaques
  • Anthony Hilyard
  • Berry Season Reminder
  • Blog
  • Complex
  • Contact Me
  • Cooperative Advancements
  • Cross Section
  • Dungeon Defender
  • Dunwich
  • Equipment Compare
  • Improved Tracker
  • Stampede
    • Stampede Credits
    • Stampede Privacy Policy
  • Upgradable Pan
  • Weapons on Display
Grend's Dev Blog

Category: Uncategorized

Framerate Optimization and Simplifying Shaders

Posted on March 20, 2021May 27, 2021 by Grend

This post is going to get a bit into the weeds, so strap in. Over the last few weeks, when working on my still unnamed game project, I noticed that framerates were getting rather sluggish as I continued to add more and more dynamic entities, especially when I turned on all the "bells and whistles" and my debug overlay, which includes showing bounding boxes for everything in the game. This was especially apparent on my Linux machine with integrated graphics, where framerates could get as low as 25-30fps while displaying the debug overlay. I decided to take some time to investigate the cause and see what could be done about it.

Investigation

The rendering of the game is done in a few stages, composed of layers of static tiles and dynamic entities. Tiles are always in the same positions and generally don't change much, so rendering them is quite efficient, whereas entities can have dynamic positions and change all the time. I focused my attention first on the entities, since I suspected their additional complexity meant their rendering logic was more likely to be coded inefficiently.

I looked over my shaders, which had been written months ago at this point, and realized that in many of the fragment shaders, I was passing in information via data textures and looping over it to effectively support rendering overlapping entities.

Fragment Shader Pseudocode

// First data texture contains tile position and sprite coordinates.
sampler entityValues1

// Second data texture contains entity pixel offset and size.
sampler entityValues2


void main()
{
	foreach (entity)
	{
		get_data_from_textures()

		calculate_entity_position()

		get_entity_sprite()
		get_entity_size()


		calculate_pos_in_sprite()


		color = get_color_at_pos()

		if (color_is_visible)
		{
			break
		}

	}

	return color
}

It should be clear that this is incredibly inefficient. Fragment shaders are run by the GPU for every single pixel on the screen, every frame, so this is clearly contributing to the slowdown. This style of shader was likely a side-effect of the way I had developed the entire rendering framework in the engine. Everything was being rendered onto the same quad that covered the window, drawn multiple times with different shaders supplied with different data. Think of it like layers of transparencies on an overhead projector--simple, but it works (albiet inefficiently). In order to be able to use simpler shaders that don't require loops, I would have to split up the entities up front, having the shader take care of a single entity instead of the whole screen. And in order to do that, I would need to have each entity have its own dynamically-positioned quad.

The Process

I begun the long task of rewriting the rendering engine from the ground up, which required touching almost every piece of code that dealt with rendering. It also meant writing support for a few OpenGL features I hadn't had to worry about before, like a Vertex Array wrapper class. I rewrote the camera manager so I could more easily get the proper perspective view matrix for the new quads, simplified my texture handler class, since I didn't have to worry about data textures any more, and wrote a low-level quad handler. During the process, I even stumbled upon something surprising. From my C++ work, I've always learned to try to minimize branching where possible for time-critical code. When writing the quad handler (which converts entity quads to floating point values that OpenGL can use), my first attempt had a few if statements and a switch statement. I thought I could do better, so I worked to format the code in a way so there was absolutely no branching. I managed this by using a delegate map and calling these functions based on the "switched" value. Despite my efforts, I found that it was slower than before I had removed the branching. Stumped, I did a little digging and found that C#, unlike C++, is very unlikely to inline function calls and the overhead of actually calling these functions turned out to be more costly than some branching! Who knew?

Anyways, I eventually finished the process off by writing a much more elegant entity shader that only deals with a single entity at a time, and has all the data it needs from vertex attributes. Here's the actual GLSL code for the new shader:

#version 130

uniform sampler2DArray entitySheet;

in vec4 texCoordV;
out vec4 fragcolor;

void main()
{
	fragcolor = texelFetch(entitySheet, ivec3(texCoordV.xyz), 0);
}

Really doesn't get any simpler than that!

So, what now?

Rewriting the entity shader was just the first step, but it was probably the longest and most impactful change. I used the same techniques to dynamically create quads for everything except tiles, such as UI elements and text as well. It was a long learning process but the results were immediately apparent. I now get a consistent 300fps (when v-sync is disabled of course), even on the slow integrated graphics. Now that I don't have any concerns with the performance of rendering, I am happy to be able to move back onto working on game content and assets instead.

+

Updates and More

Posted on July 19, 2020February 15, 2021 by Grend

Progress is still coming along steadily in the still-(officially)unnamed game I have been spending most of my free time working on. I have a lot of details fleshed out (in planning) about the world, including locations, characters, story elements, items, and more with the game itself coming along nicely. Many of the main parts of the game's engine are functional, though there is still work to be done and a lot of content to be added.

I haven't shared many details about the game anywhere yet, but it is a game that starts with you moving to a new town full of unique people. These people hold some strange traditions and can be reticent or abrasive, but it's best not to judge them based on first impressions. Everyone has a past. It's up to you to get to know these people, and perhaps improve the town and the lives of your fellow residents. How you go about accomplishing that is something I will dive into deeper in the future. The game is made in the style of SNES-era 16-bit games, with some modern game features and influences. It has role-playing and adventure elements, as well as multiple storylines. I hope to give the player a feeling of importance, with clear progression over time, not just progression of the player's character, but of the whole game world.

I was encouraged to share my development process as I work, and I think it would be cool to have others have an inside look, so I have started occasionally streaming on Twitch as I work on the game. You can watch it here, I am going to try to stream at least once a week, with the most likely day being Saturday. I will be streaming some of the more interesting parts of my development process, such as coding, creating art assets, and more, but I will try to keep things like story details and secrets out of the stream.

+

A Quick Update

Posted on January 8, 2020February 15, 2021 by Grend

Happy new year! I'm just posting to give a quick update on the game I mentioned a while back, one that I had been planning off and on for over a year. I have moved on from the planning stage and actually started working on the game! I have been very busy in my spare time coding a from-scratch custom engine for it, which is coming along nicely, and I now have also started adding assets and game elements.

I have made games in the past, but this time feels different. I am learning a lot, and I am hopeful that this will turn out special. I want to create a world that people will want to sink into and care about, all the while having fun. I don't want to overshare so early, so I'll just leave you with this small teaser. Until next time.

+

Website is up!

Posted on October 1, 2019 by Grend

I've been working on getting this website up and running for a while now, and I think it's finally at a state I am happy with. I am hoping to use this site to mostly document my game development efforts, possibly with a little personal blogging mixed in.

I've currently got the blog set up, as well as a menu with pages for each game I hope to feature on the site. The home page will eventually be fleshed out (I have some plans), but for now I'm just going to leave an ugly "under construction" note.

If you're wondering who I am, my name is Anthony Hilyard. I go by Grend online. I am a software engineer with a great interest in game design. In my free time, I like to make games and some day I hope to be able to do it full-time. As of writing this post, I have released one game (Stampede), and have finished a handful of unreleased ones.

Check back periodically, hopefully there will be something interesting to see. Until then, thanks for reading!

+
MENUMENU
  • Home
  • Games
    • Stampede
    • Cross Section
    • Dunwich
    • Complex
    • Dungeon Defender
  • Mods
    • Minecraft
      • Advancement Plaques
      • Cooperative Advancements
      • Equipment Compare
    • Stardew Valley
      • Improved Tracker
      • Berry Season Reminder
      • Upgradable Pan
      • Weapons on Display
  • Blog
  • Contact