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

Author Topic: OpenGL load texture from Thread  (Read 9569 times)

0 Members and 4 Guests are viewing this topic.

CytraL

  • Jr. Member
  • **
  • Posts: 68
    • View Profile
    • GitHub
OpenGL load texture from Thread
« on: September 14, 2013, 07:00:09 pm »
Hi, i can't use search function... says "DATABASE ERROR".

I'm trying load texture from a thread, but Main thread can't use textures....

Main Thread:
Code: [Select]
    hdc = GetDC(m_pPictureSelector->getSystemHandle());
    mainContext = wglGetCurrentContext();
    loaderContext = wglCreateContext(hdc);

    wglShareLists(loaderContext, mainContext);
    sf::Thread thread(&LoadPictures, m_pPictureSelector);
    thread.launch();

Thread:
Code: [Select]
void LoadPictures(CPictureSelector *pPictureSel)
{
    wglMakeCurrent(hdc, loaderContext);
    pPictureSel->LoadPictures();
    wglMakeCurrent(NULL, NULL);
    wglDeleteContext(loaderContext);
}


Function that load Textures
Code: [Select]
int CPictureSelector::LoadTexture(const char *filepath)
{
    sf::Image img;
    if (!img.loadFromFile(filepath))
        return -1;

    m_vTextures.push_back(0);
    glGenTextures(1, &m_vTextures[m_vTextures.size()-1]);
    glBindTexture(GL_TEXTURE_2D, m_vTextures[m_vTextures.size()-1]);
    gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, img.getSize().x, img.getSize().y, GL_RGBA, GL_UNSIGNED_BYTE, img.getPixelsPtr());
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

    return m_vTextures.size()-1;
}

What am I doing wrong? thx!
dev@redneboa.es | WordPress | GitHub | YouTube

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: OpenGL load texture from Thread
« Reply #1 on: September 14, 2013, 08:22:34 pm »
The first thing to do is to check all your WGL and OpenGL calls. If one fails, you won't notice it with your current code.
Laurent Gomila - SFML developer

CytraL

  • Jr. Member
  • **
  • Posts: 68
    • View Profile
    • GitHub
Re: OpenGL load texture from Thread
« Reply #2 on: September 14, 2013, 10:09:03 pm »
In "Thread"

    wglMakeCurrent(NULL, NULL);
    wglDeleteContext(loaderContext);

returns

GL_INVALID_OPERATION


but i don't know why....

thx!
dev@redneboa.es | WordPress | GitHub | YouTube

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: OpenGL load texture from Thread
« Reply #3 on: September 14, 2013, 10:56:39 pm »
Quote
In "Thread"

    wglMakeCurrent(NULL, NULL);
    wglDeleteContext(loaderContext);

returns

GL_INVALID_OPERATION
Which one? :P
Laurent Gomila - SFML developer

CytraL

  • Jr. Member
  • **
  • Posts: 68
    • View Profile
    • GitHub
Re: OpenGL load texture from Thread
« Reply #4 on: September 14, 2013, 10:59:22 pm »
wglMakeCurrent(NULL, NULL);    --> GL_INVALID_OPERATION

and

wglDeleteContext(loaderContext);  --> GL_INVALID_OPERATION


Code: [Select]
void LoadPictures(CPictureSelector *pPictureSel)
{
    wglMakeCurrent(hdc, loaderContext);
    PrintLastCallResult("MakeCurrent Loader: ");
    pPictureSel->LoadPictures();
    wglMakeCurrent(NULL, NULL);
    PrintLastCallResult("MakeCurrent NULL: ");
    wglDeleteContext(loaderContext);
    PrintLastCallResult("Delete Context: ");
}

Result:
Code: [Select]
MainContext: GL_NO_ERROR
LoaderContext: GL_NO_ERROR
ShareList: GL_NO_ERROR

MakeCurrent Loader: GL_NO_ERROR
MakeCurrent NULL: GL_INVALID_OPERATION
Delete Context: GL_INVALID_OPERATION


;)
« Last Edit: September 14, 2013, 11:01:16 pm by CytraL »
dev@redneboa.es | WordPress | GitHub | YouTube

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: OpenGL load texture from Thread
« Reply #5 on: September 14, 2013, 11:16:52 pm »
The last OpenGL error is not cleared until you check it. So what an error means is that it happened anywhere between your last check and the current one.

So you should check error after pPictureSel->LoadPictures() too.
Laurent Gomila - SFML developer

CytraL

  • Jr. Member
  • **
  • Posts: 68
    • View Profile
    • GitHub
Re: OpenGL load texture from Thread
« Reply #6 on: September 14, 2013, 11:53:56 pm »
Code: [Select]
-- Main Thread:
MainContext: GL_NO_ERROR
LoaderContext: GL_NO_ERROR
ShareList: GL_NO_ERROR

-- Thread:
MakeCurrent Loader: GL_NO_ERROR
---- Thread m_pPictureSel->LoadPictures():
------ LoadTexture() #1:
Gen Textures: GL_NO_ERROR
BindTexture: GL_NO_ERROR
gluBuild2DMipmaps: GL_NO_ERROR
TextParameter MIN_FILTER: GL_NO_ERROR
TextParameter MAG_FILTER: GL_NO_ERROR
TextParameter WRAP_S: GL_NO_ERROR
TextParameter WRAP_T: GL_NO_ERROR
------ LoadTexture() #2:
Gen Textures: GL_NO_ERROR
BindTexture: GL_NO_ERROR
gluBuild2DMipmaps: GL_NO_ERROR
TextParameter MIN_FILTER: GL_NO_ERROR
TextParameter MAG_FILTER: GL_NO_ERROR
TextParameter WRAP_S: GL_NO_ERROR
TextParameter WRAP_T: GL_NO_ERROR
------ LoadTexture() #3:
Gen Textures: GL_NO_ERROR
BindTexture: GL_NO_ERROR
gluBuild2DMipmaps: GL_NO_ERROR
TextParameter MIN_FILTER: GL_NO_ERROR
TextParameter MAG_FILTER: GL_NO_ERROR
TextParameter WRAP_S: GL_NO_ERROR
TextParameter WRAP_T: GL_NO_ERROR
------ LoadTexture() #4:
Gen Textures: GL_NO_ERROR
BindTexture: GL_NO_ERROR
gluBuild2DMipmaps: GL_NO_ERROR
TextParameter MIN_FILTER: GL_NO_ERROR
TextParameter MAG_FILTER: GL_NO_ERROR
TextParameter WRAP_S: GL_NO_ERROR
TextParameter WRAP_T: GL_NO_ERROR
------ LoadTexture() #5:
Gen Textures: GL_NO_ERROR
BindTexture: GL_NO_ERROR
gluBuild2DMipmaps: GL_NO_ERROR
TextParameter MIN_FILTER: GL_NO_ERROR
TextParameter MAG_FILTER: GL_NO_ERROR
TextParameter WRAP_S: GL_NO_ERROR
TextParameter WRAP_T: GL_NO_ERROR
------ LoadTexture() #6:
Gen Textures: GL_NO_ERROR
BindTexture: GL_NO_ERROR
gluBuild2DMipmaps: GL_NO_ERROR
TextParameter MIN_FILTER: GL_NO_ERROR
TextParameter MAG_FILTER: GL_NO_ERROR
TextParameter WRAP_S: GL_NO_ERROR
TextParameter WRAP_T: GL_NO_ERROR
-- Thread:
MakeCurrent NULL: GL_INVALID_OPERATION
Delete Loader Context: GL_INVALID_OPERATION

P.S: If i don't use threads (Call directly "m_pPictureSelector->LoadPictures()) all works  fine.
« Last Edit: September 14, 2013, 11:56:18 pm by CytraL »
dev@redneboa.es | WordPress | GitHub | YouTube

CytraL

  • Jr. Member
  • **
  • Posts: 68
    • View Profile
    • GitHub
Re: OpenGL load texture from Thread
« Reply #7 on: September 16, 2013, 09:35:46 pm »
Any reply?   i only need know how load textures from a thread.... thx! or any web where i can read about this :)

I need load sf::Image in the thread and load OpenGL Textures in main thread?
dev@redneboa.es | WordPress | GitHub | YouTube

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: OpenGL load texture from Thread
« Reply #8 on: September 16, 2013, 09:50:10 pm »
But... why do you use WGL code instead of SFML?
Laurent Gomila - SFML developer

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
Re: OpenGL load texture from Thread
« Reply #9 on: September 16, 2013, 09:59:10 pm »
I'm just curious... why do you need to load textures from a separate thread? Unless you load 1000s of textures from your harddisk, it should not even be noticeable unless you have a really crappy harddisk/controller/...

On the other hand, what you can do is load the images in a separate thread and load the images onto the GPU as textures in the main thread. Because of DMA you should not get any performance decrease from doing so, even when comparing to loading from a separate thread.

I really can't stand people who give bad advice such as "using threads makes everything faster" or "use threads so that your UI doesn't freeze when doing something that takes a long time", those people obviously don't have enough experience to understand what they say does not apply universally and hence they shouldn't give such advice until they ask about the circumstances.

OpenGL was not made to take advantage of multiple threads, let alone SMP processors. It might have changed with recent OpenGL, but drivers tend to queue everything and dispatch from a single thread whenever they can. There is only 1 physical PCIe connection per GPU and hence only 1 bus that everything can go over. Trying really hard to do perform 2 OpenGL operations truly simultaneously is just wasted effort.
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).

CytraL

  • Jr. Member
  • **
  • Posts: 68
    • View Profile
    • GitHub
Re: OpenGL load texture from Thread
« Reply #10 on: September 16, 2013, 10:55:50 pm »
But... why do you use WGL code instead of SFML?

I'm noob with OpenGL, but i read this: http://higherorderfun.com/blog/2011/05/26/multi-thread-opengl-texture-loading/

I'm just curious... why do you need to load textures from a separate thread? Unless you load 1000s of textures from your harddisk, it should not even be noticeable unless you have a really crappy harddisk/controller/...

On the other hand, what you can do is load the images in a separate thread and load the images onto the GPU as textures in the main thread. Because of DMA you should not get any performance decrease from doing so, even when comparing to loading from a separate thread.

I really can't stand people who give bad advice such as "using threads makes everything faster" or "use threads so that your UI doesn't freeze when doing something that takes a long time", those people obviously don't have enough experience to understand what they say does not apply universally and hence they shouldn't give such advice until they ask about the circumstances.

OpenGL was not made to take advantage of multiple threads, let alone SMP processors. It might have changed with recent OpenGL, but drivers tend to queue everything and dispatch from a single thread whenever they can. There is only 1 physical PCIe connection per GPU and hence only 1 bus that everything can go over. Trying really hard to do perform 2 OpenGL operations truly simultaneously is just wasted effort.

I have a SSD and only 15 pictures in the folder... and i need threads why if not the window shows freezed. Sorry for my ignorance but how i can pre-load the images that i need and not freeze the window without a thread? thx :)


I will try only call .loadFromFile() in the Thread.
dev@redneboa.es | WordPress | GitHub | YouTube

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: OpenGL load texture from Thread
« Reply #11 on: September 16, 2013, 11:01:29 pm »
Quote
I'm noob with OpenGL, but i read this: http://higherorderfun.com/blog/2011/05/26/multi-thread-opengl-texture-loading/
What about reading the SFML tutorials first? :P

http://www.sfml-dev.org/tutorials/2.1/window-opengl.php#opengl-without-a-window

Quote
I have a SSD and only 15 pictures in the folder... and i need threads why if not the window shows freezed
It freezes with a SSD and 15 pictures? How long? What's the size and format of your images?
Laurent Gomila - SFML developer

CytraL

  • Jr. Member
  • **
  • Posts: 68
    • View Profile
    • GitHub
Re: OpenGL load texture from Thread
« Reply #12 on: September 16, 2013, 11:17:28 pm »
Omg.... just that i need xD sry :\


formats: jpg and png
size: 1600x1200 .. 1024x768 ...
dev@redneboa.es | WordPress | GitHub | YouTube

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
Re: OpenGL load texture from Thread
« Reply #13 on: September 17, 2013, 12:24:27 am »
OK... really... just stay away from those kinds of articles. I can't think of how you can convey more wrong ideas than in that article. While what the author wants to get done actually gets done, it is not only inefficient, it might not even address the real problem.

1. The author assumes that the reason for even offloading the loading to another thread is the fact that the texture data uploading, as opposed to the much more likely image loading from disk, takes more time. This is simply not true unless you have a REALLY broken system. Memory buses are always order of magnitudes faster than storage IO controllers, even if you have a cheap IGP. What you should do is the complete opposite: load from storage in a separate thread and upload texture in the main thread. If the author's runLoader() function contains both, then either they are too lazy to separate them, or they overestimate the time it takes for the upload. It is true that the OpenGL call to load the texture data blocks. But depending on what the driver really does, it can block for differing amounts of time. Since all modern PCIe hardware makes use of DMA to transfer data, one can reliably assume that anything that you transfer to the GPU gets buffered in a separate DMA buffer in your system RAM for the GPU to "pull" over the PCIe bus when it is instructed to. Using a "pushing" variant of the driver would simply be too slow and eat up precious CPU cycles which is not something we want. Basically the call to glTexImage2D "does not block" or blocks for as little time as any other moderately complex operation involving memory copies.

2. The author states that when loading in a separate thread, you need to call glFinish() to not corrupt the texture memory because you try to read it while it is being written to... First of all, I don't see why you want to call glFinish() in the same thread that you loaded from, it makes absolutely no sense. Assuming that they meant the main thread, do they not realize calling glFinish() is exactly what they want to avoid in the first place? It is in fact even worse than a simple blocking glTexImage2D() (if that even blocks). Calling glFinish() typically causes a sync object to be inserted into the command stream and waiting for ALL operations to complete up to that point, not only the glTexImage2D. This will cause you to wait for longer than you would have without it. The best part about this point is the fact that the author assumes that the broken behaviour they describe is because of a race condition, and rule out any driver bugs. The whole idea of using "names" for resources that you need to get from OpenGL with the according glGen* functions is so that OpenGL can properly manage resources, even across multiple threads. When requesting a secondary context from which you do stuff, the driver should be smart enough to recognize any accesses to the same resource and make sure that no race conditions truly occur. Even if it didn't care, when you "use" a texture, you normally just bind it and do your rendering. This is also a queued command, and this will NOT be executed on the GPU at the same time as the data transfer. Broken drivers/implementation and an even more broken workaround.

3. The author is obviously worried about every nanosecond of CPU time that is wasted waiting for the texture load to finish. They seem to have forgotten about how much time OpenGL context management also takes up. Instead of performing explicit synchronization themselves, they just push the effort to the OS/driver and expect to magically gain performance. I'm willing to bet money that unless you load 1000+ textures, you won't even be able to measure the difference, if this implementation is even faster...

Another badly written article, containing nothing but myths that should really just die out someday. Combining C++11 code with code that is supposed to simulate proper buffer object usage on top of the legacy API is just... wrong... in all sorts of ways. If you need asynchronous transfers, buffer objects. It's that simple.
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).