0

I can load a texture just fine in SOIL/OpenGL normally. No errors, everything works fine:

// this is inside my texture loading code in my texture class
// that i normally use for loading textures
image = SOIL_load_OGL_texture
    (
    file,
    SOIL_LOAD_AUTO,
    SOIL_CREATE_NEW_ID,
    NULL
    );

However, using that same code and calling it from an std::thread, at the line image = SOIL_load_OGL_texture I get unhandled exception Integer Division by Zero:

void loadMe() {
    Texture* abc = new Texture("res/img/office.png");
}

void loadStuff() {
    Texture* loading = new Texture("res/img/head.png"); // < always works

    loadMe() // < always works
    std::thread textures(loadMe); // < always "integer division by zero"

Here's some relevant code from my Texture class:

// inside the class
private:
    GLint w, h;
    GLuint image;

// loading the texture (called by constructor if filename is given)
void Texture::loadImage(const char* file)
{

    image = SOIL_load_OGL_texture
        (
        file,
        SOIL_LOAD_AUTO,
        SOIL_CREATE_NEW_ID,
        NULL
        );

    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, image);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w);
    glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &h);
    glBindTexture(GL_TEXTURE_2D, 0);

    if (image <= 0)
        std::cout << file << " failed to load!\n";
    else
        std::cout << file << " loaded.\n";

    glDisable(GL_TEXTURE_2D);
}

It raises the exception exactly at image = SOIL_load_OGL_texture, and when I go into the debugger, I see things like w = -816294792 and w = -816294792, but I guess that just means it hasn't been set yet, as it also shows that in the debugger for loading the other textures.

Also, the SOIL_load_OGL_texture part of the code works fine by itself, outside of the Texture class, even in a std::thread.

Any idea what's going on here?

Accumulator
  • 873
  • 1
  • 13
  • 34
  • 3
    [OpenGL and multithreading](https://www.opengl.org/wiki/OpenGL_and_multithreading) – Ivan Aksamentov - Drop Jan 29 '16 at 02:16
  • @Drop I'm trying to render (animated loading screen) and load textures at the same time. There has to be a way, or else other games could not do it. – Accumulator Jan 29 '16 at 03:05
  • 1
    @Omega: The comment that Drop posted was actually a link, go read it. However, if you want to load in a background thread, easiest way is to map a PBO, load your texture into the PBO from the background thread, and then call `glTexImage()` from the main thread. – Dietrich Epp Jan 29 '16 at 03:44
  • Also note that `glEnable(GL_TEXTURE_2D)` does not do what you think it does. You can remove that part. – Dietrich Epp Jan 29 '16 at 03:47
  • Which OS/platform is this on ? Also did you refer to http://stackoverflow.com/questions/19341704/multi-threading-support-in-soil-for-opengl ? – Prabindh Jan 29 '16 at 04:59
  • @Omega The way to do this is to load texture data from HDD into memory on separate thread, but to create OpenGL texture objects on OpenGL thread. Thus you cannot use this SOIL function, as it does both on the same thread. Also SOIL is not thread safe. For more complicated scenarios you should do it all by hand. – Ivan Aksamentov - Drop Jan 29 '16 at 06:29
  • @Drop minor technicality - SOIL can take in externally generated texture object IDs as well instead of internally generating... – Prabindh Jan 29 '16 at 18:12

1 Answers1

0

This is how you do it. Note that, as others have mentioned in the comments, a context needs to be maintained current for every thread that uses GL. What this means is practically there cannot be a GL API call made in multiple threads without making one thread the owner of the GL context. Hence if the intention is to separate the Image loading overhead it is recommended to load the image file into a buffer using a library in a separate thread, then use that buffer to glTexImage2D in the main thread. Till the image is loaded, a dummy texture can be displayed.

I tried checking what platform you are on (see comment above), since I did not see a response, I am assuming Linux for below.

/* Regular GL context creation foo */
/* Regular attribute, uniform, shader creation foo */
/* Create a thread that does loading with SOIL in function SOIL_loader */
std::thread textureloader(SOIL_loader);
/* Wait for loader thread to finish, 
thus defeating the purpose of a thread. Ideally, 
only the image file read/decode should happen in separate thread */
textureloader.join();
/* Make the GL context current back again in the main thread 
for other actions */
glfwMakeContextCurrent((GLFWwindow*)window);
/* Some other foo */

======

And this is the loader thread function:

void SOIL_loader()
{
   glfwMakeContextCurrent((GLFWwindow*)window);
    SOIL_load_OGL_texture
        (
        "./img_test.png",
        SOIL_LOAD_AUTO,
        SOIL_CREATE_NEW_ID /* or passed ID */,
        NULL
        );
   GL_CHECK(SOIL);
}

Tested on Ubuntu 14.04, Mesa, and glfw3.

Prabindh
  • 3,356
  • 2
  • 23
  • 25