3

I recently found that glDrawArrays allocating and releasing huge amounts of memory on every frame. I suspect that it's related to "Shaders compiled outside of initialization" issue reported by openGL profiler. That occurs on every frame! Should it be only once, and after shaders are compiled, disappear?

EDIT: I also double checked that my vertex are properly aligned. So I'm really confused what memory driver needs to allocate on every frame.

EDIT #2: I'm using VBO's and degenerated triangle strips to render sprites and . I'm passing geometry on every frame (GL_STREAM_DRAW).

enter image description here

EDIT #3:

I think I'm close to issue but still unable to solve it. Problem disappears if I pass same texture id value to shader (see source code comment). Somehow this issue is relate to fragment shader I think.

In my sprite batch I have list of sprites and I render them by texture id and FIFO queue.

Here's source code of my sprite batch class:

void spriteBatch::renderInRange(shader& prog, int start, int count){


int curTexture = textures[start];
int startFrom = start;

//Looping through all vertexes and rendering them by texture id's
for(int i=start;i<start+count;++i){
    if(textures[i] != curTexture || i == (start + count) -1){


        //Problem occurs after decommenting this line
       // prog.setUniform("texture", curTexture-1);

         prog.setUniform("texture", 0); // if I pass same texture id everything is OK

        int startVertex = startFrom * vertexesPerSprite;
        int cnt = ((i - startFrom) * vertexesPerSprite);

        //If last one has same texture we just adding it
        //to last render call

        if(i == (start + count) - 1 && textures[i] == curTexture)
            cnt = ((i + 1) - startFrom) * vertexesPerSprite;

        render(vbo, GL_TRIANGLE_STRIP, startVertex+1, cnt-1);

        //if last element has different texture
        //we need to render it separately

        if(i == (start + count) - 1 && textures[i] != curTexture){

         //   prog.setUniform("texture", textures[i]-1);
            render(vbo, GL_TRIANGLE_STRIP, (i * vertexesPerSprite) + 1, 5);
        }


        curTexture = textures[i];
        startFrom = i;
    }
}

}

inline GLint getUniformLocation(GLuint shaderID, const string& name) {
    GLint iLocation = glGetUniformLocation(shaderID, name.data());
    if(iLocation == -1){ // shader variable not found
        stringstream errorText;
        errorText << "Uniform \"" << name << " was not found!";
        throw logic_error(errorText.str());
    }
    return iLocation;
}

void shader::setUniform(const string& name, const matrix& value) {
    GLint location = getUniformLocation(this->programID, name.data());
    glUniformMatrix4fv(location, 1, GL_FALSE, &(value[0]));
}

void shader::setUniform(const string& name, int value) {
    GLint iLocation = getUniformLocation(this->programID, name.data());
            //GLenum error =  glGetError();
    glUniform1i(iLocation, value);
            //    error =  glGetError();
}

EDIT#4: I tried to profile app on IOS 6 and Iphone5 and allocations are much bigger. But methods are different in this case. I'm attaching new screenshot.

enter image description here

4

3 に答える 3

1

Issue is resolved by creating separate shader for each texture. It looks like bug in driver implementation that does happen on all IOS devices (I tested on IOS 5/6). However on higher iPhone models it's not that noticeable.

On iPhone4 performance hit was very significant from 60 FPS to 38!

于 2013-02-17T18:20:09.343 に答える
0

More code would help, but have you checked to see if the amount of memory involved is comparable to the amount of geometry you're updating? (although that would seem like a lot of geometry!) It looks like GL is holding your update until glDrawArrays, releasing it when it can be pulled into internal GL state.

If you can run the code in a MacOS app, the OpenGL Profiler tool may be able to further isolate the condition. (look in XCode documentation for more info, if you're not familiar with this tool). I'd also suggest looking at texture use, given the amount of memory involved.

The easiest thing to do might be to conditionally break on malloc() for a large allocation, note the address, and examine what's been loaded there.

于 2012-10-17T17:07:04.303 に答える
0

try to query the texture uniform just once (in initialization) and cache it. calling "glGetUniformLocation" too much in one frame will hammer the performance (depending on the sprite count).

于 2012-10-18T16:08:16.020 に答える