Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / multimedia / OpenGL

Exploring Multi-Threading in C++: Loading Textures

5.00/5 (1 vote)
15 Nov 2019CPOL2 min read 4.9K  
Loading textures - exploring multi-threading in C++

Series of Articles

Problem Overview

Let’s say we have a game engine that uses OpenGL and we need to load textures asynchronously so that we don’t block the main thread, and we can load the editor or game much faster.

Now as previously demonstrated, I could launch a new set of threads and have them load up the textures (I’m using stb_image for that) and generate textures with glGenTextures. The main issue here is that OpenGL context is only available in the main thread so if we want to take advantage of multi-threading texture loading, we need to split the loading and generating for textures.

Loading is going to be done in worker threads, and generating textures will be done in the main thread. The following diagram shows a simplified workflow of what we’ll achieve.

Image 1

Simplified execution of loading textures in worker threads, and processing them in the main thread.

In our main thread, we have a method that will check our processing textures queue for a job. If it finds one, it generates the OpengGL texture and assigns it back to the material.

C++
void AssetManager::Update()
{
	if (!m_processingTexturesQueue.Empty())
	{
		TextureLoadJob assetJob;
		if (m_processingTexturesQueue.TryPop(assetJob))
		{
			// Generate OpenGL texture
			Texture outputTexture = GenerateTexture(assetJob.loadedData, assetJob.textureType);
			// Update Material
			assetJob.materialOwner->AddTexture(outputTexture);
		}
	}
}

The loader thread will continuously run and check the loading textures queue for jobs. In this case, I load the texture from a file path and assign the result into the loaded data.

C++
void AssetManager::LoaderThread()
{
	while (m_loadingThreadActive)
	{
		if (!m_loadingTexturesQueue.Empty())
		{
			TextureLoadJob assetJob;
			if (m_loadingTexturesQueue.TryPop(assetJob))
			{
				// Load texture data into asset job
				assetJob.loadedData = LoadTextureData(assetJob.texturePath);
				// push job into processing queue
				m_processingTexturesQueue.Push(assetJob);
			}
		}
		// ....
	}
}

Image 2

In game sponza scene.

This architecture allows me to load textures while the game is running without blocking the main thread. It's a bit pointless to compare times here since I’m using my own sandbox instead of a sample program to test only this matter. See Part 1 and Part 2 for more information and code you can follow along.

In the next part, we’ll parallelize a toy Ray Tracer. This a different problem on its own where we need to use the resulting values of multiple threads or jobs to build a final image.

Continue Reading

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)