简体   繁体   中英

OpenGL ES glTexImage2D optimization

My task is to show several pictures. I implemented it as a class to make several instances. Each instance represents a picture. It compiles shaders, set two triangles and loads picture data in constructor. The main program creates instances and then goes to loop to switch prigramid and call render() method for each instance.

while(true)
    for (uint g = 0; g < pictures.size(); g++){
        glUseProgram(pictures[g]->ProgramId);
        pictures[g]->render();
    }

It works well and shows the pictures but I do not like it. It could be done much better.

Here is partial code of the class

Picture::Picture(picPosition* pPosition, const char * fileName)
:BasePicture(pPosition)
{
    pos = glGetAttribLocation(ProgramId, "position");
    uv = glGetAttribLocation(ProgramId, "texture_vert");

    glGenBuffers(1, &vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);

    glGenBuffers(1, &uvbuffer);
    glBindBuffer(GL_ARRAY_BUFFER, uvbuffer);

    int n;
    textureData = stbi_load(fileName, &picWidth, &picHeight, &n, STBI_rgb_alpha);
    TextureID  = glGetUniformLocation(ProgramId, "myTextureSampler");
    glBindTexture(GL_TEXTURE_2D, TextureID);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glActiveTexture(GL_TEXTURE0);

    glDepthMask(GL_FALSE);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
    //calculating the vertex matrix using MVP calculated in parent class
    for (int i = 0; i < 6; i++)
        ModeledVerts.push_back(MVP * verts[i]);
    v = glm::value_ptr(ModeledVerts[0]);
}

Picture::~Picture()
{
    stbi_image_free(textureData);
    glDeleteBuffers(1, &vbo);
    glDeleteBuffers(1, &uvbuffer);
}

void Picture::render()
{
    glBufferData(GL_ARRAY_BUFFER, 96, v, GL_STATIC_DRAW);
    glVertexAttribPointer(pos, 4, GL_FLOAT, GL_FALSE, 0, (GLvoid*) 0);
    glEnableVertexAttribArray(pos);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);

    glBufferData(GL_ARRAY_BUFFER, sizeof(verticesUV), verticesUV, GL_STATIC_DRAW);
    glVertexAttribPointer(uv, 2, GL_FLOAT, GL_FALSE, 0, (GLvoid*) 0);
    glEnableVertexAttribArray(uv);
    glBindBuffer(GL_ARRAY_BUFFER, uvbuffer);

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, picWidth, picHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureData);

    glDrawArrays(GL_TRIANGLES, 0, 6);
}

I played a lot with the code to make render() function as light as possible but I cannot make it lighter then it is now.

The biggest problem is sending textureData every time (glTexImage2D). The data never gets changed. I tried to move it to constructor but in this case all picture objects show the same picture that was loaded latest. It looks like one instance overrides texture data uploaded before. I am looking for a way to load the picture data once in the constructor and not every time it renders. It looks like there is something in OpenGL API for that but I do not know it yet.

Another improvement could be for taking vertex data set up from render(). That data never changes. But it is not that significant as glTexImage2D call in render().

Could you point me to the OpenGL API to separate shader's data? Or show me what I am doing wrong...

You stated:

It works well and shows the pictures but I do not like it. It could be done much better.

From a design approach I think that this may help you.

Separate the functionality of opening, reading & parsing the image files for texture data from the actual texture struct or class. This would be a sample pseudo code:

struct Texture {
    unsigned int width;
    unsigned int height;
    bool         hasTransparency; 

    GLint id; // ID that is used by OpenGL to setActive, bind, and pass to shaders as either a uniform or sampler2D.
    std::string filenameAndPath; // Keep this filename associated with texture so you can prevent trying to reload the same file over and over.
    GLuchar*  data; // the actual color - pixel texture data. 
}

// This function will handle the opening and reading in of the texture data
// it would return back the ID value generated by OpenGL which will also be
// stored into the texture struct. The texture struct is returned by reference so that it can be populated with data.
GLuint loadTexture( const char* filenameAndPath, Texture& texture, /*loading parameters & flags*/ ) {
    // Check to see if file exists or is already loaded
    if ( fileanameAndPath already exists ) {
        // get the existing ID from the already loaded texture
        // and just return that. 
    } else {
        // Try to open the new file for reading.

        // parse the data for general purposes that will support
        // your application. You can simply use `stbi_load` as it is a fairly
        // decent third party library.

        // Check the internal formatting of how the data is stored
        // Compression, pixel orientation etc.

        // configure the data to your needs (color format),
        // (flipping the pixels either horizontally, vertically or both),

        // now copy the actual pixel data into your buffer.

        // close the file handle

        // save all the information into your struct

        // return the ID value that was generated by OpenGL
    }
}

The within your main engine code before the render loop you will want to load your texture(s) from file and then you can use this Texture object where needed. Finally in your render loop is where you would want to set the texture(s) to active and bind them to the render target and pass them off to your shaders. In some cases you might want to set them active & bind them before your render loop depending on the type of shader-technique you are implementing.

Answering my own question. The solution is to use atlas map. Software generates atlas that contains all pictures, upload it once (glTexImage2D) and use coordinates for each picture. That improves performance very significantly as glTexImage2D was called just once.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM