0

i'm working on a school project and I've come across an issue with my FBO.

game is rendered in 2 passes: 1) I render to the shadow map texture using an FBO. 2) I render scene normally to the default FBO.

Issue is, for some reason, binding the FBO when i do the first pass slows down my game by roughly 200+ fps, I really don't know what could be wrong with the FBO since it's as barebones as possible. If i were to render the shadow map without binding, so directly to the screen, it'd be 200 fps faster, so it's not an issue of rendering, it's an issue of binding the FBO I believe.

Anyways, here's the first pass function.

//renders to the depth buffer texture.
void firstPass()
{
    static GLuint shadowID = Resources::getInstance().shadowShader;

    shadowBuffer->bindForWriting();//make active frame buffer the shadow buffer
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glViewport(0, 0, shadowBuffer->TEXTURE_WIDTH, shadowBuffer->TEXTURE_HEIGHT);

    //render to the shadow map from the point of view of the sunlight.
    glUseProgram(shadowID);

    ... set some uniforms

    scene->render(shadowID);
    shadowBuffer->unBindForWriting();//set frame buffer to default
    glUseProgram(0);
}

And here is my FBO class in its entirety.

ShadowMapFBO()
{
    init();
}

void bindForWriting()
{
    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, FBO);
}

void unBindForWriting()
{
    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
}

void bindForReading(GLenum TextureUnit, GLuint texture)
{
    glActiveTexture(TextureUnit);
    glBindTexture(GL_TEXTURE_2D, texture);
}

void BindTexture(GLuint textureID, GLuint location)
{
    glUniform1i(textureID, location);
}

void unBindForReading()
{
    glBindTexture(GL_TEXTURE_2D, 0);
}

GLuint shadowTexture;

int TEXTURE_WIDTH = 2048;
int TEXTURE_HEIGHT = 2048;


GLuint FBO;

void init()
{
    glGenFramebuffers(1, &FBO);
    glBindFramebuffer(GL_FRAMEBUFFER, FBO);

    shadowTexture = Util::createTexture(TEXTURE_WIDTH, TEXTURE_HEIGHT, true);

    glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, shadowTexture, 0);

    glDrawBuffer(GL_NONE);
    glReadBuffer(GL_NONE);


    GLenum Status = glCheckFramebufferStatus(GL_FRAMEBUFFER);

    if (Status != GL_FRAMEBUFFER_COMPLETE)
        printf("FB error, status: 0x%x\n", Status);
    else
        printf("Shadow Buffer created successfully.\n");

    glBindFramebuffer(GL_FRAMEBUFFER, 0);
}

Here's how I create my depth buffer texture.

static GLuint createTexture(int width, int height)
    {
        GLuint textureId;
        glGenTextures(1, &textureId);
        glBindTexture(GL_TEXTURE_2D, textureId);


        glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);

        int i;
        i = glGetError();
        if (i != 0)
        {
            std::cout << "Error happened while loading the texture: " << i << std::endl;
        }
        glBindTexture(GL_TEXTURE_2D, 0);
        return textureId;
    }
  • 1
    What makes you think it's the binding of the framebuffer that's the issue? Have you profiled it? – user1118321 Feb 25 '14 at 06:55
  • well, when I still do the first pass, so i render the shadow map, when I do it to the screen without binding i get 200 fps, when i bind, so draw to text, i get -200fps, so I know it isn't the rendering that's slow, it's something else, but I don't know what. – user3349448 Feb 25 '14 at 15:11
  • -200fps compared to what? Changing the framebuffer is one of the slowest GL operations, so if it's taking 200fps off something that normally renders at 5000fps (with vsync off) then that might not be that strange. You need to establish the value either in percentage of total frame render time, or better yet, in absolute milliseconds. Consider using glBeginQuery/glEndQuery to determine the actual timing taken to do particular operations to narrow down your search for the performance issue. – Jherico Feb 25 '14 at 21:25
  • For one thing, stop clearing the color buffer after you bind your FBO. Your FBO clearly has no color buffer attachment, so that is just silly. Next, realize that without the FBO, your depth buffer almost certainly has a resolution ***less*** than 2048x2048; not many GL windows are that large. Last, you have not requested a specific bit depth for the depth texture. If you are concerned with performance, try `GL_DEPTH_COMPONENT16`, `GL_DEPTH_COMPONENT24` and `GL_DEPTH_COMPONENT32[F]` in that order. The lower bit-depth ones may be inadequate for shadow mapping, but will be quicker. – Andon M. Coleman Feb 25 '14 at 23:47
  • Following up on the last statement - you have not shown the implementation of `Util::createTexture (...)`, which needs to be creating a texture with an internal format `GL_DEPTH_COMPONET[16/24/32|F]` or an appropriate packed Depth+Stencil format. – Andon M. Coleman Feb 25 '14 at 23:50
  • Oh Andon I think you got it, I changed GL_DEPTH_COMPONENT to GL_DEPTH_COMPONENT16 and fps went up by roughly 200 fps, I will show you here just in case how I create my textures in case there is something else i'm doing incorrectly, thanks!! I edited my post. – user3349448 Feb 26 '14 at 04:47
  • Also, `GL_CLAMP` is not a valid texture repeat mode in core OpenGL 3.2+ or GL 3.1 without the `GL_ARB_compatibility` extension. It was never really hardware accelerated anyway, it was supposed to blend a special set of border texels with the edge of a texture for any texture coordinate that was out of the range [0,1]. Since `GL_CLAMP` was removed beginning with GL 3.1, you should use `GL_CLAMP_TO_EDGE` instead. `GL_CLAMP_TO_EDGE` was added to the API later on (GL 1.2), but if you have FBOs you definitely have access to that texture repeat mode ;) – Andon M. Coleman Feb 27 '14 at 17:26
  • I would also point out that you do not necessarily have to re-draw your shadow map every time you draw the scene. If the position of a light does not change and no objects in the light source's coverage area change between frames you can re-use the old shadow map. It can be worth implementing a system to determine whether or not to update the shadow map(s) because they often take the largest chunk of render-time in a real-world game. You can easily compute the amount of time taken to build the shadow map(s) each frame if you use OpenGL Timer Queries as Jherico suggested. – Andon M. Coleman Feb 27 '14 at 17:36
  • oh thanks!. Any idea how to accept an answer? I dont see the up/down arrow for your comments. currently i have a light that always rotates around and follows the player, this light also always looks at the player so the shadow map will need to be created every frame. Issue is, if the player moves, so will the light, and that will change the angle at which the shadows are drawn, easy fix would be to place the light way farther, but then I would get very poor depth accuracy and shadows would look really blocky, not sure how to fix that issue, but you've been really helpful! – user3349448 Feb 28 '14 at 02:30

0 Answers0