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

Author Topic: problem with render images and threads  (Read 4677 times)

0 Members and 1 Guest are viewing this topic.

T.T.H.

  • Full Member
  • ***
  • Posts: 112
    • View Profile
problem with render images and threads
« on: July 12, 2010, 03:54:07 pm »
I've ran into the following problem: when a render image is created in one thread it cannot be modified anymore in another thread. The render image is still there and it can e.x. be saved, but whatever modification (clear, draw, etc.) I throw at it the image won't change. Please note that I already do allocate an sf::Context in every thread.

The following minimalistic code example demonstrates the problem:
Code: [Select]
// include SFML
#include <SFML/Graphics.hpp>

// include STD
#include <iostream>
#include <fstream>
#include <sstream>

// include threads
#include <windows.h>
#include <process.h>

// global variable (for simplicity)
sf::RenderImage* g_pRenderImage = NULL;

// thread function
unsigned int _stdcall ThreadFunction(void* pParam)
{
  // create SFML context in every thread
  sf::Context MyContext;

  // get and output thread index
  int* pThreadIndex = (int*) pParam;
  std::cout << "thread " << *pThreadIndex << " started" << std::endl;

  // create or reuse render image
  if (g_pRenderImage == NULL) {
    std::cout << "  creating render image" << std::endl;
    g_pRenderImage = new sf::RenderImage;
    g_pRenderImage->Create(300, 100);
  } else {
    std::cout << "  reusing render image" << std::endl;
  }

  // loop
  int ImageIndex;
  for (ImageIndex = 0; ImageIndex < 2; ++ImageIndex) {

    // clear render image
    g_pRenderImage->Clear(sf::Color(200, 200, 200));

    // create label
    std::stringstream Label;
    Label << "thread" << *pThreadIndex << "image" << ImageIndex;

    // create SFML text from label
    sf::Text MyText(Label.str());
    MyText.SetColor(sf::Color(255, 0, 0));
    MyText.SetPosition(20.0f, 20.0f);

    // draw SFML text
    g_pRenderImage->Draw(MyText);

    // display (finish) render image
    g_pRenderImage->Display();

    // save render image
    std::cout << "  saving image '" << Label.str() << ".png'" << std::endl;
    g_pRenderImage->GetImage().SaveToFile(Label.str() + ".png");
  }

  std::cout << "  done" << std::endl;
  return 0;
}

// main function
int main(int argc, char** argv)
{
  // create SFML context in main thread
  sf::Context MyContext;

  // loop over threads
  int ThreadIndex;
  for (ThreadIndex = 0; ThreadIndex < 2; ++ThreadIndex) {

    // create thread
    unsigned int TempThreadID = 0;
    HANDLE TempThreadHandle = (HANDLE) _beginthreadex(
        NULL,           // no security attributes
        0,              // use default stack size
        ThreadFunction, // thread function
        &ThreadIndex,   // argument to thread function
        0,              // use default creation flags
        &TempThreadID); // returns the thread identifier

    // handle thread creation error
    if (TempThreadHandle == NULL) {
      std::cout << "failed to create thread " << ThreadIndex << std::endl;
      return 1;
    }

    // wait till thread finishes
    WaitForSingleObject(TempThreadHandle, INFINITE);
  }

  return 0;
}

This code was made with Visual C++ 2003 .NET on Windows XP 32 Bit using https://sfml.svn.sourceforge.net/svnroot/sfml/branches/sfml2 revision 1523.

After running this code there will be 4 image files:

"thread0image0.png" containing the text "thread0image0" which is correct.
"thread0image1.png" containing the text "thread0image1" which is correct.
"thread1image0.png" containing the text "thread0image1" which is wrong.
"thread1image1.png" containing the text "thread0image1" which is wrong.

Based on my actual, big project using multiple threads seems to work for render windows, but as the example above shows it does not work for render images.

I'd like to know whether I'm doing something wrong, whether this is intended/expected behaviour or whether this is a bug, thanks.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
problem with render images and threads
« Reply #1 on: July 12, 2010, 04:17:00 pm »
Render-images have their own context, it must explicitely be deactivated before being used in another thread.

Code: [Select]
g_pRenderImage->SetActive(false);

Note that you don't need to do anything for activating the context, it is always done implicitely.
Laurent Gomila - SFML developer

T.T.H.

  • Full Member
  • ***
  • Posts: 112
    • View Profile
problem with render images and threads
« Reply #2 on: July 12, 2010, 04:32:38 pm »
Thanks for the hint, but where exactly in my code do I have to put this statement? (sorry, can't get it to work myself)

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
problem with render images and threads
« Reply #3 on: July 12, 2010, 05:14:42 pm »
Forget about your example, it won't work anyway. You would have to use a mutex (at least) to make sure that a thread can complete a frame without being interrupted by another one.

You have to call this function when you're done using a render-image in one thread, and before another thread starts using it.
Laurent Gomila - SFML developer

T.T.H.

  • Full Member
  • ***
  • Posts: 112
    • View Profile
problem with render images and threads
« Reply #4 on: July 12, 2010, 06:07:57 pm »
Quote from: "Laurent"
Forget about your example, it won't work anyway. You would have to use a mutex (at least) to make sure that a thread can complete a frame without being interrupted by another one.

In my example is a...
Code: [Select]
WaitForSingleObject(TempThreadHandle, INFINITE);
...which ensures that no thread runs in parallel.

In my actual project it's a bit different but even there I already ensure that the very same thread renders a complete frame.


Quote from: "Laurent"
You have to call this function when you're done using a render-image in one thread, and before another thread starts using it.


This would be here then...
Code: [Select]
<snip>
    // display (finish) render image
    g_pRenderImage->Display();

    // save render image
    std::cout << "  saving image '" << Label.str() << ".png'" << std::endl;
    g_pRenderImage->GetImage().SaveToFile(Label.str() + ".png");
  }

  // fix?
  g_pRenderImage->SetActive(false); // <<<<<< NEW <<<<<<<

  std::cout << "  done" << std::endl;
  return 0;
}

// main function
int main(int argc, char** argv)
{
<snip>

...but this does not fix the issue.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
problem with render images and threads
« Reply #5 on: July 12, 2010, 07:33:47 pm »
Quote
which ensures that no thread runs in parallel.

Sorry, I read your code too quickly, and I thought it was a WaitForMultipleObject outside the loop :)

Quote
but this does not  fix the issue.

Indeed, there's something wrong here. I'll do more tests and I'll let you know if I can find something.
Laurent Gomila - SFML developer

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
problem with render images and threads
« Reply #6 on: July 12, 2010, 07:50:00 pm »
It seems to be related to the FBO implementation of render-images. So if you need to make it work until I find a solution, you can disable the corresponding code in src/SFML/Graphics/RenderImage.cpp:
Code: [Select]
   /* ----- commented ---- if (priv::RenderImageImplFBO::IsSupported())
    {
        // Use FBO
        myRenderImage = new priv::RenderImageImplFBO;
    }
    else ----- end of comment ----- */ if (priv::RenderImageImplPBuffer::IsSupported())
    {
        // Use P-Buffer
        myRenderImage = new priv::RenderImageImplPBuffer;
    }
Laurent Gomila - SFML developer

T.T.H.

  • Full Member
  • ***
  • Posts: 112
    • View Profile
problem with render images and threads
« Reply #7 on: July 13, 2010, 10:36:32 am »
Thank you, that change in RenderImages.cpp does solve the issue.

It is even not necessary to call...
Code: [Select]
g_pRenderImage->SetActive(false);
...then.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
problem with render images and threads
« Reply #8 on: July 13, 2010, 11:21:29 am »
Quote
It is even not necessary to call...

Ah, you're right, this is not necessary for render images. It's only required for render windows.
Laurent Gomila - SFML developer

 

anything