2
votes

I'm trying to use the accumulation buffer in OpenGL but for some reason the buffer does not appear to be filling. I constructed a simple test application, a 2D plane being rendered and nothing else. This renders fine. I then tried doing the simplest possible accumulation buffer operation I could think of, loading the rendered frame into the accumulation buffer, clearing the screen and then returning the accumulation buffer to the screen. When I do this it appears that the accumulation buffer contains no information at all, the image is simply the color the screen was cleared to, as though the accumulation buffer was never returned at all. I've also tried doing a more traditional motion blur setup, making multiple updates to the scene and buffer before returning it and got the same result.

This is the main loop for the simple test:

SDL_Event eve;
while (true)
{
    //Normal stuff
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

    //Accumulation///////////////////////
    glAccum(GL_LOAD, 1.0f);

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glAccum(GL_RETURN, 1.0f);
    //Accumulation///////////////////////

    SDL_GL_SwapWindow(window);

    SDL_PollEvent(&eve);
}

And this is the main loop for the motion blur test:

float x = 0.0f;

int step = 0;
int steps = 4;

SDL_Event eve;
while (true)
{
    //Test stuff
    x += 0.005f;

    GLfloat newVerts[] = {
        -0.5f + x,  0.5f,
        0.5f + x,  0.5f,
        0.5f + x, -0.5f,
        -0.5f + x, -0.5f,
    };

    glBufferData(GL_ARRAY_BUFFER, sizeof(newVerts), newVerts, GL_STATIC_DRAW);

    //Normal stuff
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

    //Accumulation///////////////////////
    if (step == 0)
    {
        glAccum(GL_LOAD, 1.0f / steps);
    }
    else
    {
        glAccum(GL_ACCUM, 1.0f / steps);
    }

    step++;

    if (step < steps)
    {
        continue;
    }

    step = 0;
    glAccum(GL_RETURN, 1.0f);
    //Accumulation///////////////////////

    SDL_GL_SwapWindow(window);

    SDL_PollEvent(&eve);
}

This is the full application source (it's only about 100 lines, I'm including it just incase something is wrong with my glEnable or SDL_GL_SetAttribute calls):

#include "tools.h"

static string vertexSource = getFile("D:/test.vsh");
static string fragmentSource = getFile("D:/test.fsh");

int main(int argc, char *argv[])
{
    //SDL///////////////////////////////////////////////
    SDL_Init(SDL_INIT_EVERYTHING);

    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 5);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);

    SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
    SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
    SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
    SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);

    SDL_GL_SetAttribute(SDL_GL_ACCUM_RED_SIZE, 8);
    SDL_GL_SetAttribute(SDL_GL_ACCUM_GREEN_SIZE, 8);
    SDL_GL_SetAttribute(SDL_GL_ACCUM_BLUE_SIZE, 8);
    SDL_GL_SetAttribute(SDL_GL_ACCUM_ALPHA_SIZE, 8);

    SDL_Window *window = SDL_CreateWindow("Test", 50, 50, 1600, 900, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);

    SDL_GLContext context = SDL_GL_CreateContext(window);

    //GLEW///////////////////////////////////////////////
    glewExperimental = GL_TRUE;
    GLint result = glewInit();

    if (result != GLEW_OK)
    {
        cout << glewGetErrorString(result) << "\n";
        cout << "GLEW initialization failed.\n";
    }

    //OpenGL///////////////////////////////////////////////
    glEnable(GL_DEPTH);
    glDepthFunc(GL_LEQUAL);
    glEnable(GL_DEPTH_TEST);

    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    glClearColor(1.0f, 1.0f, 0.0f, 1.0f);
    glClearDepth(1.0f);

    //Object///////////////////////////////////////////

    //Vertex Array
    GLuint vao;
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);

    //Vertex Buffer
    GLuint vbo;
    glGenBuffers(1, &vbo);

    GLfloat vertices[] = {
        -0.5f,  0.5f,
        0.5f,  0.5f,
        0.5f, -0.5f,
        -0.5f, -0.5f,
    };

    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    //Element Buffer
    GLuint ebo;
    glGenBuffers(1, &ebo);

    GLuint elements[] = {
        0, 1, 2,
        2, 3, 0
    };

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elements), elements, GL_STATIC_DRAW);

    //Shader
    GLuint shaderProgram = createShader(vertexSource, fragmentSource);
    glUseProgram(shaderProgram);

    GLint posAttrib = glGetAttribLocation(shaderProgram, "position");
    glEnableVertexAttribArray(posAttrib);
    glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 0, 0);

    //Loop///////////////////////////////////////////////
    float x = 0.0f;

    int step = 0;
    int steps = 4;

    SDL_Event eve;
    while (true)
    {
        //Test stuff
        x += 0.005f;

        GLfloat newVerts[] = {
            -0.5f + x,  0.5f,
            0.5f + x,  0.5f,
            0.5f + x, -0.5f,
            -0.5f + x, -0.5f,
        };

        glBufferData(GL_ARRAY_BUFFER, sizeof(newVerts), newVerts, GL_STATIC_DRAW);

        //Normal stuff
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

        //Accumulation///////////////////////
        if (step == 0)
        {
            glAccum(GL_LOAD, 1.0f / steps);
        }
        else
        {
            glAccum(GL_ACCUM, 1.0f / steps);
        }

        step++;

        if (step < steps)
        {
            continue;
        }

        step = 0;
        glAccum(GL_RETURN, 1.0f);
        //Accumulation///////////////////////

        SDL_GL_SwapWindow(window);

        SDL_PollEvent(&eve);
    }
}

I'm using GLEW to get access to the OpenGL calls and I'm using SDL for context creation and window management.

General specifications of the platform I'm running this on:

  • OpenGL 4.5 (also tried with 4.3 and 3.3, no difference).
  • Windows 10 64 bit
  • AMD FX-9590 @ 4.7 GHz
  • NVIDIA GTX 970 SC
  • ASUS Sabertooth 990FX
  • 16GB DDR3 RAM
1

1 Answers

3
votes
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^

Removed functionality (like accumulation buffers) won't work in a Core context.

OpenGL 3.2 Core spec, appendix E, page 329 & 333:

E.2 Deprecated and Removed Features

...

Functions which have been removed will generate an INVALID_OPERATION error if called in the core profile or in a forward-compatible context.

...

E.2.2 Removed Features

...

Accumulation buffers - ClearAccum, and ACCUM_BUFFER_BIT is not valid as a bit in the argument to Clear (section 4.2.3); Accum; the ACCUM_*_-BITS framebuffer state describing the size of accumulation buffer components; and all associated state.

Window system-binding APIs such as GLX and WGL may choose to either not expose window configs containing accumulation buffers, or to ignore accumulation buffers when the default framebuffer bound to a GL context contains them.