Page 1 of 1

Noesis and Threading

Posted: 05 Mar 2014, 15:25
by HeinrichduToit
Hello

I’m in the progress of designing my program now.
I was wondering if it is possible to use threads to optimize the process.

Now I am well aware that openGL context is locked to a single thread.
But would it be possible to run some of the noesis processing in a different thread while the main thread draws the rest of the scene?

I was thinking about this part of the code:
NsGetKernel()->Tick();
xamlRender1->Update(((double)curTime-startTime)/1000.0);
commands = xamlRender1->WaitForUpdate();

Do I need to implement a mutex then to make sure this isn’t executing at the same time than xamlRender->Render()?
Would I see any real benefit from this? How processor intensive is the above mentioned code?

Thank you for your response, I’m just trying to find ways to use the multi-core architecture efficiently if possible.

Best Regards

Re: Noesis and Threading

Posted: 05 Mar 2014, 16:19
by jsantos
Our API offers two multithreading opportunities:

1. Update() work is always redirected to one of our internal worker threads. This mean that this function returns immediately. The work is collected in the WaitForUpdate(). So between Update() and WaifForUpdate() you should do more things. Ideally you should do:

. Proces Input
. Update
. Do your things
. WaitForUpdate
. Render

Note that, if you have several renderers each one is updated in parallel.

2. xamlRender->Render() does not interact with any state of the noesisGUI renderer. It only invokes GL/DirectX function. So, yes, it can be done in parallel to update. In fact, the ideal scenario is that you invoke this function from your render thread.

The real benefit depends on the kind of scene and how much work your application can do in parallel to the render. But in all the scenarios we tried the conclusion is that it is worth the effort.

Regards.

Re: Noesis and Threading

Posted: 09 Mar 2015, 17:39
by TheSHEEEP
Slight thread necroing because I have a few more questions about this:

I have a program with a multi-threaded environment, too.
Ignoring all other things, there is a gameplay and a rendering thread.
My plan is to do the following:

On the gameplay thread I basically have the following loop:
- NoesisGUI->Update()
- Input & script handling, things that can affect NoesisGUI
- RenderCommands = NoesisGui->WaitForUpdate()

1. Is that even possible? What happens when you make changes to the GUI (let's say, change a text, move the mouse cursor) while the Update() is going on in the background? I could live with it if the changes were applied in the next frame, but if it crashes or breaks stuff, that would be bad.

2. If the above is not possible, how could I make use of the time between Update() and WaitForUpdate()?
I could do it like this, but that would require much more implementation time:
- Input handling
- Apply buffered GUI changes
- NoesisGUI->Update()
- Script handling, if something comes up for the GUI (i.e. changing a text), it gets buffered and applied in the next frame
- mRenderCommands = NoesisGui->WaitForUpdate()

3. My render thread does the following:
- Ogre rendering, calling the next line on its own:
- NoesisGui->Render(mRenderCommands.offscreenCommands.GetPtr())

Should the "mRenderCommands" not be mutexed? Otherwise, it would be possible that the renderCommands.offscreenCommands are changed by the gameplay thread while the NoesisGui rendering in the render thread tries to use them.

Re: Noesis and Threading

Posted: 11 Mar 2015, 21:48
by jsantos
On the gameplay thread I basically have the following loop:
- NoesisGUI->Update()
- Input & script handling, things that can affect NoesisGUI
- RenderCommands = NoesisGui->WaitForUpdate()

1. Is that even possible? What happens when you make changes to the GUI (let's say, change a text, move the mouse cursor) while the Update() is going on in the background? I could live with it if the changes were applied in the next frame, but if it crashes or breaks stuff, that would be bad.
Exactly. That is the way our API is expected to be used. If you make changes to the GUI while an Update is in flight those changes would be applied in the next frame.

3. My render thread does the following:
- Ogre rendering, calling the next line on its own:
- NoesisGui->Render(mRenderCommands.offscreenCommands.GetPtr())

Should the "mRenderCommands" not be mutexed? Otherwise, it would be possible that the renderCommands.offscreenCommands are changed by the gameplay thread while the NoesisGui rendering in the render thread tries to use them.
No mutex is needed. The commands returned by WaitForUpdate are copied and the next frame will generate a new set of commands. You must only take care to always have an update tick per render tick. Probably the best solution is having a thread-safe queue where you push the commands in the gameplay thread. The render thread waits on that queue.

Re: Noesis and Threading

Posted: 12 Mar 2015, 11:17
by TheSHEEEP
Ah, good news! Thanks.

Two more things:

1. Since our threads run on independent frame rates, it is possible that the gameplay thread creates more than one RenderCommands per frame of the graphics thread. It is actually likely as graphics threads ar usually the bottleneck. So when the graphics thread starts a new frame, it can happen that there have been 2 or 3 updates to the RenderCommands.

I assume that you have to use only the latest RenderCommands and drop the rest in such a situation, right?

2. Assuming the other way around, which is theoretically also possible. The graphics thread has a new frame, but there are no new RenderCommands. Would it be better to not call Noesis->render() at all (we are rendering directly to a texture, so not rendering again just means keeping the current texture), or use the old RenderCommands?
I would assume that the first way could save some performance, but am not sure if it is harmful in any way.

Re: Noesis and Threading

Posted: 13 Mar 2015, 14:03
by jsantos
1. Since our threads run on independent frame rates, it is possible that the gameplay thread creates more than one RenderCommands per frame of the graphics thread. It is actually likely as graphics threads ar usually the bottleneck. So when the graphics thread starts a new frame, it can happen that there have been 2 or 3 updates to the RenderCommands.

I assume that you have to use only the latest RenderCommands and drop the rest in such a situation, right?
Yes. That is correct.
2. Assuming the other way around, which is theoretically also possible. The graphics thread has a new frame, but there are no new RenderCommands. Would it be better to not call Noesis->render() at all (we are rendering directly to a texture, so not rendering again just means keeping the current texture), or use the old RenderCommands?
I would assume that the first way could save some performance, but am not sure if it is harmful in any way.
Hmmm... it is a bit strange that you are kicking a new render frame without having done the update part. At least, in all the integrations we have done so far, we never found such scenario. But yes, you can reuse the old RenderCommands if you need to repaint the surface.

Re: Noesis and Threading

Posted: 16 Mar 2015, 13:12
by TheSHEEEP
Thanks again!

In the meantime, only one new question popped up that may be of interest to other people as well :)

How many internal threads does Noesis GUI start? We already have a number of threads of our own, and it would help us managing a bit if we know how many "external" threads get into the mix.

Is it a number of X job threads, or one background thread per renderer?

Btw. this whole thread would make a wonderful FAQ section.

Re: Noesis and Threading

Posted: 17 Mar 2015, 17:05
by jsantos
How many internal threads does Noesis GUI start? We already have a number of threads of our own, and it would help us managing a bit if we know how many "external" threads get into the mix.

Is it a number of X job threads, or one background thread per renderer?
Right now a thread per hardware thread is created. So for example, in a dual core hyperthreaded machine, 4 threads are created. But this is something that is going to change soon because we don't like the idea of creating threads in the user code. In fact, this is only happening right now in Win32 32bits. We prefer the idea of providing a proper API that our users must call from their threads. That is the idea of the Update/Render API of each renderer.