threading and rendering

Problems building or running the engine, queries about how to use features etc.
Post Reply
kuma
Kobold
Posts: 25
Joined: Sat May 17, 2014 6:35 am

threading and rendering

Post by kuma »

I've seen this topic come up a few times, but I have not been able to get it working!
In my small game engine I use manual objects to build my terrain from a heightmap.
It's working, but I encounter the common problem of the program freezing as my paging system loads in new data.

To overcome this, I am trying to implement boost threads.
Below is sample code from my program, simplified for readability.
  • updateTerrain : Called from the main function about every second.
    createTerrainUpdate : Builds terrain information and stores it in OgreTerra class variables.
    renderTerrainUpdate : Updates the manual object using the above class variables.

Code: Select all

void [color=#4080FF]OgreTerra::updateTerrain[/color]() {
        boost::thread createTerrainUpdateThread(boost::bind(&OgreTerra::createTerrainUpdate, this));
        createTerrainUpdateThread.join();
        renderTerrainUpdate();
}

Code: Select all

void [color=#4080FF]OgreTerra::renderTerrainUpdate[/color]() {
    Ogre::ManualObject* manual = OgreFramework::getSingletonPtr()->m_pSceneMgr->getManualObject("big");
    manual->beginUpdate(0);
    for ( int k=0; k < segments[i].vertex_indices.size();) {          
         // Set the vertex positions. 
         manual->position(vertices[segments[i].vertex_indices[k]],vertices[segments[i].vertex_indices[k+1]],vertices[segments[i].vertex_indices[k+2]]);
         // Set the normals 
         manual->normal(normals[segments[i].vertex_normals[n]]);
         // Set the UVs
         manual->textureCoord(a, b);
    }
    for ( int j=0; j < segments[i].triangle_indices.size();) {
         manual->triangle(segments[i].triangle_indices[j],segments[i].triangle_indices[j+1],segments[i].triangle_indices[j+2]);
         j=j+3;
    }
    manual->end();
The above works, the boost thread successfully loads the data, which is then picked up and rendered.
This half solves my issue, however I still get subsecond stalls as renderTerrainUpdate is processed..

Now if rewrite updateTerrain to also fire renderTerrainUpdate as a boost thread as below..

Code: Select all

void [color=#4080FF]OgreTerra::updateTerrain[/color]() {
        boost::thread createTerrainUpdateThread(boost::bind(&OgreTerra::createTerrainUpdate, this));
        createTerrainUpdateThread.join();
        boost::thread renderTerrainUpdateThread(boost::bind(&OgreTerra::renderTerrainUpdate, this));
        renderTerrainUpdateThread.join();
}
When it get's hit it segfaults as follows..
start createTerrainUpdate
[New Thread 0x7fffd267e700 (LWP 4269)]
createTerrainUpdate - 64 , 4096 , 64
update started
[Thread 0x7fffd267e700 (LWP 4269) exited]
[New Thread 0x7fffd267e700 (LWP 4275)]

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7fffd267e700 (LWP 4275)]
0x00007fffeefb9069 in glGenBuffersARB () from /usr/lib64/libGL.so.1
(gdb) bt
#0 0x00007fffeefb9069 in glGenBuffersARB () from /usr/lib64/libGL.so.1
#1 0x00007fffef32d3b3 in Ogre::GLHardwareVertexBuffer::GLHardwareVertexBuffer(Ogre::HardwareBufferManagerBase*, unsigned long, unsigned long, Ogre::HardwareBuffer::Usage, bool) () from /usr/local/lib/OGRE/RenderSystem_GL.so
#2 0x00007fffef32647f in Ogre::GLHardwareBufferManagerBase::createVertexBuffer(unsigned long, unsigned long, Ogre::HardwareBuffer::Usage, bool) () from /usr/local/lib/OGRE/RenderSystem_GL.so
#3 0x00007fffef33bec5 in ?? () from /usr/local/lib/OGRE/RenderSystem_GL.so
#4 0x00007ffff6f607c4 in Ogre::ManualObject::end() () from /usr/lib64/libOgreMain.so.1.8.1
#5 0x0000000000442a23 in OgreTerra::renderTerrainUpdate (this=0x67c060 <myterrain>) at ogre/ogre_terrain.cc:499
#6 0x00000000004505f5 in boost::_mfi::mf0<void, OgreTerra>::operator() (this=0x165c870, p=0x67c060 <myterrain>)
at /usr/include/boost/bind/mem_fn_template.hpp:49
#7 0x0000000000450558 in boost::_bi::list1<boost::_bi::value<OgreTerra*> >::operator()<boost::_mfi::mf0<void, OgreTerra>, boost::_bi::list0> (this=0x165c880, f=..., a=...) at /usr/include/boost/bind/bind.hpp:253
#8 0x00000000004504cb in boost::_bi::bind_t<void, boost::_mfi::mf0<void, OgreTerra>, boost::_bi::list1<boost::_bi::value<OgreTerra*> > >::operator() (this=0x165c870) at /usr/include/boost/bind/bind_template.hpp:20
#9 0x0000000000450412 in boost::detail::thread_data<boost::_bi::bind_t<void, boost::_mfi::mf0<void, OgreTerra>, boost::_bi::list1<boost::_bi::value<OgreTerra*> > > >::run (this=0x165c6d0) at /usr/include/boost/thread/detail/thread.hpp:78
#10 0x00007ffff52b7af3 in ?? () from /usr/lib64/libboost_thread.so.1.52.0
#11 0x00007ffff6aa3c74 in start_thread () from /lib64/libpthread.so.0
#12 0x00007ffff4815b0d in clone () from /lib64/libc.so.6


ogre/ogre_terrain.cc:499 is manual->end(); in renderTerrainUpdate() .

I know ogre is not threadsafe like this, but what would be the recommended way to overcome this?
I am looking at the workqueue http://www.ogre3d.org/tikiwiki/tiki-ind ... +WorkQueue and I'll attempt that, but any feedback or comments on this would be appreciated.

edit: it seems this question was asked before http://www.ogre3d.org/forums/viewtopic.php?f=1&t=64291 , and points the issue being related to manual object!! Does this mean manual objects simple can not be used with threads?

Another topic http://www.ogre3d.org/forums/viewtopic.php?f=2&t=79387 shows a possible implementation in workqueue, does this allow for safe updating of manual objects?
User avatar
c6burns
Beholder
Posts: 1512
Joined: Fri Feb 22, 2013 4:44 am
Location: Deep behind enemy lines
x 138

Re: threading and rendering

Post by c6burns »

Regardless of the threading mechanism, you can't touch the GPU except in the render thread. So for example, you could prepare all of the vertex/index buffers of your terrain in memory or load any images into memory, but you can't do any actual render operations (eg. creating actual hardware buffers, or loading textures into video memory). You have to simply prepare data for the render thread to use.
kuma
Kobold
Posts: 25
Joined: Sat May 17, 2014 6:35 am

Re: threading and rendering

Post by kuma »

I see, in that situation for a manual object does that mean, that your render will always stall for as long as it takes to run manual begin, position, normal, triangle, end etc.
If so it would make large manual objects unusable ?
User avatar
c6burns
Beholder
Posts: 1512
Joined: Fri Feb 22, 2013 4:44 am
Location: Deep behind enemy lines
x 138

Re: threading and rendering

Post by c6burns »

I don't use manual objects so I can't speak to how they work in terms of when/where they access the GPU, but I can tell you that rendering definitely 100% has to wait for new geometry/textures to be transferred to the GPU. You are free to prepare vertex/index buffers in RAM, or load images into RAM in a background thread ... but when you need to move those over to the GPU's memory it must be done by the render thread. So the more you try to push to the GPU in a single frame, the more noticeable the stall in rendering is going to be. Ogre allows you to take control of filling hardware buffers yourself, and you could do so incrementally across multiple frames to avoid stalls with large sets of geometry, but not with manual objects.
kuma
Kobold
Posts: 25
Joined: Sat May 17, 2014 6:35 am

Re: threading and rendering

Post by kuma »

Thanks c6burns. Indeed there seems to be no way to do this with manual objects without first converting to mesh using the hardware buffer. So I may as well just use the hardware buffer to begin with! I'll refactor my code.

Thanks again.
Post Reply