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

Author Topic: [Solved] Loading Images Inside a Thread  (Read 33108 times)

0 Members and 1 Guest are viewing this topic.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
[Solved] Loading Images Inside a Thread
« Reply #30 on: November 07, 2010, 07:38:32 pm »
You should show your code.
Laurent Gomila - SFML developer

opatut

  • Newbie
  • *
  • Posts: 25
    • View Profile
[Solved] Loading Images Inside a Thread
« Reply #31 on: November 07, 2010, 09:55:19 pm »
That's a bit complicated as it is a whole engine I'm working on, but I'll try to pick the important pieces together.

This is how I start the thread:
Code: [Select]
void ResourceManager::LoadAllQueuedImages(void* data) {
auto resmgr = Root::get_mutable_instance().GetResourceManagerPtr();
while(resmgr->GetPercentageLoadingDone() < 1) {
resmgr->LoadNextImage();
}
}

void ResourceManager::StartLoadingAllQueuedImagesInBackground() {
sf::Thread thread(&ResourceManager::LoadAllQueuedImages);
thread.Launch();
sf::Sleep(20.f); // segfault occurs immediately, so it must be caused by the loader thread
}


ResourceManager::LoadNextImage() deques the next image, loads it and saves it into the boost::ptr_map. This is all a bit complicated, as I use ImageMagick to convert from *.svg, but without multithreading it works fine. The important part:

   
Code: [Select]
// Load cached file
sf::Image sfimage;
sfimage.LoadFromFile(cacheFile);
// Save loaded Image in map
mImages[image_key] = sfimage;




In my main loop I call ResourceManager::StartLoadingAllQueuedImagesInBackground() once and get the status from the ResourceManager. As I only read integers, this should be fine. And of course in debug this does not happen, as I have 20 seconds delay to avoid problems between the two threads.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
[Solved] Loading Images Inside a Thread
« Reply #32 on: November 07, 2010, 10:43:06 pm »
So you never use a sf::Context instance?
Laurent Gomila - SFML developer

opatut

  • Newbie
  • *
  • Posts: 25
    • View Profile
[Solved] Loading Images Inside a Thread
« Reply #33 on: November 07, 2010, 11:24:00 pm »
Now I do ;) It has not been mentioned in the 1.6 multithreading tutorial and I did not find anything about it...

And the 1.6 API says:
Quote
It's meant to be used internally.


Anyway, it works now. Thanks!

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
[Solved] Loading Images Inside a Thread
« Reply #34 on: November 07, 2010, 11:54:07 pm »
Yeah, I don't even remember how it is supposed to work in SFML 1.6 :lol:

But you were talking about SFML 2, so...
Laurent Gomila - SFML developer

opatut

  • Newbie
  • *
  • Posts: 25
    • View Profile
[Solved] Loading Images Inside a Thread
« Reply #35 on: November 13, 2010, 10:42:49 pm »
I am still not getting the results I want. I added an sf::Context in my loading thread, but after loading all the images they are not available from the main thread. It's not that I can't access the objects. I can even retrieve the width and height, but drawing them does nothing. I think this is again the Open GL context problem. Is it possible to use the same context in both threads or will it crash? Or do I have to load the raw data into RAM and wrap them into the sf::Image from the main thread?

/Edit: Width and Height seem to be always 48, exept while Loading the images, the GUI, which is loaded synchronously has other values. Is 48 x 48 the default size for any sf::Image?

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
[Solved] Loading Images Inside a Thread
« Reply #36 on: November 13, 2010, 11:06:54 pm »
It should work, all OpenGL contexts are shared.

Can you show your code?
Laurent Gomila - SFML developer

opatut

  • Newbie
  • *
  • Posts: 25
    • View Profile
[Solved] Loading Images Inside a Thread
« Reply #37 on: November 14, 2010, 12:05:39 am »
I don't even know what I changed over the last few minutes but now it works. Must have been the awareness that it HAS to work like this ;) Thanks, Laurent!

Svenstaro

  • Full Member
  • ***
  • Posts: 222
    • View Profile
[Solved] Loading Images Inside a Thread
« Reply #38 on: November 14, 2010, 06:59:00 pm »
I still seem to have problems with this. I'm working on the project with opatut and the threading stuff that works for him crashes for me. I debugged it quite a bit and figured it must be an implementation problem but I do not know who is at fault.

Relevant parts of backtrace on my machine (Arch Linux x86_64, Mobility Radeon X2100 with r500g drivers, mesa from recent git):

Quote
#0  0x0000000000000020 in ?? ()
#1  0x00007fffef33d1af in ?? () from /usr/lib/xorg/modules/dri/r300_dri.so
#2  0x00007fffef34b882 in ?? () from /usr/lib/xorg/modules/dri/r300_dri.so
#3  0x00007fffef4020b9 in ?? () from /usr/lib/xorg/modules/dri/r300_dri.so
#4  0x00007fffef49af57 in ?? () from /usr/lib/xorg/modules/dri/r300_dri.so
#5  0x00007fffef3e6b21 in ?? () from /usr/lib/xorg/modules/dri/r300_dri.so
#6  0x00007ffff794eccb in sf::Image::EnsureTextureUpdate() const ()
   from /usr/lib/libsfml-graphics.so.2.0
#7  0x00007ffff794ecf9 in sf::Image::Bind() const ()
   from /usr/lib/libsfml-graphics.so.2.0
#8  0x00007ffff7964a3d in sf::Renderer::SetTexture(sf::Image const*) ()
   from /usr/lib/libsfml-graphics.so.2.0
#9  0x00007ffff7969132 in sf::Sprite::Render(sf::RenderTarget&, sf::Renderer&) const ()
   from /usr/lib/libsfml-graphics.so.2.0
#10 0x00007ffff796581a in sf::RenderTarget::Draw(sf::Drawable const&) ()
   from /usr/lib/libsfml-graphics.so.2.0
#11 0x000000000055b93d in Submarine::Draw (this=0x7fffe4037390, target=0x8410a8)
    at /home/svenstaro/NoisyHunter/game/src/common/Submarine.cpp:111


Surprisingly, it works when I start it in valgrind (albeit with corruption). I originally suspected a racing condition in our code. However, it works just fine for the nvidia users with proprietary nvidia drivers.

The thread is launched as follows:
Code: [Select]
void ResourceManager::LoadAllQueuedImages(void* data) {
sf::Context context;
auto resmgr = Root::get_mutable_instance().GetResourceManagerPtr();
while(!resmgr->GetLoadingStatus().IsFinished()) {
resmgr->LoadNextImage();
}
}

The problematic line here is sf::Conext context. If I take it out, the thread breaks for nvidia users due to missing glContext but works for me (though I get white images as expected). If I put it in, nvidia users observe expected behavior but it crashes for me with the above backtrace unless I run it in valgrind, oddly enough.

The problem isn't even that the sf::Context can't somehow be created. For instance, if I run it with
Code: [Select]
void ResourceManager::LoadAllQueuedImages(void* data) {
sf::Context context;
auto resmgr = Root::get_mutable_instance().GetResourceManagerPtr();
while(!resmgr->GetLoadingStatus().IsFinished()) {
resmgr->LoadNextImage();
}
        sf::Sleep(10.f);
}

I can play for 10 seconds until the thread goes out of scope. The behavior is just as expected in that case. I'd idle the thread indefinitely but that looks like an ugly hack. I tried creating a memory leak like this:
Code: [Select]
void ResourceManager::LoadAllQueuedImages(void* data) {
sf::Context* context = new sf::Context();
auto resmgr = Root::get_mutable_instance().GetResourceManagerPtr();
while(!resmgr->GetLoadingStatus().IsFinished()) {
resmgr->LoadNextImage();
}
}

and it works without crash. It gives me almost the expected behavior. I get a few image corruptions in the images loaded in the thread. Not all images come out corrupt, but those that do are so corrupt that my driver refuses rendering them (I get a kernel exception for an invalid texture steam).

I tested the exactly same stuff on a Arch Linux i686-based Radeon Mobility FireGl 9000-series card with r200 (non-gallium) drivers and the behavior is almost exactly the same as on my r500g (the corruption looks different).

Suspecting a problem in the mesa part of this, I ran it on my Arch Linux x86_64 Virtualbox guest. In this case, the sf::Context never was created and the images were never actually loaded. They all came out white. The Virtualbox guest uses their accelerated Chromium drivers.

Can you give us some insight here? At first glance it would seem as though the drivers are at fault but on a second look this might not be actually true and the sf::Context might in fact be the problem. Any help appreciated.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
[Solved] Loading Images Inside a Thread
« Reply #39 on: November 14, 2010, 07:19:35 pm »
It's hard to tell from such a little piece of code. If you could write a complete and minimal example, I could test it and debug it on my computer.
Laurent Gomila - SFML developer

Svenstaro

  • Full Member
  • ***
  • Posts: 222
    • View Profile
[Solved] Loading Images Inside a Thread
« Reply #40 on: November 14, 2010, 08:00:29 pm »
Le minimal example:

Code: [Select]
#include <SFML/Graphics.hpp>

sf::Image image;
bool done = false;

void Thread(void* data) {
    // Swapping this causes corruption but works (kinda)
    //Sf::Context* c = new sf::Context();
    sf::Context c;
   
    // http://paradoxdgn.com/junk/avatars/trollface.jpg
    image.LoadFromFile("trollface.jpg");
    done = true;
}

int main() {
    // Create main window
    sf::RenderWindow app(sf::VideoMode(800,600,32), "Test window");

    // Load image in thread
    sf::Thread t(&Thread);
    t.Launch();

    while(app.IsOpened()) {
        sf::Event Event;
        while(app.GetEvent(Event)) {
            if(Event.Type == sf::Event::Closed) {
                app.Close();
            }
        }      
       
        app.Clear(sf::Color::White);
        // show image as soon as it is loaded
        if(done) {
            sf::Sprite lol(image);
            lol.SetPosition(100,100);
            app.Draw(lol);
        }

        app.Display();
        sf::Sleep(1);
    }
}


Gives us:
Code: [Select]
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff25b0f1a in radeon_bo_ref () from /usr/lib/libdrm_radeon.so.1
(gdb) bt
#0  0x00007ffff25b0f1a in radeon_bo_ref () from /usr/lib/libdrm_radeon.so.1
#1  0x00007ffff25b0db8 in radeon_cs_space_add_persistent_bo ()
   from /usr/lib/libdrm_radeon.so.1
#2  0x00007ffff2a2692c in ?? () from /usr/lib/xorg/modules/dri/r300_dri.so
#3  0x00007ffff2a28810 in ?? () from /usr/lib/xorg/modules/dri/r300_dri.so
#4  0x00007ffff2a28a38 in ?? () from /usr/lib/xorg/modules/dri/r300_dri.so
#5  0x00007ffff2bb5482 in ?? () from /usr/lib/xorg/modules/dri/r300_dri.so
#6  0x00007ffff2a3ace7 in ?? () from /usr/lib/xorg/modules/dri/r300_dri.so
#7  0x00007ffff2a219dc in ?? () from /usr/lib/xorg/modules/dri/r300_dri.so
#8  0x00007ffff2b71050 in ?? () from /usr/lib/xorg/modules/dri/r300_dri.so
#9  0x00007ffff2abcb21 in ?? () from /usr/lib/xorg/modules/dri/r300_dri.so
#10 0x00007ffff7b5eccb in sf::Image::EnsureTextureUpdate() const ()
   from /usr/lib/libsfml-graphics.so.2.0
#11 0x00007ffff7b5ecf9 in sf::Image::Bind() const ()
   from /usr/lib/libsfml-graphics.so.2.0
#12 0x00007ffff7b74a3d in sf::Renderer::SetTexture(sf::Image const*) ()
   from /usr/lib/libsfml-graphics.so.2.0
#13 0x00007ffff7b79132 in sf::Sprite::Render(sf::RenderTarget&, sf::Renderer&) const
    () from /usr/lib/libsfml-graphics.so.2.0
#14 0x00007ffff7b7581a in sf::RenderTarget::Draw(sf::Drawable const&) ()
---Type <return> to continue, or q <return> to quit---
   from /usr/lib/libsfml-graphics.so.2.0
#15 0x0000000000401949 in main () at main.cpp:34

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
[Solved] Loading Images Inside a Thread
« Reply #41 on: November 14, 2010, 08:28:05 pm »
With which revision of SFML 2?
Laurent Gomila - SFML developer

Svenstaro

  • Full Member
  • ***
  • Posts: 222
    • View Profile
[Solved] Loading Images Inside a Thread
« Reply #42 on: November 14, 2010, 08:52:41 pm »
Newest as of right now: 1639 (on all tested computers).

opatut

  • Newbie
  • *
  • Posts: 25
    • View Profile
[Solved] Loading Images Inside a Thread
« Reply #43 on: November 18, 2010, 08:42:34 pm »
bump

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
[Solved] Loading Images Inside a Thread
« Reply #44 on: November 18, 2010, 09:33:32 pm »
Yeah, don't worry, it's on my todo-list ;)
Laurent Gomila - SFML developer