Background loading within another thread on Linux using POSIX

Post those lines of code you feel like sharing or find what you require for your project here; or simply use them as tutorials.
Post Reply
radubolovan
Posts: 60
Joined: Tue Nov 13, 2007 7:03 pm
Location: Bucharest - Romania
Contact:

Background loading within another thread on Linux using POSIX

Post by radubolovan »

After many crashes and no correct functionality, I did it! :)
I had to patch Irrlicht engine with two functions though (in CIrrDeviceLinux class):
in private area:

Code: Select all

        GLXWindow glxWin2;
        GLXContext Context2;
then in public area:

Code: Select all

        GLXContext const& createNewContext();;
        void releaseContext( GLXContext const& a_context );
in constructor:

Code: Select all

        glxWin2 = 0;
        Context2 = 0;
Then the functions:

Code: Select all

GLXContext const& CIrrDeviceLinux::createNewContext()
{
	if( Context2 != 0 )
	{
		GLXContext cntx;
		return cntx;
	}

	const int MAX_SAMPLES = 16;
	int visualAttrBuffer[] =
	{
		GLX_RENDER_TYPE, GLX_RGBA_BIT,
		GLX_RED_SIZE, 4,
		GLX_GREEN_SIZE, 4,
		GLX_BLUE_SIZE, 4,
		GLX_ALPHA_SIZE, 4,
		GLX_DEPTH_SIZE, 16,
		GLX_DOUBLEBUFFER, GL_TRUE,
		GLX_STENCIL_SIZE, 1,
		GLX_SAMPLE_BUFFERS_ARB, GL_TRUE,
		GLX_SAMPLES_ARB, MAX_SAMPLES,
		None
	};

	int nitems = 0;
	GLXFBConfig* configList = glXGetFBConfigs( display, screennr, &nitems );
	Context2 = glXCreateNewContext( display, *configList, GLX_RGBA_TYPE, Context, True );//create a new context with common resources with first one
	glxWin2 = glXCreateWindow( display, *configList, RootWindow( display, visual->screen ), NULL );//create a window
	glXMakeContextCurrent( display, glxWin2, glxWin2, Context2 );//making second context current for this thread in specific window

	return Context2;
}

void CIrrDeviceLinux::releaseContext( GLXContext const& a_context )
{
	if( Context2 != a_context )
		return;

	glXDestroyContext( display, Context2 );
	glXDestroyWindow( display, glxWin2 );
}
Then in my app I have a:

Code: Select all

static bool m_bScreenshotEnable;
and the draw function:

Code: Select all

m_pIrrDriver->beginScene( true, true, SColor( 255, 0, 0, 0 ) );
if( DSIrrApp::m_bScreenshotEnable )
{
    drawLoadingScreen();//just a function for drawing something
}
else
{
    drawAll();//a function whitch draws all stuff
}
m_pIrrDriver->endScene();
And the threads stuff - a function:

Code: Select all

void* startLoadingThread( void *ptr )
{
	tThreadData* data = (tThreadData*)ptr;

	GLXContext context = ((CIrrDeviceLinux*)g_pIrrInterface->m_pIrrDevice)->createNewContext();

	DSIrrApp::m_bLoadingScreen = true;

	loadScene();

	DSIrrApp::m_bLoadingScreen = false;

	((CIrrDeviceLinux*)g_pIrrInterface->m_pIrrDevice)->releaseContext( context );

	dsfree( data->fileName );
	dsdelete( data );

	return NULL;
}
tThreadData is a structure:

Code: Select all

typedef struct _tThreadData
{
	_tThreadData()
	{
		pIrrDriver = NULL;
		fileName = NULL;
	}
	_tThreadData( IVideoDriver* pID, char* fN )
	{
		pIrrDriver = pID;
		fileName = fN;
	}

	IVideoDriver* pIrrDriver;
	char* fileName;
}tThreadData;
And a testing part:

Code: Select all

//somwhere in the code
tThreadData* data = dsnew tThreadData( g_pIrrInterface->m_pIrrDriver, ascii );
					int threadRet = pthread_create( &g_pLoadingThread, NULL, startLoadingThread, (void*)data );
g_pLoadingThread is just a:

Code: Select all

pthread_t g_pLoadingThread;
and of course:

Code: Select all

#include <pthread.h>
#include <unistd.h>
Enjoy! ;-)
Last edited by radubolovan on Tue Oct 08, 2024 11:04 am, edited 1 time in total.
lester
Posts: 86
Joined: Mon Jan 29, 2007 3:33 pm

Post by lester »

Man, you certainly deserve a monument :)
BlindSide
Admin
Posts: 2821
Joined: Thu Dec 08, 2005 9:09 am
Location: NZ!

Post by BlindSide »

Thats pretty awesome.
ShadowMapping for Irrlicht!: Get it here
Need help? Come on the IRC!: #irrlicht on irc://irc.freenode.net
rogerborg
Admin
Posts: 3590
Joined: Mon Oct 09, 2006 9:36 am
Location: Scotland - gonnae no slag aff mah Engleesh
Contact:

Re: loading within another thread on Linux using POSIX

Post by rogerborg »

Code: Select all

GLXContext const& CIrrDeviceLinux::createNewContext()
{
	if( Context2 != 0 )
	{
		GLXContext cntx;
		return cntx;
	}
You're returning a reference to a stack object. If your intention is to return an invalid reference, then you'd be better off returning a 0 pointer rather than a garbage reference.

Code: Select all

void CIrrDeviceLinux::releaseContext( GLXContext const& a_context )
{
	if( Context2 != a_context )
		return;
You're comparing Context2 against garbage, which is risky. A 0 pointer would be more explicit. And passing a const & is disingenuous, as you are destroying the object that it references, just via another reference.

Irrlicht is explicitly not thread safe, so I hope that your analysis involved more than just running this and seeing that it didn't crash under a success path.
Please upload candidate patches to the tracker.
Need help now? IRC to #irrlicht on irc.freenode.net
How To Ask Questions The Smart Way
radubolovan
Posts: 60
Joined: Tue Nov 13, 2007 7:03 pm
Location: Bucharest - Romania
Contact:

Post by radubolovan »

@rogerborg
The ideea is to avoid creating a new context over an existing one and not to distroy an context which doesn't exist.
1) the checks should be done outside irrlicht eg.:

Code: Select all

GLXContext myContext = ((CIrrDeviceLinux*)driver->createNewContext();
if( myContext != 0 )
{
    //make something with context
}
else
{
    printf( "creating context error\n" );
    //TODO: free data initialized
    return;
}

//some code here and loading stuff

//and just:
((CIrrDeviceLinux*)driver->releaseContext( myContext );//try not to use myContext variable after this line of code ;-)
b)because both functions work with const&, this shouldn't be risky.
The ideea of & is not to create copies of memmory and verify the exact one created!!!
The ideea of const is to avoid writting in its memory.
2) Yes, maybe this is better:

Code: Select all

GLXContext const* CIrrDeviceLinux::createNewContext()
{
    /* this is ok because in constructor is: Context2 = 0;
       and after creation it is pozitive*/
   if( Context2 != 0 )
   {
      return NULL;
   }
   //creation of context here
   return &Context2;
}
void CIrrDeviceLinux::releaseContext( GLXContext* a_context )
{
   if( Context2 != *a_context )
      return;
   //destroy the context here
   a_context = NULL;
}
But anyway both versions work well, once again, the user must do the checks, not me.
And you have right about this:

Code: Select all

if( Context2 != 0 )
   {
      GLXContext cntx;
      return cntx;
   }
This is better:

Code: Select all

if( Context2 != 0 )
   {
      return (GLXContext)0;
   } 
Enjoy
radubolovan
Posts: 60
Joined: Tue Nov 13, 2007 7:03 pm
Location: Bucharest - Romania
Contact:

Post by radubolovan »

Is there anyone who can port the code for other S.O. (eg. Windows)?
here: http://en.wikipedia.org/wiki/POSIX it sais that POSIX works on different platforms, but I don't know how to create a window and a OpenGL context in Windows :(
lester
Posts: 86
Joined: Mon Jan 29, 2007 3:33 pm

Post by lester »

radubolovan

Forget about it. POSIX on Win named Xenix is dead officially.
vvv
Posts: 11
Joined: Mon Feb 25, 2008 4:56 pm

Post by vvv »

lester wrote:radubolovan

Forget about it. POSIX on Win named Xenix is dead officially.
You are completely wrong.

1. According to POSIX THREADS in windows: http://sourceware.org/pthreads-win32/ - so code example is useful for windows too (I use pthreads in my project)

2. According to Xenix you are wrong too. Check this out:
http://technet.microsoft.com/en-us/inte ... 80242.aspx

It's native POSIX layer for Win32 from Microsoft.
muenalan
Posts: 7
Joined: Tue Feb 26, 2008 9:11 pm

irrlicht can be multithreaded with this patch ?

Post by muenalan »

I just came across fences when a have a separate irrlicht render thread. The window was not painting any more if the while(-run()) loop is in another thread (boost thread).

Does this mean irrlicht was not capable of these things, *BUT* this modification shall fix it ?
radubolovan
Posts: 60
Joined: Tue Nov 13, 2007 7:03 pm
Location: Bucharest - Romania
Contact:

Post by radubolovan »

I've found if the window doesn't recieve an event (from mouse or keyboard), the next line was not executed:

Code: Select all

Context2 = glXCreateNewContext( display, *configList, GLX_RGBA_TYPE, Context, True );
so the next code should resolve this problem;

Code: Select all

GLXContext const& CIrrDeviceLinux::createNewContext()
{
	if( Context2 != 0 )
	{
		GLXContext cntx;
		return cntx;
	}

	const int MAX_SAMPLES = 16;
	int visualAttrBuffer[] =
	{
		GLX_RGBA, GL_TRUE,
		GLX_RED_SIZE, 4,
		GLX_GREEN_SIZE, 4,
		GLX_BLUE_SIZE, 4,
		GLX_ALPHA_SIZE, 4,
		GLX_DEPTH_SIZE, 16,
		GLX_DOUBLEBUFFER, GL_TRUE,
		GLX_STENCIL_SIZE, 1,
		None
	};

	int nitems = 0;
	GLXFBConfig* configList = glXGetFBConfigs( display, screennr, &nitems );

	XEvent event;
	XPutBackEvent( display, &event );

	Context2 = glXCreateNewContext( display, *configList, GLX_RGBA_TYPE, Context, True );
	glxWin2 = glXCreateWindow( display, *configList, RootWindow( display, visual->screen ), NULL );
	glXMakeContextCurrent( display, glxWin2, glxWin2, Context2 );

	return Context2;
}
radubolovan
Posts: 60
Joined: Tue Nov 13, 2007 7:03 pm
Location: Bucharest - Romania
Contact:

Post by radubolovan »

This is still happening :(
The problem is that the window doesn't recieve an event ... I will see if can be resolved... maybe I should define the event.
Keep in touch.
radubolovan
Posts: 60
Joined: Tue Nov 13, 2007 7:03 pm
Location: Bucharest - Romania
Contact:

Post by radubolovan »

I've founnd that this problem is occurred when the wndow lose focus ;) so ...
in .h:

Code: Select all

bool m_bTryToCreateNewContext;
in .cpp:
in constructor:

Code: Select all

m_bTryToCreateNewContext = false;
in createNewContext() function:

Code: Select all

if( Context2 != 0 )
	{
		GLXContext cntx;
		return cntx;
	}

	m_bTryToCreateNewContext = true;

	const int MAX_SAMPLES = 16;
	int visualAttrBuffer[] =
	{
		GLX_RGBA, GL_TRUE,
		GLX_RED_SIZE, 4,
		GLX_GREEN_SIZE, 4,
		GLX_BLUE_SIZE, 4,
		GLX_ALPHA_SIZE, 4,
		GLX_DEPTH_SIZE, 16,
		GLX_DOUBLEBUFFER, GL_TRUE,
		GLX_STENCIL_SIZE, 1,
		None
	};

	int nitems = 0;
	GLXFBConfig* configList = glXGetFBConfigs( display, screennr, &nitems );
	Context2 = glXCreateNewContext( display, *configList, GLX_RGBA_TYPE, Context, True );
	glxWin2 = glXCreateWindow( display, *configList, RootWindow( display, visual->screen ), NULL );
	glXMakeContextCurrent( display, glxWin2, glxWin2, Context2 );

	return Context2;
in run() function at the beginning:

Code: Select all

os::Timer::tick();

	if( m_bTryToCreateNewContext )
	{
		WindowActive = true;
	}
and finaly in the releaseContext() function

Code: Select all

if( Context2 != a_context )
		return;

	glXDestroyContext( display, Context2 );
	glXDestroyWindow( display, glxWin2 );
	m_bTryToCreateNewContext = false;
Now it's all ok! :D
Post Reply