0

I have a Java application using OpenGL 3 through JOGL, and am trying to implement multi-sampling. I am following this tutorial, and so far, it seems to work, except for one line. When I call gl.glBackBuffer(GL3.GL_BACK), it generates a GL_INVALID_OPERATION error. If the program continues, it appears to draw to only one buffer, regardless of whether it is currently the front- or the back-buffer, and switches between the desired output and garbage data whenever it is redrawn.

According to the documentation:

GL_INVALID_OPERATION is generated if the default framebuffer is affected and none of the buffers indicated by buf exists.

GL_INVALID_OPERATION is generated if a framebuffer object is affected and buf is not equal to GL_NONE or GL_COLOR_ATTACHMENT$m$, where $m$ is a value between 0 and GL_MAX_COLOR_ATTACHMENTS.

I don't think that either of these is my problem, but one of them must be, because they are the only scenarios in which that error is generated.

Here is the relevant code:

@Override
public void init(GLAutoDrawable drawable) {

    GL3 gl = drawable.getGL().getGL3();
    int[] pointer = new int[1];

    sl = new ShaderLoader();
    sl.loadShader(gl);

    gl.glEnable(GL3.GL_DOUBLEBUFFER);
    gl.glEnable(GL3.GL_MULTISAMPLE);

    gl.glClearColor(1, 1, 1, 1);

    gl.glGenTextures(1, pointer, 0);
    multisampleTex = pointer[0];

    gl.glGenBuffers(1, pointer, 0);
    multisampleFbo = pointer[0];

    gl.glGenRenderbuffers(1, pointer, 0);
    multisampleRbo = pointer[0];

    main.init(drawable);

    gl.glGetIntegerv(GL3.GL_MAX_SAMPLES, pointer, 0);
    System.out.println(pointer[0]);

}

@Override
public void dispose(GLAutoDrawable drawable) {

    GL3 gl = drawable.getGL().getGL3();

    sl.destroy(gl);

}

@Override
public void display(GLAutoDrawable drawable) {

    // GL3 gl = new DebugGL3(drawable.getGL().getGL3());
    GL3 gl = drawable.getGL().getGL3();

    // drawable.setGL(gl);

    gl.glClear(GL3.GL_COLOR_BUFFER_BIT);

    gl.glBindFramebuffer(GL3.GL_FRAMEBUFFER, multisampleFbo);

    gl.glClear(GL3.GL_COLOR_BUFFER_BIT);

    main.render(drawable);

    gl.glBindFramebuffer(GL3.GL_DRAW_FRAMEBUFFER, GL3.GL_NONE);
    gl.glBindFramebuffer(GL3.GL_READ_FRAMEBUFFER, multisampleFbo);
    checkGLError();
    gl.glDrawBuffer(GL3.GL_BACK); // Throws GL_INVALID_OPERATION
    checkGLError("OpenGL error at glDrawBuffer: 0x%h%n");
    gl.glBlitFramebuffer(0, 0, width, height, 0, 0, width, height,
            GL3.GL_COLOR_BUFFER_BIT, GL3.GL_NEAREST);

    checkGLError();

}

@Override
public void reshape(GLAutoDrawable drawable, int x, int y, int width,
        int height) {

    GL3 gl = drawable.getGL().getGL3();

    this.width = width;
    this.height = height;

    updateMultisampleObjects(gl);

    gl.glViewport(0, 0, width, height);

    updatePMatrix();

}

private void updateMultisampleObjects(GL3 gl) {

    gl.glBindTexture(GL3.GL_TEXTURE_2D_MULTISAMPLE, multisampleTex);
    gl.glTexImage2DMultisample(GL3.GL_TEXTURE_2D_MULTISAMPLE,
            NUM_OF_SAMPLES, GL3.GL_RGBA8, width, height, true);

    gl.glBindFramebuffer(GL3.GL_FRAMEBUFFER, multisampleFbo);
    gl.glFramebufferTexture2D(GL3.GL_FRAMEBUFFER, GL3.GL_COLOR_ATTACHMENT0,
            GL3.GL_TEXTURE_2D_MULTISAMPLE, multisampleTex, 0);

    gl.glBindRenderbuffer(GL3.GL_RENDERBUFFER, multisampleRbo);
    gl.glRenderbufferStorageMultisample(GL3.GL_RENDERBUFFER,
            NUM_OF_SAMPLES, GL3.GL_DEPTH24_STENCIL8, width, height);
    gl.glFramebufferRenderbuffer(GL3.GL_FRAMEBUFFER,
            GL3.GL_DEPTH_STENCIL_ATTACHMENT, GL3.GL_RENDERBUFFER,
            multisampleRbo);

}

Also, I know I haven't done much cleanup, but that should not impact this problem.

EDIT: As requested, here is the code where the GLCanvas is created:

    glp = GLProfile.get("GL3");
    caps = new GLCapabilities(glp);
    caps.setDoubleBuffered(true);
    canvas = new GLCanvas(caps);
    canvas.setPreferredSize(new Dimension(800, 600));
    canvas.addGLEventListener(glListener);

    frame.add(canvas);
Community
  • 1
  • 1
Ontonator
  • 319
  • 3
  • 17
  • 1
    Is your default framebuffer double buffered? The symptoms suggest that you might be using a single buffered framebuffer. – Reto Koradi Dec 25 '14 at 21:43
  • Do you even have a double-buffered framebuffer? Note that `gl.glEnable(GL3.GL_DOUBLEBUFFER);` is not valid, and will not create one. – derhass Dec 25 '14 at 21:44
  • I'm not sure, but it appears to be double buffered, as the image toggles between the desired result and garbage data when it is updated. This means that there must be two buffers, one of which is being drawn to. Correct me if I'm wrong, I'm still learning. – Ontonator Dec 25 '14 at 21:48
  • I haven't used JOGL, but it seems to use something called a `GLCanvas`. Can you show the code where you create an instance of that? – Reto Koradi Dec 25 '14 at 22:25
  • @Ontonator: you probably need to use [setDoubleBuffered()](http://download.java.net/media/jogl/jogl-2.x-docs/javax/media/opengl/GLCapabilities.html#setDoubleBuffered(boolean)) to request a double-buffered context. A window showing "garbage" during update is a sure sign of _single_ buffered operation. – derhass Dec 25 '14 at 22:53
  • I added `caps.setDoubleBuffered(true);` to the canvas creation, but it hasn't seemed to help. – Ontonator Dec 25 '14 at 22:57
  • @Ontonator: Well, that is to be expected. If you suddenly switch from a single-buffered to double-buffered pixel format, without changing anything else, then all drawing will go into the back-buffer and the front-buffer will be undefined (garbage as you call it). You need to swap buffers at the end of your frame. It's even more important in modern window systems, drawing into the front-buffer alone is not adequate, they need the actual swap operation to occur before anything will show up on screen. – Andon M. Coleman Dec 26 '14 at 04:10
  • @AndonM.Coleman `setDoubleBuffered()` is applied to the `GLCapabilities` object before the `GLCanvas` and `GLContext` objects are created. Also, `canvas.swapBuffers()` is automatically called after the `display` method. – Ontonator Dec 26 '14 at 06:48

1 Answers1

0

I suspect that the error comes from an earlier call. At least there should be numerous errors, for example from the glBindFramebuffer() call immediately preceding the glDrawBuffer() call:

gl.glBindFramebuffer(GL3.GL_READ_FRAMEBUFFER, multisampleFbo);
checkGLError();
gl.glDrawBuffer(GL3.GL_BACK); // Throws GL_INVALID_OPERATION
checkGLError("OpenGL error at glDrawBuffer: 0x%h%n");

multisampleFbo is not a framebuffer object. It was created like this:

gl.glGenBuffers(1, pointer, 0);
multisampleFbo = pointer[0];

glGenBuffers() creates buffer objects, not framebuffer objects. To create an FBO, you need to call glGenFramebuffers():

gl.glGenFramebuffers(1, pointer, 0);
multisampleFbo = pointer[0];
Reto Koradi
  • 53,228
  • 8
  • 93
  • 133
  • It turns out that this was the problem. The error was to do with the lack of double buffering, but it did not have any impact on the symptoms that I was experiencing. – Ontonator Dec 27 '14 at 04:52