Feasibility/correctness of calling GL in another thread

Stefanos A. wrote:

2014/1/23 slimshader <@slimshader (@slimshader)>

Stefanos A. wrote:

After trying several threading strategies, my current preference is to keep rendering and window management to the main thread, but handle input on a secondary thread. So far, this has proven the best method to maintain responsiveness without impacting compatibility.

But how that does help? If main thread is blocked, then you don’t refresh your screen to show the impact of processed events. In my experience event handling is tiny fraction of a frame. Do you mean that with 2nd thread event handling you avoid “busy” system cursor / window appearing to hang?

The point is not to improve performance but to minimize latency between the user pressing a button and the world reacting to that button press.

If you handle input in your rendering thread, then any dip in the framerate will increase input latency, which can be jarring (esp. on slower systems that cannot maintain a stable framerate.) By spawning a separate thread for input, the OS scheduler will “smoothen out” input latency even when your framerate dips below 10 fps.

Of course, this only helps if your world update rate is decoupled from your framerate. In my case, I will skip up to 12 frames in order to guarantee a pseudo-fixed update rate. In other words, I prioritize world updates (60 updates/sec no matter what) and only render frames as a best-effort.

This way, if the player presses the “fire” trigger then she will shoot the enemy immediately even if she is running at 5 fps.

If the input was handled in the same thread, then the “fire” button would take up to 200ms to register - or it would be skipped completely, if the player lifted her finger before the 200ms mark. This would place the player at a severe disadvantage (hi, Diablo 3!)

Clean now :slight_smile:

A question: I just tried to build minimal GL ES2 app under Win but I am getting unresolved externals for glClear, glClearColor and 2 more in sdl_main function. So it clearly wants to use full GL. I assume you use SDL2 with ANGLE?

I am using ANGLE with and without SDL2, but I’m using C#/OpenTK which loads
both libraries dynamically - so I cannot really help you on these errors,
sorry. (“Dynamically” in this case means using LoadLibrary +
GetProcAddress(“eglGetProcAddress”) and then using eglGetProcAddress to
load the rest of the entry points.)

IIRC, I had to compile SDL2 from hg in order to get ANGLE working, but it
was otherwise straightforward.

2014/1/23 slimshader <szymon.gatner at gmail.com>>

Stefanos A. wrote:

2014/1/23 slimshader <>

Quote:

Stefanos A. wrote:

After trying several threading strategies, my current preference is to
keep rendering and window management to the main thread, but handle input
on a secondary thread. So far, this has proven the best method to maintain
responsiveness without impacting compatibility.

But how that does help? If main thread is blocked, then you don’t refresh
your screen to show the impact of processed events. In my experience event
handling is tiny fraction of a frame. Do you mean that with 2nd thread
event handling you avoid “busy” system cursor / window appearing to hang?

The point is not to improve performance but to minimize latency between
the user pressing a button and the world reacting to that button press.

If you handle input in your rendering thread, then any dip in the
framerate will increase input latency, which can be jarring (esp. on slower
systems that cannot maintain a stable framerate.) By spawning a separate
thread for input, the OS scheduler will “smoothen out” input latency even
when your framerate dips below 10 fps.

Of course, this only helps if your world update rate is decoupled from
your framerate. In my case, I will skip up to 12 frames in order to
guarantee a pseudo-fixed update rate. In other words, I prioritize world
updates (60 updates/sec no matter what) and only render frames as a
best-effort.

This way, if the player presses the “fire” trigger then she will shoot the
enemy immediately even if she is running at 5 fps.

If the input was handled in the same thread, then the “fire” button would
take up to 200ms to register - or it would be skipped completely, if the
player lifted her finger before the 200ms mark. This would place the player
at a severe disadvantage (hi, Diablo 3!)

Clean now [image: Smile]

A question: I just tried to build minimal GL ES2 app under Win but I am
getting unresolved externals for glClear, glClearColor and 2 more in
sdl_main function. So it clearly wants to use full GL. I assume you use
SDL2 with ANGLE?


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

I might be missing something here but how do you even implement a list
without tail pointer? You always keep at least one end otherwise it would
be inaccessible. In any case, node-based lists suck [image: Razz]

slimshader,
While I normally don’t reference Wikipedia for programming matters, look at
the tradeoff section ( http://en.wikipedia.org/wiki/Linked_list#Tradeoffs )
and particularly the chart where the last element is known. I was mostly
clarifying Nathan’s comment that keeping track of the last element will be
faster
rather than may be faster in case others wish to take his
approach. When he mentioned tail pointer, he meant keeping track of the
last element. Ultimately, the best choice of container is suited to the
particular problem and as Nathan mentioned, a singly-linked-list is easy to
implement. In some cases you may not have the luxury of using a standard
library and rolling your own is the only choice.

slimshader wrote:

I hear you, but I am in the niche of older machines, in fact I am having trouble even getting users to get OpenGL 1.4 work correctly (for VBOs (in fact I think it is about time I implement D3D renderer)), also mobile devices are not what you’d consider 2010s “gaming rigs”. That being said, secondary thread is (as I said before) not used to speed-up level loading but rather to keep main (event processing, rendering) thread responsive.

I do use task queues (double-buffered) but they are per-thread. Since cross-thread tasks are very seldom I don’t want them having locks all the time.

BTW. Since we are on threading / GL topic: do you guys render from main thread? What are your update vs render step strategies? If you do them on separate threads how do you sync later (condition vars seem obvious choice)?

It may still make sense to avoid the second thread by making tasks shorter. Use non-blocking or even asynchronous I/O, or memory mapping (all three options will require writing system-specific code), and you will find that resource loading tasks will not impede the render and event processing tasks (since upload to GPU already blocks other API calls on most implementations anyway). Blocking on file reads is probably the bottleneck pushing you towards the direction you’re going.

Jonathan Greig wrote:

I was mostly clarifying Nathan’s comment that keeping track of the last element will be faster rather than may be faster in case others wish to take his approach.

This is true 99% of the time, but not 100% of the time. Maintaining a tail pointer is occasionally not worth the added complexity, and I have seen situations in which it was actually an optimization to remove it. O(1) and O(n) for tail insertion are equal when there is only one element, but the O(n) code may actually perform better. This is why I disagree with professors and professionals alike treating the big-O notation as the silver bullet of algorithms. It is a useful tool, but there is never a silver bullet.------------------------
Nate Fries