🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

Render in other thread

Started by
12 comments, last by swiftcoder 2 years, 12 months ago

Hi All

I must draw “what user wants”, e.g. amount of geometry can be any. Sometimes my drawing takes several seconds per frame, and UI is frozen during this time. That's why I need to move render in a seperated thread. I understand it makes a lot of new probs with synchronization and does not make render faster. I would be really happy to avoid this and keep all in main thread, but I see no way “how”. So my first question is:

Is there other way(s) to avoid “freeze UI” prob"?

And the second question is “how”. I've read about “one context can operate with only one thread at a time”, but can't figure out what should I do?

I use Qt (QOpenGLWindow)

Thx

Advertisement

What games do is to try to avoid having too much visible geometry in one frame by using level-of-detail and similar techniques. Another way that is used in interactive renderers is to initially show big pixels and make them gradually smaller in successive frames.

Tommato said:
And the second qurestion is “how”. I've read about “one context can operate with only one thread at a time”, but can't figure out what should I do?

There was the ‘AZDO’ technique trying to solve some problems, maybe it helps: https://de.slideshare.net/CassEveritt/approaching-zero-driver-overhead

Tommato said:
Sometimes my drawing takes several seconds per frame,

Are those just some spikes, or is your scene indeed that large every frame takes that long?

I can not imagine rendering models could take a whole second. Is there some other processing going on as well?
Or are there a lot of state changes / shaders? Maybe shader compiling could be an issue?

JoeJ said:

I can not imagine rendering models could take a whole second. Is there some other processing going on as well?
Or are there a lot of state changes / shaders? Maybe shader compiling could be an issue?

I just want to second this. A whole second seems inordinately long to me. Perhaps there is some bug. I remember a couple months back I had some code where I was calling SetWindowText. There was a timer where it would only call it about every second. However I changed something and created a bug where it started calling it every frame. This not only caused my program to run many times slower by my entire system became unresponsive.

In any case, just make sure you simply don't have some dumb bug that's causing your problem. If your frame rate really is that slow, I would consider looking for ways to speed up your rendering. Of course you can do rendering in a different thread. I have many threads running in my current project. However I'm only using one thread for the actual rendering and that's also the Windows message loop and it's still blazingly fast.

Thx for the replies. Of course any draw code “can be better” but here the prob is not “a fat bug”, but arbitrary geometry amount. For example 1000 trees (50 K polys per each). Instancing helps a lot but not always, user's creativity has no limit ;-)

Ok, back to the theme. So I moved drawing into a seperated thread, and .. it works (bad omen, bugs should be). I understand I've got a megaton of probs with data sync. but it's another story. Looks like the “threading” needs nothing special, just a call to QOenGLContext::makeCirrent to bind (shared) context to the current thread (I did not debug what this call does inside), Also I saw a note that some cards require doneCurrent call after drawn. But that's all

Is it really so simple (in principle) in OpenGL?

Thx

Tommato said:

For example 1000 trees (50 K polys per each). Instancing he;ps a lot but not always, user's creativity has no limit ;-)

But you aren't drawing all 1000 trees in the same spot, which means some will be close to the camera but most will father away. This is why you have LOD (Level Of Detail) for you tree models. Trees in the distance should only have a fraction of the polys of your full tree models. Is this for a game or is this for some movie software or something along those lines? Because if it's for a game, a slow render time like this is pretty much untenable.

Tommato said:
Is it really so simple (in principle) in OpenGL?

It is simple as long as you still do all rendering in one thread. Usually you create render thread, then create context within that thread and start render loop after that. Maybe QT has tool function to move context to another thread, likely backed by automatic context recreation, but overall it should work like this.

I'm not sure if it is possible to submit draw commands from multiple threads using GL, using some tricks or hacks. I thought AZDO is related to that topic but not sure. Maybe somebody can answer…

However, GL can do indirect draws. So maybe it could help to move towards a compute driven scene management and renderer, e.g. doing culling on GPU and generate indirect draws for each object. If you have a really big number of draw calls this might help. But i guess it's a lot of work just to figure out it does not help at the end.

So at first i'd use some gfx debugging tools and look if they can show you something suspicious, like bubbles, overall underutilization, too much waiting on sync, etc.

Also try different GPUs. I've seen NV being much faster with rendering, but AMD being much faster with compute. Differences of factor 10 for similar powerful GPUs on paper. This can be a hint to try to do some things differently.

Then maybe it's an option to switch to Vulkan, where multithreaded rendering is easy, but drawing a first simple triangle already takes thousands lines of code.

For example 1000 trees (50 K polys per each).

Still does not sound much. You do batching by textures, states, etc. and such usual optimizations?

Oh, what i personally do to keep fps up is using some ‘stochastic culling’.
Say i have 10000 trees, but only want to draw 1000 each frame.
Then i generate a hash from object index and frame count, and make probability to randomly cull trees so only 1000 remain to render.
Ofc. it looks shitty flickering, but i can still make a mental image of all the trees that should be there.
Your users won't be impressed, but better than nothing for a quick fix.

Thx for the optimization advices, just the theme is a bit different. My app is more “editor” than “game”. For example, user opens a next .fbx file and the app should load and draw all file data, I can't show a message like "Stop, it's too much data for me". Yes, starting from a some limit a “real-time” display is out of the question. But the app should remain functional, sensitive to mouse and keys input.

Ok, back to the theme. It's interested what OpenGL does with threads? For me it looks like nothing, just all API calls are NOT thread-safe. And it's enough to protect calls with mutex (for example). Pseudo-code

void DrawGL( QOpenGLWindow * win )
{  
 theDrawMutex.lock();  
 win->makeCurrent();  
 ...  // setup shaders etc  
 glDrawElements(...); 
 ...   
 win->swapBuffers();  
 theDrawMutex.unlock();
}

Is it correct ?

Thx

Tommato said:
For me it looks like nothing, just all API calls are NOT thread-safe.

Still waiting on some advice to use OpenGL from multiple threads, but let's assume it's not possible,

Then you don't need a mutex? You just make sure all rendering is done from the thread which owns the context. There is nothing to win from using multiple threads while preventing hazards. All rendering is still serialized, but CPU may slow down due to waiting.

Found some remarks on MT rendering here: https://www.khronos.org/opengl/wiki/OpenGL_and_multithreading

So one could use multiple contexts (one per thread), but share resources like textures. May be worth to try.

This topic is closed to new replies.

Advertisement