SFML community forums

General => SFML projects => Topic started by: l0calh05t on July 30, 2009, 06:15:34 pm

Title: (Very) small techdemo with sources (threaded OGL rendering)
Post by: l0calh05t on July 30, 2009, 06:15:34 pm
Hey, in case anyone remembers my game "Not quite pong", I had been experimenting with doing the rendering in a separate thread (from input&game logic). Here's a very basic / reduced version of what I did. This is written against the current SFML-2.0 branch (but only 1 or 2 lines have to be changed for SFML-1.5) and boost 1.35. A windows binary (requires VS2008 runtimes) is included.

http://www.carolander.net/joe/threaded_gl.zip

You may notice a few differences in behavior from the standard way of doing it. (Try resizing!)

Please tell me if you notice anything strange. Of course comments and suggestions for improvement are welcome :-)

@Laurent: Should you happen to look in this thread, blocking input would be perfect here, as it would get rid of any and all polling  :wink:
Title: (Very) small techdemo with sources (threaded OGL rendering)
Post by: Laurent on July 30, 2009, 06:38:13 pm
Quote
@Laurent: Should you happen to look in this thread, blocking input would be perfect here, as it would get rid of any and all polling

Yeah, I think I'll implement it soon ;)
Title: (Very) small techdemo with sources (threaded OGL rendering)
Post by: l0calh05t on July 30, 2009, 06:53:37 pm
:mrgreen:
Title: (Very) small techdemo with sources (threaded OGL rendering)
Post by: Jaenis on July 31, 2009, 04:45:45 am
Interesting app...
Have you noticed that you can drag that SMFL window around and it's contents are still being updated while dragging? (On Windows OS)

Normally Windows blocks this that your screen would freeze while you are dragging the window.
Hmm.. You seem to have actual drawing on another thread, so it gets around this. Nice trick :)
Title: (Very) small techdemo with sources (threaded OGL rendering)
Post by: l0calh05t on July 31, 2009, 08:23:25 am
Quote from: "Jaenis"
Interesting app...
Have you noticed that you can drag that SMFL window around and it's contents are still being updated while dragging? (On Windows OS)

Normally Windows blocks this that your screen would freeze while you are dragging the window.
Hmm.. You seem to have actual drawing on another thread, so it gets around this. Nice trick :)


Yup, that's exactly what I meant by "You may notice a few differences in behavior" :-)

Currently I'm trying to add a Fullscreen toggle feature but I'm getting some evil, evil crash... (my window pointer is 0 after the call to create... very, very bad and I can't explain it yet)
Title: (Very) small techdemo with sources (threaded OGL rendering)
Post by: l0calh05t on July 31, 2009, 09:04:58 am
Just in case I made any obvious errors...
(http://www.carolander.net/joe/screencutout.png)
Title: (Very) small techdemo with sources (threaded OGL rendering)
Post by: Jaenis on July 31, 2009, 04:02:41 pm
I got inspired of your system and made similar test.

What you are doing when you call renderTask->pause(true) ?
I do this instead:
Code: [Select]

void Renderer::DetachWindow(void)
{
// Stop the thread
Stop();              // Send async stop command
Thread.join();       // Wait thread to finish
Clear();             // Clear function queue

// We do not have window anymore
Window=NULL;
}


And where you unpause your thread I do following:
Code: [Select]

void Renderer::AttachWindow(sf::Window &NewWindow)
{
// Store pointer and set caller window inactive
Window=&NewWindow;
Window->SetActive(false);

// Launch thread
Thread=boost::thread( boost::bind(&Renderer::ThreadMain,this) );
}


So when I want to change videomode I just wait the renderer thread to exit, then I can be sure that it does not require access to SFML window. And afterwards I restart the renderer thread.
Might be overkill, but I don't care if fullscreen<->windowed change takes few more milliseconds ;)
Title: (Very) small techdemo with sources (threaded OGL rendering)
Post by: l0calh05t on July 31, 2009, 05:16:43 pm
Maybe I should try that solution... I actually pause the thread by using a condition variable and before blocking, the render thread calls an "onPause" function which deactivates the window. (Pausing and unpausing by itself works... but recreating the window crashes with all kinds of strangeness...

Modified GameTask:
Code: [Select]

void GameTask::run()
{
running = true;
paused = false;

init();

while(running)
{
{
boost::unique_lock<boost::mutex> lock(pauseMutex);
bool first = true;
while(paused)
{
if(first)
{
first = false;
onPause(true);
}
pauseCond.notify_all();
pauseCond.wait(lock);
}

if(!first)
onPause(false);
}
loopBody();
executeCalls();
}

fini();
}

void GameTask::pause(bool pause)
{
if(pause && !paused)
{
boost::unique_lock<boost::mutex> lock(pauseMutex);
paused = true;
pauseCond.wait(lock); // wait until the task is actually paused
}
else if(!pause && paused)
{
{
boost::lock_guard<boost::mutex> lock(pauseMutex);
paused = false;
}
pauseCond.notify_all();
}
}


onPause function for Renderer:
Code: [Select]

void onPause(bool paused)
{
window->SetActive(!paused);

if(!paused)
{
// Set color and depth clear value
glClearDepth(1.f);
glClearColor(0.f, 0.f, 0.f, 0.f);

// Enable Z-buffer read and write
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);

// Setup a perspective projection
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(90.f, (float)window->GetWidth()/(float)window->GetHeight(), 1.f, 500.f);

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
}
Title: (Very) small techdemo with sources (threaded OGL rendering)
Post by: Astrof on July 31, 2009, 06:19:42 pm
In the code I see a
Code: [Select]
if(fullscreen= !fullscreen)
shouldn't it be
Code: [Select]
if(fullscreen==!fullscreen)
or
Code: [Select]
if(fullscreen!= fullscreen)

or wait, shouldn't it be set to something other than itself? Sorry i didnt do a thorough readthrough, this just popped up at me.
Title: (Very) small techdemo with sources (threaded OGL rendering)
Post by: l0calh05t on July 31, 2009, 06:31:22 pm
Quote from: "Astrof"
In the code I see a
Code: [Select]
if(fullscreen= !fullscreen)
shouldn't it be
Code: [Select]
if(fullscreen==!fullscreen)
or
Code: [Select]
if(fullscreen!= fullscreen)

or wait, shouldn't it be set to something other than itself? Sorry i didnt do a thorough readthrough, this just popped up at me.


no, it's correct

if(fullscreen = !fullscreen) inverts the value of fullscreen and checks if the inverted value is true (the other variants leave fullscreen unchanged and always return false ;-) )
Title: (Very) small techdemo with sources (threaded OGL rendering)
Post by: Daazku on July 31, 2009, 06:49:20 pm
Nice work!
Title: (Very) small techdemo with sources (threaded OGL rendering)
Post by: l0calh05t on July 31, 2009, 06:59:26 pm
Just tried stopping the render thread and starting a new one after calling window->Create ... leads to the same error. But if I destroy the window and create a new one... it works. Very strange. Does anyone have an idea what might be happening?

EDIT:

so much for "it works"... after toggling window/fullscreen a few times, my system decided to hang indefinitely...

actually something similar has been happening from time to time when just closing the window: the window stays there for 3-4 seconds and in the last 1-2 of those even the windows mouse cursor stops moving. but then the window gets closed and everything continues normally.

now the really strange thing is... it hangs after all my code has been executed, except for the destructors. and the only things that are destroyed are a mutex, and an (empty) std::vector.

EDIT 2:
Just tested all 3 variants on my Win7 machine (with much newer nvidia drivers):

V 1 (pause then re-create):
WinXP: Fails
Win7: Fails
In both cases the "window" pointer changes to an invalid value, without an actual assignment...

V 2 (stop then re-create):
WinXP: Fails
Win7: Works (so far)

V 3 (stop, destroy, create):
WinXP: Works (but has hung up windows once)
Win7: Works (so far)

Very strange stuff...
Title: (Very) small techdemo with sources (threaded OGL rendering)
Post by: klusark on July 31, 2009, 09:04:45 pm
One thing that I do in my project is in my update thread
Code: [Select]

if (lastWidth != App.GetWidth() || lastHeight != App.GetHeight()){
    lastWidth = App.GetWidth();
    lastHeight = App.GetHeight();

    float currentRatio = (float)lastWidth/(float)lastHeight;
    float correctY = 320/currentRatio;
    view.SetFromRect((sf::FloatRect(0, 0, 320, correctY)));
}

Using this I am able to get real time resizing. Something similar (and better written) would go well in your project.
I dont use the resize event in the event loop because it blocks untill the resizing is done.  

@Laurent would it be possible to use some code similar to this in sfml for better resize event prossesing?
Title: (Very) small techdemo with sources (threaded OGL rendering)
Post by: l0calh05t on July 31, 2009, 09:09:42 pm
Quote from: "klusark"

@Laurent would it be possible to use some code similar to this in sfml for better resize event prossesing?


Let's try to find a reliable solution to the fullscreen toggle error first...

PS:
Also, there isn't much to improve in that snippet, except maybe putting the actual resizing code in a separate function
Title: (Very) small techdemo with sources (threaded OGL rendering)
Post by: Laurent on July 31, 2009, 09:20:56 pm
Quote
@Laurent would it be possible to use some code similar to this in sfml for better resize event prossesing?

I don't see what SFML could do with this code.
Title: (Very) small techdemo with sources (threaded OGL rendering)
Post by: l0calh05t on July 31, 2009, 09:28:40 pm
Quote from: "Laurent"
Quote
@Laurent would it be possible to use some code similar to this in sfml for better resize event prossesing?

I don't see what SFML could do with this code.


Nothing without switching to a separate render thread, which would probably make it quite beginner-unfriendly... (although maybe if the messages are polled automatically and forwarded... hrmm...)
Title: (Very) small techdemo with sources (threaded OGL rendering)
Post by: klusark on July 31, 2009, 09:59:32 pm
As long as the api stays the same, a hidden render thread could be added and beginner users would not notice. I am not sure if this is possible though. When I get a chance I will try to implement this.
Title: (Very) small techdemo with sources (threaded OGL rendering)
Post by: Laurent on July 31, 2009, 10:03:15 pm
SFML is too low-level, it doesn't control anything about rendering. Objects are rendered when the user calls window.Draw. I couldn't even implement a rendering queue to be executed later / in another thread.

And besides, it sounds a little bit overkill...
Title: (Very) small techdemo with sources (threaded OGL rendering)
Post by: l0calh05t on July 31, 2009, 10:09:31 pm
Quote from: "Laurent"
SFML is too low-level, it doesn't control anything about rendering. Objects are rendered when the user calls window.Draw. I couldn't even implement a rendering queue to be executed later / in another thread.

And besides, it sounds a little bit overkill...


And inefficient. Better leave it as it is.
Suggestions about that crash issue are welcome though  :P