SFML community forums
Help => Graphics => Topic started by: Tank on February 11, 2010, 03:01:27 pm
-
Hi guys,
I've recently discovered that the font texture gets somehow messed up. Look at this screenshot:
(http://pitload.org/show/2001/font.png)
The lines are created after each other. When I don't add the last two lines (abcdef...), only the "v" in "Server disconnected" is missing.
5th line is lower-case, 6th line is upper-case. This happened to me at first with the default font, so I switched it -- just to say that it's not font-related. ;)
-
Hi
Any message on the standard error output? Which revision are you using?
-
Nope, no errors on stdout/err. I'm using the latest revision (updated just now).
-
Can you show a minimal example that reproduces this problem?
What graphics card do you have?
-
Okay this is weird. I've done the same steps in a minimal example and everything works. I'll recheck my application and post when I've got news on that.
-
Okay, got it. Was not so easy to get this bug working, again. ;)
The problem only shows up in a multi-threaded application. And I had to do some "tricks" to make it appear. The following code is a bit longer, but I couldn't come up with something shorter, sorry.
#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
#include <SFML/System.hpp>
#include <list>
void ThreadFunc( void* arg );
typedef std::list<sf::Text> TextList;
TextList List;
bool Running( true );
sf::Mutex Lock;
int main() {
sf::RenderWindow wnd( sf::VideoMode( 800, 600, 32 ), "Font" );
sf::Thread thread( ThreadFunc, 0 );
thread.Launch();
while( Running ) {
wnd.Clear();
// Critical section begins.
Lock.Lock();
TextList::iterator iter( List.begin() );
TextList::iterator iterend( List.end() );
for( ; iter != iterend; ++iter ) {
wnd.Draw( *iter );
}
Lock.Unlock();
// Ends.
wnd.Display();
}
sf::Sleep( 2.f );
return 0;
}
void UpdatePositions() {
TextList::iterator iter( List.begin() );
TextList::iterator iterend( List.end() );
float yoffset( 0.f );
for( ; iter != iterend; ++iter ) {
iter->SetPosition( 0.f, yoffset );
yoffset += iter->GetRect().GetSize().y + 3.f;
}
}
void ThreadFunc( void* arg ) {
sf::Context ctx;
Lock.Lock();
List.push_back( sf::Text( L"Trying to connect..." ) );
UpdatePositions();
Lock.Unlock();
sf::Sleep( .2f );
Lock.Lock();
List.push_back( sf::Text( L"Connection established. Sending username and password..." ) );
UpdatePositions();
Lock.Unlock();
sf::Sleep( .2f );
Lock.Lock();
List.push_back( sf::Text( L"Login failed. Wrong username and/or password." ) );
UpdatePositions();
Lock.Unlock();
sf::Sleep( .2f );
Lock.Lock();
List.push_back( sf::Text( L"Server disconnected." ) );
UpdatePositions();
Lock.Unlock();
sf::Sleep( .2f );
Running = false;
}
When you move the "Lock.Unlock()" lines in "ThreadFunc()" behind the "sf::Sleep()" calls, everything's working like a charm. I don't have a clue what's happening here.
-
This is fun.
Look at this:
#include <SFML/Graphics.hpp>
#include <list>
void ThreadFunc( void* );
typedef std::list<sf::Text> TextList;
TextList List;
bool Running( true );
sf::Mutex Lock;
int main() {
sf::RenderWindow wnd( sf::VideoMode( 800, 600, 32 ), "Font" );
sf::Thread thread( ThreadFunc, 0 );
thread.Launch();
while( Running ) {
wnd.Clear();
// Critical section begins.
Lock.Lock();
TextList::iterator iter( List.begin() );
TextList::iterator iterend( List.end() );
for( ; iter != iterend; ++iter ) {
wnd.Draw( *iter );
}
Lock.Unlock();
// Ends.
wnd.Display();
}
sf::Sleep( 2.f );
return 0;
}
void AddText(const std::string& Text)
{
Lock.Lock();
List.push_back( sf::Text( Text ) );
TextList::iterator iter( List.begin() );
TextList::iterator iterend( List.end() );
float yoffset( 0.f );
for( ; iter != iterend; ++iter ) {
iter->SetPosition( 0.f, yoffset );
yoffset += iter->GetRect().GetSize().y + 3.f;
}
Lock.Unlock();
sf::Sleep( 0.5f );
}
void ThreadFunc( void* ) {
sf::Context ctx;
AddText( "aej" );
AddText( "aba" );
AddText( "abca" );
AddText( "abcda" );
AddText( "abcdea" );
AddText( "abcdefa" );
AddText( "abcdefga" );
AddText( "abcdefgha" );
AddText( "abcdefghia" );
AddText( "abcdefghija" );
AddText( "abcdefghijka" );
AddText( "abcdefghijkla" );
AddText( "abcdefghijklma" );
AddText( "abcdefghijklmna" );
AddText( "abcdefghijklmnoa" );
Running = false;
}
Only the glyphs contained in the first text are rendered in the other lines, all the other glyphs appear magically at the end of the program.
Note that swapping Lock and Sleep calls didn't change anything for me.
More fun: if I write AddText like this
void AddText(const std::string& Str)
{
static float yoffset( 0.f );
Lock.Lock();
sf::Text Text(Str);
Text.SetY(yoffset);
yoffset += 30;
List.push_back( Text );
sf::Sleep( 0.5f );
Lock.Unlock();
}
Everything's fine.
I have to go buy some food for my ferret, but I'll do more funny tests after that :D
-
Must have been much food. ;)
But yeah, it's truly weird. So getting rid of the iterators fixed it, mh. That's just strange in my eyes. Do you have any idea what may cause this? New font rendering? OpenGL? Some multi-threading issue?
Edit: Ha, you're right. When I push back texts with all glyphs I use later, everything's fine (like preloading them ;)).
-
Must have been much food
I had an accident on my way to the pet store :P
But yeah, it's truly weird. So getting rid of the iterators fixed it, mh. That's just strange in my eyes.
I didn't have time to check yet, but I think it is related to the GetRect() call rather than iterators.
Do you have any idea what may cause this? New font rendering? OpenGL? Some multi-threading issue?
I think it is a combination of multi-threading, internal sf::Image optimizations (lazy updates) and sf::Font texture generation on-the-fly.
-
After some more tests, I found that it is indeed GetRect() that messes things up - more specifically, it is the line which generates a new glyph.
My conclusion is that an OpenGL texture cannot be active on two different contexts at the same time, even if it is not used concurrently. I kind of confirmed it by activating another texture after drawing the texts in the main thread: it worked with a little lag (probably due to the locks and sleep calls).
It also explains why the first text is always rendered properly: the texture is not active yet in the main thread.
I couldn't find more information about this, and don't know if it can be solved :(
-
Okay, too bad OpenGL bitches so much around with multi-threading. :roll:
So the only solution is to limit the creation of textures to the main thread. Thanks for the info.
And hopefully nothing happened at your accident.
-
So the only solution is to limit the creation of textures to the main thread
No, this is a different problem. Creating a texture in a thread is of course possible, what you can't do is activating (glBindTexture) the same texture in two different threads.
The problem in SFML is that a texture remains active until another one is activated, so for example in your code the texture is always active in both threads, because this is the only one that is used.
-
Okay I see. So a thread would have to call glBindTexture() again to ensure a proper display? If so, can this be implemented or would it not fit into the library design?
I'm currently creating and activating the texts/fonts in the main thread as a workaround. But if there'd be another and maybe simplier method, I'd prefere that, of course.
-
So a thread would have to call glBindTexture() again to ensure a proper display? If so, can this be implemented or would it not fit into the library design?
It wouldn't fit at all :?
I think that you should just preload all the glyphs that you need before starting your thread, that should be enough.
-
Good point, thanks.