Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: I'm missing something with sf::Context and sf::Image  (Read 3700 times)

0 Members and 1 Guest are viewing this topic.

Groogy

  • Hero Member
  • *****
  • Posts: 1469
    • MSN Messenger - groogy@groogy.se
    • View Profile
    • http://www.groogy.se
    • Email
I'm missing something with sf::Context and sf::Image
« on: June 03, 2011, 06:07:37 pm »
Aight well I am missing something. As you know or may not know I am doing my stuff multi-threaded so I have to create a context for the thread if I want to load images. The weird thing is, it worked without a context in Debug but not in Release? The problem appeared as that the sprite is rendered with it's correct size but it's texture is not applied. With debug information in release I do get that the sprite's pixel pointer actually got the correct values in it so it seems like the image actually was loaded.

Anyway I thought nothing of it and tried adding a context to my logic thread like this:

Code: [Select]

// NOTE: This is actually my base class that wraps around a sf::Thread.
void Threading::Looper::Loop()
{
sf::Context context; // Added here <-----
while( mySynchro.myShouldThreadExit == false )
{
if( mySynchro.myIsThreadAllowedToStart == true )
{
Init();  // Image is loaded to memory here <-----
break;
}
System::OS::Yield();
}

while( mySynchro.myShouldThreadExit == false )
{
if( mySynchro.myIsThreadAllowedToStart == true )
{
mySynchro.myIsThreadAllowedToStart = false;
Frame();
mySynchro.myIsThreadFinished = true;
}
else
{
System::OS::Yield();
}
}
}


No change what so ever EXCEPT that when I exit now I see the sprite with it's actual graphics for one frame before the window closes.

So what am I missing? Is there nothing on the SFML side I've missed and it has to be something stupid on my behalf? Since it works in Debug but not in Release I feel like I have a race condition. But it freaks me out that I could load the image without a context and that's why I'm checking here first.

Ow yeh moving the loading of the image to the main thread does solve it for release. But I don't find this acceptable as then I can't have a responsive loading screen(Main handles events and thread synchronization).
Developer and Maker of rbSFML and Programmer at Paradox Development Studio

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
I'm missing something with sf::Context and sf::Image
« Reply #1 on: June 03, 2011, 08:43:24 pm »
If you're using a recent SFML 2 revision, there's no need to explicitely declare a sf::Context anymore in threads.

And for your problem... Sorry but your code is hard to figure out, there's a lot of custom threading stuff but what I'd like to see is image and sprite related code instead ;)

A minimal example would be great, when there's too much stuff to debug it's easy to get lost, especially when threads are involved.
Laurent Gomila - SFML developer

Groogy

  • Hero Member
  • *****
  • Posts: 1469
    • MSN Messenger - groogy@groogy.se
    • View Profile
    • http://www.groogy.se
    • Email
I'm missing something with sf::Context and sf::Image
« Reply #2 on: June 03, 2011, 10:55:36 pm »
Quote from: "Laurent"
A minimal example would be great, when there's too much stuff to debug it's easy to get lost, especially when threads are involved.


I tried but I can't reproduce it XD My try was:

Code: [Select]
void ThreadFunction()
{
sf::Context context;
ourTexture.LoadFromFile( "hal-9000-eye.jpg" );
}

void RenderFunction( sf::RenderWindow *aWindow )
{
aWindow->SetActive( true );
sf::Sprite sprite( ourTexture );
aWindow->Draw( sprite );
aWindow->Display();
}

int main()
{
CreateGlobalManagers();
sf::RenderWindow myWindow;
myWindow.Create( sf::VideoMode( 800, 600 ), "MyEpic" );
myWindow.SetActive( false );
sf::Thread thread( ThreadFunction );
thread.Launch();
thread.Wait();
sf::Thread renderer( RenderFunction, &myWindow );
renderer.Launch();
renderer.Wait();
sf::Sleep( 1000 );
return 0;
}


Though this does show me correct result but it is a minimal version of what I do. Load an image in another thread and then display it in another. The thing that differentiate here is that the threads are not run parallel to each others. Though it does mimic what my application does( As graphics can't draw the sprite until the image has been loaded )

And for how it is actually done in my application:
Code: [Select]

// Run on Logics
void Game::Init( SignalSender &aSender )
{
mySender = &aSender;

// My resource manager for textures, actually only sf::Images but they are going to be used for 3D models too so this name felt better.
TextureHandle texture = TextureManager::Instance().Get( "hal-9000-eye.jpg" );
ModelHandle model = ModelManager::Instance().Get( "Cubes.obj" );

myTestSprite = I::Sprite( "test.sprite" ); // A Interface class for the real sprite on the graphic thread.
// These calls are converted to inter-thread messages.
myTestSprite.SetTexture( texture );
myTestSprite.SetScale( 0.5f, 0.5f );
myTestSprite.SetPosition( 100, 100 );

myTestObject = I::Object( "test.object" ); // A Interface class for a 3D object
myTestObject.SetModel( model );

myCamera.SetPosition( 0, 0, 10 );

myPlayer = new PlayerController(); // Only handles my camera
}

// Run on graphics
void ApplicationGraphics::RenderSprite( const RenderData &someData )
{
someData;
myContext.Prepare2DView();
myContext.Render( *mySelectedSprite );
myContext.Prepare3DView();
}

void ApplicationGraphics::LoadSprite( const RenderData &someData )
{
mySelectedSprite->SetImage( *someData.texture );
}



I don't think there should be anything more relevant actually.

What really bugs me is that ALL values on the sprite is right. Even the pixels pointer, so it's just a bit annoying that the gaphics isn't being drawn =/
I am actually thinking of moving loading to the main thread actually but I want to understand why this is happening before continuing. You know so I don't get this bug creeping up on me again ^^
Developer and Maker of rbSFML and Programmer at Paradox Development Studio

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
I'm missing something with sf::Context and sf::Image
« Reply #3 on: June 04, 2011, 10:56:17 am »
If a minimal example doesn't show the same problem, I won't be able to help you.

It will probably be hard to find what's wrong in your code. What you can try is to start with this piece of code, and add stuff gradually until it happens again.
Laurent Gomila - SFML developer

Groogy

  • Hero Member
  • *****
  • Posts: 1469
    • MSN Messenger - groogy@groogy.se
    • View Profile
    • http://www.groogy.se
    • Email
I'm missing something with sf::Context and sf::Image
« Reply #4 on: June 04, 2011, 03:13:39 pm »
I Think I got a minimal example! Here's what I got:

Code: [Select]
sf::Image ourTexture;
bool ourTextureLoaded = false;
bool ourIsRunning = true;

void LogicFunction()
{
ourTexture.LoadFromFile( "hal-9000-eye.jpg" );
ourTextureLoaded = true;
}

void RenderFunction( sf::RenderWindow *aWindow )
{
aWindow->SetActive( true );
sf::Sprite sprite;
bool spriteTextureSet = false;
while( ourIsRunning == true )
{
aWindow->Clear();
if( ourTextureLoaded == true )
{
if( spriteTextureSet == false )
{
sprite.SetImage( ourTexture );
spriteTextureSet = true;
}
aWindow->Draw( sprite );
}
aWindow->Display();
sf::Sleep( 0 )
}
}

int main()
{
sf::RenderWindow window( sf::VideoMode( 800, 600 ), "Test" );
window.SetActive( false );
sf::Thread logics( LogicFunction );
sf::Thread graphics( RenderFunction, &window );
logics.Launch();
graphics.Launch();
while( ourIsRunning == true )
{
sf::Event event;
while( window.PollEvent( event ) == true )
{
if( event.Type == sf::Event::Closed )
{
ourIsRunning = false;
window.Close();
}
}
sf::Sleep( 0 )
std::stringstream error;
error.set_rdbuf( sf::Err().rdbuf() );
if( error.str().size() > 0 )
{
MessageBoxA( NULL, error.str().c_str(), "SFML Error", 0 );
}
}
return 0;
}


This gives an EXACT replication of what happens in my application. Works in Debug but not in Release. Visual Studio 2010 and the latest version of SFML from github( I always have the latest since I have to make sure it works with rbSFML :P ).
Developer and Maker of rbSFML and Programmer at Paradox Development Studio

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
I'm missing something with sf::Context and sf::Image
« Reply #5 on: June 04, 2011, 04:08:14 pm »
Works for me.

The only things that I've changed are:
- the image is not constructed at global init but in main (although global variables are not recommended, I should fix this issue)
- the image is created from scratch rather than loaded from an image that I don't have ;)
- I removed all the non-standard code that didn't compile

Here is my code:
Code: [Select]
#include <SFML/Graphics.hpp>

sf::Image* ourTexture = NULL;
bool ourTextureLoaded = false;
bool ourIsRunning = true;

void LogicFunction()
{
   ourTexture->Create(500, 500, sf::Color(0, 255, 0));
   ourTextureLoaded = true;
}

void RenderFunction( sf::RenderWindow *aWindow )
{
   aWindow->SetActive( true );
   sf::Sprite sprite;
   bool spriteTextureSet = false;
   while( ourIsRunning == true )
   {
      aWindow->Clear();
      if( ourTextureLoaded == true )
      {
         if( spriteTextureSet == false )
         {
            sprite.SetImage( *ourTexture );
            spriteTextureSet = true;
         }
         aWindow->Draw( sprite );
      }
      aWindow->Display();
      sf::Sleep( 0 );
   }
}

int main()
{
   ourTexture = new sf::Image;
   sf::RenderWindow window( sf::VideoMode( 800, 600 ), "Test" );
   window.SetActive( false );
   sf::Thread logics( LogicFunction );
   sf::Thread graphics( RenderFunction, &window );
   logics.Launch();
   graphics.Launch();
   while( ourIsRunning == true )
   {
      sf::Event event;
      while( window.PollEvent( event ) == true )
      {
         if( event.Type == sf::Event::Closed )
         {
            ourIsRunning = false;
            window.Close();
         }
      }
      sf::Sleep( 0 ) ;
   }
   return 0;
}
Laurent Gomila - SFML developer

Groogy

  • Hero Member
  • *****
  • Posts: 1469
    • MSN Messenger - groogy@groogy.se
    • View Profile
    • http://www.groogy.se
    • Email
I'm missing something with sf::Context and sf::Image
« Reply #6 on: June 04, 2011, 04:17:01 pm »
That code shows me an all white box just like with my own code. But in debug of course it's green.
Developer and Maker of rbSFML and Programmer at Paradox Development Studio

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
I'm missing something with sf::Context and sf::Image
« Reply #7 on: June 04, 2011, 08:33:59 pm »
Oops sorry I forgot about that and only tested in debug mode :lol:

I'll try in release mode tomorrow.
Laurent Gomila - SFML developer

Groogy

  • Hero Member
  • *****
  • Posts: 1469
    • MSN Messenger - groogy@groogy.se
    • View Profile
    • http://www.groogy.se
    • Email
I'm missing something with sf::Context and sf::Image
« Reply #8 on: June 04, 2011, 08:36:53 pm »
Quote from: "Laurent"
Oops sorry I forgot about that and only tested in debug mode :lol:

I'll try in release mode tomorrow.


Sweet no worries. I got school projects to finish. The library I'm doing right now is for my second year at The Game Assembly where we will be doing 3D, since we start with our fifth game immediately when school start it would be nice to have a working 3D engine that fills the criteria from our teachers.

So we got the entire summer to get this problem working ^^

Also since I managed to create this minimal code example, and if it doesn't work at your machine it seems like I've found a bug in SFML  :shock: It was like that when I came here :roll:

Otherwise if it does work for you then it's probably my computer and I'll find a second one to test it on.
Developer and Maker of rbSFML and Programmer at Paradox Development Studio

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
I'm missing something with sf::Context and sf::Image
« Reply #9 on: June 05, 2011, 11:07:12 am »
I can reproduce the bug in release mode. I though it was a side-effect of optimization settings, but disabling them doesn't solve the problem. So I have no idea.
Laurent Gomila - SFML developer

Groogy

  • Hero Member
  • *****
  • Posts: 1469
    • MSN Messenger - groogy@groogy.se
    • View Profile
    • http://www.groogy.se
    • Email
I'm missing something with sf::Context and sf::Image
« Reply #10 on: June 05, 2011, 11:46:00 am »
Quote from: "Laurent"
I can reproduce the bug in release mode. I though it was a side-effect of optimization settings, but disabling them doesn't solve the problem. So I have no idea.


 I think I remember somewhere someone talking about problems with Textures not being bound a second time or something? And you hoped your idea of a Texture class would solve it? Might be related to that?

Because the texture has been loaded as the pixels are set correctly and the sf::Image itself got correct values. And since it is in release it's probably an uninitialized variable somewhere prohibiting the texture from being bound.

Though I am just guessing of course ^^
Developer and Maker of rbSFML and Programmer at Paradox Development Studio

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
I'm missing something with sf::Context and sf::Image
« Reply #11 on: June 05, 2011, 11:52:55 am »
Quote
I think I remember somewhere someone talking about problems with Textures not being bound a second time or something? And you hoped your idea of a Texture class would solve it? Might be related to that?

Nop, I just tried and it doesn't change anything.
Laurent Gomila - SFML developer

Groogy

  • Hero Member
  • *****
  • Posts: 1469
    • MSN Messenger - groogy@groogy.se
    • View Profile
    • http://www.groogy.se
    • Email
I'm missing something with sf::Context and sf::Image
« Reply #12 on: June 10, 2011, 12:08:17 am »
Coming a little further. Now when I first draw a sprite and then a 3D cube with texture on... In release the cube(the last texture) texture turns white while now the sprite has it's texture drawn.

Release:


Debug:


Hopefully this will help you out :P You should be able to get a similar result just by drawing two sprites. As all I do is calling sf::Image::Bind when loading a material for a model. Here the sf::Image is the diffuse map.
Somehow the last texture is not being bound.
Developer and Maker of rbSFML and Programmer at Paradox Development Studio

Groogy

  • Hero Member
  • *****
  • Posts: 1469
    • MSN Messenger - groogy@groogy.se
    • View Profile
    • http://www.groogy.se
    • Email
I'm missing something with sf::Context and sf::Image
« Reply #13 on: June 12, 2011, 02:55:28 am »
Alright just in case anyone else get this problem I will post a hotfix here. It's not a real solution but it will make it work in Release. Don't know if it will help you find the problem Laurent. But for everyone else this will fix your problem if you are having problems with textures/images being loaded in one thread and then used in another.

HOW TO FIX IT!
I created an image that is always loaded last that I call "bugfix.jpg". So just make sure that you always load one last image. You don't need to draw it or anything. You only need to load it last.

WHAT IS HAPPENING?
Well I tried to understand it but it puzzled me... Because if I changed the order of how I drawed the sprite and cube, it was still the same texture that was being omitted.
So I thought... "Hmm let's see if we can get the previous behaviour back"
The behaviour I was thinking about was that the sprite texture was omitted. So I commented out the render call of my cube so that it's texture was never bound. But I was surprised. The sprite was still being drawn with it's texture, not giving me the same result as before! I was puzzled but started thinking... What's the difference between before and now? And it occurred to me, I'm loading a second texture! So I tried just loading a third texture into memory, not drawing it or anything. And it worked!

So somehow it seems like the last image you load into memory is in fact... not loaded into memory until next image is being loaded. This of course only seem to apply if you are loading a texture/image in a thread that is not main and then use this texture/image for drawing in another thread than it was loaded in(also not main).

Example code for reproducing the problem also the hotfix is presented in commented code.
Code: [Select]
#include <SFML\Graphics.hpp>

sf::Image* ourTexture = NULL;
bool ourTextureLoaded = false;
bool ourIsRunning = true;

void LogicFunction()
{
   ourTexture->Create(500, 500, sf::Color(0, 255, 0));
   ourTextureLoaded = true;
   /* These two lines of code fixes everything!
    * sf::Image bugFixImage;
    * bugFixImage.Create(1,1);
    */
}

void RenderFunction( sf::RenderWindow *aWindow )
{
   aWindow->SetActive( true );
   sf::Sprite sprite;
   bool spriteTextureSet = false;
   while( ourIsRunning == true )
   {
      aWindow->Clear();
      if( ourTextureLoaded == true )
      {
         if( spriteTextureSet == false )
         {
            sprite.SetImage( *ourTexture );
            spriteTextureSet = true;
         }
         aWindow->Draw( sprite );
      }
      aWindow->Display();
      sf::Sleep( 0 );
   }
}

int main()
{
   ourTexture = new sf::Image;
   sf::RenderWindow window( sf::VideoMode( 800, 600 ), "Test" );
   window.SetActive( false );
   sf::Thread logics( LogicFunction );
   sf::Thread graphics( RenderFunction, &window );
   logics.Launch();
   graphics.Launch();
   while( ourIsRunning == true )
   {
      sf::Event event;
      while( window.PollEvent( event ) == true )
      {
         if( event.Type == sf::Event::Closed )
         {
            ourIsRunning = false;
            window.Close();
         }
      }
      sf::Sleep( 0 ) ;
   }
   return 0;
}
Developer and Maker of rbSFML and Programmer at Paradox Development Studio