Multithreading

classic Classic list List threaded Threaded
18 messages Options
Reply | Threaded
Open this post in threaded view
|

Multithreading

Haroogan
Hey, everyone, I would like to know about multithreading ability in JOGL. In brief, I need to stream my terrain blocks from HD, therefore I consider 2 possible solutions:

1. I can stream  terrain blocks in a secondary thread and then in a primary thread (the JOGL one) upload vertex and index buffers' data to graphics card (I mean glBindBuffer, glBufferData and other functions, which we need to throw data to graphics card). In this case I won't have to carry about multithreading with JOGL, since I don't make any OpenGL calls in the secondary thread. However, I'm sure that these preparation calls (glBindBuffer, glBufferData and etc.) will cost me too much in the primary thread and will drop FPS hard, therefore I want to deal with solution n. 2.

2. Streaming and uploading (glBindBuffer, glBufferData and etc.) of terrain blocks is done in secondary thread. Obviously here I need to know how to deal with multithreaded OpenGL API calling.

So tell me, if I'm right about these considerations, and if I am, then let me know how to deal with solution n. 2.

Reply | Threaded
Open this post in threaded view
|

Re: Multithreading

Wade Walker
Administrator
Hopefully Demoscene or Julien can comment on this -- they've probably got direct experience doing it

I've always seen this suggested:

main thread:
    gl.glBindBuffer()
    gl.glBufferData()   // use null data pointer so no data is copied
    gl.glMapBuffer()    // returns a ByteBuffer or similar object

secondary thread:
    write data to mapped ByteBuffer

main thread:
    gl.glUnmapBuffer()

Supposedly, as long as you don't try to use that bound VBO in the main thread until after you unmap it, this allows you to move the expensive data write into a second thread. You also keep all OpenGl calls on the main thread, and don't have to share the GL context between threads, which reduces the potential for multithreaded programming errors or driver bugs with context sharing.

You'll probably have to do some experiments to find the fastest way, since the performance of multithreaded programs can be counter-intuitive.
Reply | Threaded
Open this post in threaded view
|

Re: Multithreading

Haroogan
Could you make it more detailed, especially about "writing data to mapped ByteBuffer" in secondary thread... I guess you mean that glMapBuffer will return me ByteBuffer, which references some memory on graphics card and I should use this ByteBuffer in the secondary thread to write data to it? If yes, then how will OpenGL know how much memory to allocate for this ByteBuffer?
Reply | Threaded
Open this post in threaded view
|

Re: Multithreading

Wade Walker
Administrator
Here's some more detail. You'll still need more code to coordinate between the threads.

I'd strongly suggest getting this working in a single thread first, then trying to move the buffer fill to a second thread

I don't think the ByteBuffer is really memory on the graphics card. I believe it's in system memory, and is copied to the graphics card with a DMA when you call glUnmapBuffer().

main thread:
    gl.glGenBuffers( 1, aiVertexBufferIndices, 0 );

    // create vertex buffer data store without initial copy
    gl.glBindBuffer( GL.GL_ARRAY_BUFFER, aiVertexBufferIndices[0] );
    gl.glBufferData( GL.GL_ARRAY_BUFFER,
                             aiNumOfVertices[0] * 3 * Buffers.SIZEOF_FLOAT * 2,
                             null,
                             GL2.GL_DYNAMIC_DRAW );

    // map the buffer and write vertex and color data directly into it
    gl.glBindBuffer( GL.GL_ARRAY_BUFFER, aiVertexBufferIndices[0] );
    ByteBuffer bytebuffer = gl.glMapBuffer( GL.GL_ARRAY_BUFFER, GL2.GL_WRITE_ONLY );
    FloatBuffer floatbuffer = bytebuffer.order( ByteOrder.nativeOrder() ).asFloatBuffer();

secondary thread:
    // fill the buffer
    for( ... )
        floatbuffer.put( your data );

main thread:
    gl.glUnmapBuffer( GL.GL_ARRAY_BUFFER );
Reply | Threaded
Open this post in threaded view
|

Re: Multithreading

Haroogan
But you see, all those expensive operations of buffer preparation (I mean these gl calls) are done in rendering thread, it's going to drop FPS isn't it?
Reply | Threaded
Open this post in threaded view
|

Re: Multithreading

Wade Walker
Administrator
I'd suggest implementing your program first without any optimizations or multithreading at all. You could get lucky, it might already be fast enough

Then, once you've proved it's too slow, you can do profiling and testing to find the slow parts. It's very hard to guess which GL operations will be expensive unless you gather real performance data.

The operations glGenBuffers, glBindBuffer, glBufferData (with a null data pointer), and glBindBuffer seem like they're only creating a few small objects inside the graphics driver -- they shouldn't be copying any large amount of data.

However, you can't know for sure how the driver is implemented -- it could be doing something horrible, like locking some internal resource and waiting on it.

I always end up regretting when I try to optimize first, before measuring the problem with real data. Usually I waste a lot of effort, and then I have to redo the optimization once I measure the performance for real
Reply | Threaded
Open this post in threaded view
|

Re: Multithreading

Haroogan
Alright, thanks a lot WW, gotta try coding now ))
Reply | Threaded
Open this post in threaded view
|

Re: Multithreading

Demoscene Passivist
Administrator
In reply to this post by Wade Walker
>Hopefully Demoscene or Julien can comment on this -- they've probably got direct experience doing it

Not really  as I generally avoid multithreading with OpenGL. I've tried mutlithreading when I begun with OpenGL but made really discouraging experiences regarding driver stability on a lot of platforms. All OpenGL calls I do are made from on single thread, tho I do data preprocessing on multiple threads to later feed the data to the single "OpenGL-API-Call" thread.

So my advise is if u have to release ur application to a broad range of different OpenGL drivers: DON'T USE MULTITHREADING! If u know the platform/driver implementation and can actively test ur application on that setup, feel free to try it out: It may work for u.

As ur only reason to do multithreading seems to be better performance be aware the most OpenGL drivers are already multithreaded by default. The driver kind of "caches" ur calls and processes them in parallel as good as possible. This works regardless of ur application is multithreading aware or not. See "Best Practices for Multi-threading" from NVidia for further information on that. The document also covers some tips on OpenGL bufffer objects and how tooptimize them for multithreading use.

>You'll probably have to do some experiments to find the fastest way, since the
>performance of multithreaded programs can be counter-intuitive.

Exactly, as Wade points out here be 100% that u really get a benefit from multithreading. Maybe the benefit will only be 10% or stg like that wich would not be worth the effort. Try to get ur application up and running as single threaded version first, then optimize it to use multithreading afterwards if u see that singlethreading is the bottleneck of ur application.

>I need to stream my terrain blocks from HD

As a last note: Maybe u can work around the problem of loading big chunks from HD by reducing geometry data using tesselation in conjunction with displacenment mapping ? Or a more advanced geometry representation like NURBS ? Textures are genereally much easier to stream coz they can be interpolated on the fly ...

Reply | Threaded
Open this post in threaded view
|

Re: Multithreading

gouessej
Administrator
In reply to this post by Wade Walker
Wade's suggestion is fine, avoid making the context current on multiple threads, perform all OpenGL calls on ... the dedicated OpenGL thread. Manipulating a NIO buffer can be done on any thread but don't forget that the VBO must not be accessed by the rendering thread while you manipulate its buffer.
Julien Gouesse | Personal blog | Website
Reply | Threaded
Open this post in threaded view
|

Re: Multithreading

Sven Gothel
Administrator
In reply to this post by Demoscene Passivist
On Sunday, January 09, 2011 20:34:33 Demoscene Passivist [via jogamp] wrote:

>
> >Hopefully Demoscene or Julien can comment on this -- they've probably got
> direct experience doing it
>
> Not really  as I generally avoid multithreading with OpenGL. I've tried
> mutlithreading when I begun with OpenGL but made really discouraging
> experiences regarding driver stability on a lot of platforms. All OpenGL
> calls I do are made from on single thread, tho I do data preprocessing on
> multiple threads to later feed the data to the single "OpenGL-API-Call"
> thread.
>
> So my advise is if u have to release ur application to a broad range of
> different OpenGL drivers: DON'T USE MULTITHREADING! If u know the
> platform/driver implementation and can actively test ur application on that
> setup, feel free to try it out: It may work for u.

I don't agree with this statement when it comes to data streaming,
even though it might be true for just 'the rendering loop'.

As Wade explained, it is a very good and used technique
to stream data to the GPU via async DMA (PBO, ..).

To achieve that all you need to to know where your sync points are,
ie you need a proper application level synchronization to be able to
signal your rendering loop that data is available.
I have used this technique for PBO DMA xfers and OpenMAX,
where your decoder thread fills texture buffers.
You can sync via OpenGL sync points in the stream (or PBO commands),
or high level in your API - your choice.
If you like to use GL in your data thread which fills buffer,
you may need to use a shared GL context, sure.

In the end you may need to experiment which strategy is best as Wade advised.

!Sven
Reply | Threaded
Open this post in threaded view
|

Re: Multithreading

Haroogan
This post was updated on .
I'm back again :)

Finally I have had my time to finish the idea, which was explained in my first post. The multi-threaded streaming works fine, but there is one problem with mapping buffers as WW said. I don't know why but it seems like my file reader does not fill mapped ByteBuffers (I'm not sure about it yet). I've done everything as WW said... But nothing on screen if I use mapping :(

If I use traditional glBufferData (then one which copies data to graphics card), then it works fine, but I think that's a bad idea to use glBufferData in rendering loop. I'm sure mapping should speed things up. I will try to figure out, right now, why it does not work, but anyway if you have some ideas on typical mistakes I could do while mapping - tell me.

For instance, I've used GL_STATIC_DRAW flag instead of GL_DYNAMIC_DRAW, is that acceptable?
Or maybe, something should changed in rendering code?
Reply | Threaded
Open this post in threaded view
|

Re: Multithreading

Haroogan
This post was updated on .
LoL! that was an awful mistake...

I've just noticed that I've wrote the following snippet:

assert gl2.glUnmapBuffer(target);

Yeah, never do like that :)

Here you are a demo with mapping (ahh, at last). By the way, please post your FPS results and your feedback on overall quality, how smooth it was and etc. Also post your system (CPU and GPU).

This is a height map of 8193x8193 points -  DEMO

My stats are:
FPS ~1500
No freezes, everything is smooth and works just brilliant. Big thanks to WW :)
CPU - core-i7 960
GPU - ATI Radeon HD 5870

And some screenshots:







Reply | Threaded
Open this post in threaded view
|

Re: Multithreading

Michael Bien
works great. V-synced 60fps. all smooth.

old win xp box. i7. GeForce 295 GTX.

-michael
Reply | Threaded
Open this post in threaded view
|

Re: Multithreading

Wade Walker
Administrator
In reply to this post by Haroogan
Hi Haroogan! I'm glad you got it working

It works at 60fps on my Core 2 Quad 2.4 GHz with nvidia 8800GTX (unless I make the window bigger ).
Reply | Threaded
Open this post in threaded view
|

Re: Multithreading

Sven Gothel
Administrator
In reply to this post by Haroogan
On Monday, February 14, 2011 22:08:15 Haroogan [via jogamp] wrote:

>
> LoL! that was an awful mistake...
>
> I've just noticed that i wrote the following snippet:
>
> assert gl2.glUnmapBuffer(target);
>
> Yeah, never do like that :)
>
> Here you are a demo with mapping (ahh, at last). By the way, please post
> your FPS results and your feedback on overall quality, how smooth it was and
> etc. Also post your system (CPU and GPU).

great stuff

>
> This is a height map of 8193x8193 points -  
> http://www.megafileupload.com/en/file/301269/LS-rar.html DEMO

hmm .. so I assume it's w/o source code :)

~Sven

Reply | Threaded
Open this post in threaded view
|

Re: Multithreading

Haroogan
By the way I see some of you have ~60 fps, I'm sure you should have a lot more. On problem I know is text rendering. For instance, when we've tested on my friends machine we also had ~60 fps until we've changed the method of rendering text. Now I will go in some details to make it clear.

The first method:

textRenderer.beginRendering(...);
textRenderer.setColor(...);
textRenderer.draw(...);
textRenderer.endRendering();

In my demo I use this method and it works fine on my machine, but on the machine of my friend it drops FPS hardly to ~60. Does anybody know why?

The second method:

for(int i = 0; i < string.length(); ++i)
{
        glut.glutBitmapCharacter(GLUT.BITMAP_TIMES_ROMAN_24, string.charAt(i));
}

This is old method. But when I've tried this - it surprised me even more. On my machine this method drops FPS hardly and on my friends machine it works fine...

Currently the first method is in the demo. With all that mess I guess I'll have to write FPS output to some secondary window (text area or something). But in any case, do you have any ideas? By the way, my friend also has NVidia GeForce 8XXX.
Reply | Threaded
Open this post in threaded view
|

Re: Multithreading

Sven Gothel
Administrator
On Tuesday, February 15, 2011 11:32:21 Haroogan [via jogamp] wrote:
>
> By the way I see some of you have ~60 fps, I'm sure you should have a lot
> more. On problem I know is text rendering. For instance, when we've tested
> on my friends machine we also had ~60 fps until we've changed the method of
> rendering text. Now I will go in some details to make it clear.
>

dude .. if it's 60fps almost exactly, it's most likely to be V-Sync
where you can't go faster than the monitors refresh rate :)

you could measer the actual 'render time' .. look at the GLAutoDrawable's impl,
they usually count it.

~Sven
Reply | Threaded
Open this post in threaded view
|

Re: Multithreading

Haroogan
Yeah I know that, but I've told you that FPS changes exactly when we change the method of rendering text :)

BTW what is w/o source code? :)