How can I load Textures in the background in EGL?

150 Views Asked by At

I'm coding a college assignment in which I need to create an openGL scene using Textures/Materials. My idea is to allow the user to decide whether to use Textures or Materials (note that this is already implemented) however, the loading of the Texture images takes too long, which makes the whole scene to hault when launching until they are all loaded up. I would like to load the images from the disk in some way (maybe threads? although I read this was not possible) while the scene is rendered with Materials, so the scene can load faster. My code for loading the Texture images looks like this:

Texture imgGold;
imgGold.initTexture("resources/textures/gold/gold.png");

And the initTexture function is provided by the teacher (we can change it tho). The Texture.cpp file looks like this:

#include "Texture.h"

//------------------------
// Crea la textura
//------------------------
void Texture::initTexture(const char *textureFile) {

    // Creamos la textura a configurar
    glGenTextures(1,&texture);
    glBindTexture(GL_TEXTURE_2D, texture);

    // Cargamos la imagen
    unsigned int  w, h;
    unsigned char *pixels = loadTexture(textureFile, w, h);

    // Creamos la textura
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, (void *)pixels);
    glGenerateMipmap(GL_TEXTURE_2D);

    // Configuramos la textura (GL_REPEAT repite textura; GL_CLAMP no, GL_LINEAR y tal mirar la teoria)
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

    float aniso;
    glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &aniso);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);

}

//--------------------------------------------------
// Carga una textura mediante la librería Freeimage
//--------------------------------------------------
unsigned char* Texture::loadTexture(const char *textureFile, unsigned int &w, unsigned int &h) {

    FreeImage_Initialise(TRUE);

    // Leemos la textura
    FREE_IMAGE_FORMAT format = FreeImage_GetFileType(textureFile,0);
    if(format==FIF_UNKNOWN) format = FreeImage_GetFIFFromFilename(textureFile);
    if((format==FIF_UNKNOWN) || !FreeImage_FIFSupportsReading(format)) {
        std::cout << "Formato de la textura " << textureFile << " no está soportado." << std::endl;
        std::cin.get();
        exit(1);
    }
    FIBITMAP *texture = FreeImage_Load(format,textureFile);
    if(texture==NULL) {
        std::cout << "El fichero " << textureFile << " no se puede abrir." << std::endl;
        std::cin.get();
        exit(1);
    }
    FIBITMAP *temp = texture;
    texture = FreeImage_ConvertTo32Bits(texture);
    FreeImage_Unload(temp);

    // De BGRA a RGBA
    w = FreeImage_GetWidth(texture);
    h = FreeImage_GetHeight(texture);
    unsigned char *pixelsBGRA = (unsigned char *)FreeImage_GetBits(texture);
    unsigned char *pixelsRGBA = new unsigned char[4*w*h];
    for(int j=0; j<w*h; j++){
        pixelsRGBA[j*4+0] = pixelsBGRA[j*4+2];
        pixelsRGBA[j*4+1] = pixelsBGRA[j*4+1];
        pixelsRGBA[j*4+2] = pixelsBGRA[j*4+0];
        pixelsRGBA[j*4+3] = pixelsBGRA[j*4+3];
    }

    FreeImage_Unload(texture);
    FreeImage_DeInitialise();

    return pixelsRGBA;
}

//-----------------------------------------
// Devuelve el identificador de la textura
//-----------------------------------------
unsigned int Texture::getTexture() {

    return texture;

}

//-----------------------
// Destructor de la clase
//-----------------------
Texture::~Texture() {

    glDeleteTextures(1,&texture);

}

and Texture.h looks like this:


#ifndef TEXTURE_H
#define TEXTURE_H

#include <iostream>
#include <GL/glew.h>
#include <FreeImage.h>

class Texture {

public:

    void         initTexture(const char *textureFile);
    unsigned int getTexture();

    virtual ~Texture();

private:

    unsigned int  texture;

    unsigned char *loadTexture(const char *textureFile, unsigned int &w, unsigned int &h);

};

#endif /* TEXTURE_H */

Note: Once loaded, the images are used to create a Textures object, which looks like this:

struct Textures {
    unsigned int diffuse;
    unsigned int specular;
    unsigned int emissive;
    unsigned int normal;
    float        shininess;
};

This was also provided by our teacher.

How can I achieve this?

I tried calling a new thread when I load the Texture images but nothing was loaded.

1

There are 1 best solutions below

0
Erdal Küçük On

In order to use multiple threads, you'll need multiple contexts bound (make current) to a specific thread. Most of the OpenGL objects (textures are one of them) can be shared among different contexts.

In EGL you would use the following operations:

To create a (shared) context

EGLContext eglCreateContext(
    EGLDisplay display,
    EGLConfig config,
    EGLContext share_context,
    EGLint const * attrib_list
);

share_context

Specifies another EGL rendering context with which to share data, as defined by the client API corresponding to the contexts. Data is also shared with all other contexts with which share_context shares data. EGL_NO_CONTEXT indicates that no sharing is to take place.

To make a context current on a thread

EGLBoolean eglMakeCurrent(
    EGLDisplay display,
    EGLSurface draw,
    EGLSurface read,
    EGLContext context
);

After that you're free to create/load a texture in one thread/context and use it in another thread/context.

If you're not able to use multiple contexts, then load the image data (e.g. from disk) from another thread and then create a texture and upload the data in the thread, where the context is bound to.

In your case, that would mean, that you call the loadTexture function from another thread and leave the rest in the thread where the context is bound to.

Reference