GL_EXT_framebuffer_multisample

Hi All,

We are collectiong a number of issues on this hardware using the GL_EXT_framebuffer_multisample extension. The first one is the following:

  1. If we create a multisample pixel format and don’t call glEnable(GL_MULTISAMPLE_ARB) the FSAA is active and cannot be deactivated even adding a glDisable(GL_MULTISAMPLE_ARB) call

We are following these instructions http://www.opengl.org/wiki/index.php/GL_EXT_framebuffer_multisample and using a RGB 24bit bitmap, not a RGBA 32bit one.

Why?

Thanks,

Alberto

Is this behaviour tied to one particular hardware, driver, or vendor ?

Hi ZbuffeR,

No, we and the customer are experiencing this issue on multiple nvidia cards. Do you think that posting the code would help to spot any discutible command sequence?

Thanks,

Alberto

EXT_framebuffer_multisample is not related to ARB_multisample. The former allows you to create multisampled framebuffer objects, the latter is legacy cruft that I recommend you don’t use at all.

As Don’t Disturb already said - this is very normal. glEnable/Disable(GL_MULTISAMPLE_ARB) doesn’t influence rendering to multisample renderbuffers in any way.

glEnable/Disable(GL_MULTISAMPLE_ARB) only enables multisampling on 0 framebuffer if you have created OpenGL context with multisampling (GL/WGL/GLX_ARB_multisample extension).

Guys, you’re right. The truth is we have problems in both areas.

Lets start with FSAA. We use this code to get a multisample pixel format. As far as I know you need to call glEnable/Disable(GL_MULTISAMPLE_ARB) to activate deactivate it, why we always see FSAA even after calling glDisable(GL_MULTISAMPLE_ARB) on NVidia geForce 8400???


	    if (IsExtensionSupported(new string[] {"GL_ARB_multisample", "GLX_ARB_multisample", "WGL_ARB_multisample"}) == false)
                
                return 0;

            int[] iAttributes = new int []
                                    {
                                        WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
                                        WGL_DOUBLE_BUFFER_ARB,  GL_TRUE,
                                        WGL_ACCELERATION_ARB,   WGL_FULL_ACCELERATION_ARB,
                                        WGL_COLOR_BITS_ARB,     24,
                                        WGL_ALPHA_BITS_ARB,     8,
                                        WGL_DEPTH_BITS_ARB,     24,
                                        WGL_STENCIL_BITS_ARB,   0,
                                        WGL_SAMPLE_BUFFERS_ARB, GL_TRUE,
                                        WGL_SAMPLES_ARB,        0,
                                        0, 0
                                    };

            for (samples = 16; samples > 0; samples /= 2)
            {

                iAttributes[17] = samples;

                int pixelFormat;
                uint numFormats;
                float[] fAttributes = new float[2];

                bool bStatus = ChoosePixelFormatARB(testHdc, iAttributes, fAttributes, 1, out pixelFormat, out numFormats);

                if (bStatus && numFormats > 0)
                {
                    return pixelFormat;
                }

            }

            return 0;

There is possibility that you have this setting forcefully enabled in driver settings.

No, just checked. I currently see:

Antialiasing - Gamma correction = Off
Antialiasing - Mode = Application controlled
Antialiasing - Setting = Application controlled
Antialiasing - Transpaarency = Off

I also downloaded another sample app for antialiasing and works like ours if you call glDisable(GL_MULTISAMPLE_ARB): you still see some sort of antialiasing on the OpenGL viewport. This sample app also support CSAA (GL_NV_multisample_coverage) and disabling this one we get a standard jagged viewport. Should we prefer this AA on NVidia cards instead of the GL_ARB_multisample?

Thanks,

Alberto

P.S.: Even the NVidia driver is updated to the latest version and we work on Windows Vista

The second issue is a problem (overlapped copy of a different area of the viewport) on getting a bitmap from the MSAA pixel format. Here is the code, do you see something strange? On the ATI hardware this works perfectly…

   	uint fb = glGenFramebuffersEXT();
        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb);

        cb = glGenRenderbuffersEXT();
        glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, cb);
        glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGB, width, height);

        db = glGenRenderbuffersEXT();
        glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, db);
        glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, width, height);

        glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, cb);
        glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, db);

        int status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);

        ReportFboStatus();

        if (isFsaaAvailable && GL_EXT_framebuffer_multisample)
        {

   			uint fb1 = glGenFramebuffersEXT();
            glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb1);

            cb1 = glGenRenderbuffersEXT();
            glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, cb1);
            glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGB, width, height);

            GL_RENderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples, GL_RGB8, width, height);

            db1 = glGenRenderbuffersEXT();
            glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, db1);
            glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, width, height);

            GL_RENderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples, GL_DEPTH_COMPONENT24, width, height);

            glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, cb1);
            glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, db1);

            int status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);

            ReportFboStatus();

            //Bind the MS FBO
            glBindFramebufferEXT(gl.READ_FRAMEBUFFER_EXT, fb1);
            //Bind the standard FBO
            glBindFramebufferEXT(gl.DRAW_FRAMEBUFFER_EXT, fb);
            gl.BlitFramebufferEXT(0, 0, posterWidth, posterHeight, 0, 0, posterWidth, posterHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST);
            glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb);

        }

        DrawScene();

        glReadPixels(0, 0, width, height, GL_BGR, GL_UNSIGNED_BYTE, bitmapData.Scan0);

        glDeleteTexture(cb);
        glDeleteRenderbuffersEXT(db);

        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
        glDeleteFramebuffersEXT(fb);

        if (isFsaaAvailable && GL_EXT_framebuffer_multisample)
	{
            glDeleteTexture(colorBuf);
            glDeleteRenderbuffersEXT(depthBuf);

            glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
            glDeleteFramebuffersEXT(fb);
	}

Is really fb1 framebuffer created correctly? Does glCheckFramebufferStatusEXT returns GL_FRAMEBUFFER_COMPLETE_EXT ?
GL_EXT_framebuffer_multisample says that if

The value of RENDERBUFFER_SAMPLES_EXT is the same for all attached images

is false, then GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT error will be returned.

And you are attaching multisampled color renderbuffer and non-multisample depth renderbuffer to framebuffer.
Create depth renderbuffer with same samples as color renderbuffer.

Also - do you use glReadPixels when fb1 is active? Because this also is forbbiden. Quoting EXT_framebuffer_multisample spec:

"ReadPixels generates INVALID_OPERATION if READ_FRAMEBUFFER_BINDING (section 4.4) is non-zero, the read framebuffer is framebuffer complete, and the value of SAMPLE_BUFFERS for the read framebuffer is greater than zero.

Is really fb1 framebuffer created correctly? Does glCheckFramebufferStatusEXT returns GL_FRAMEBUFFER_COMPLETE_EXT ?
GL_EXT_framebuffer_multisample says that if

[quote]The value of RENDERBUFFER_SAMPLES_EXT is the same for all attached images

is false, then GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT error will be returned.[/QUOTE]Yes, both FBO return GL_FRAMEBUFFER_COMPLETE_EXT.

And you are attaching multisampled color renderbuffer and non-multisample depth renderbuffer to framebuffer.
Create depth renderbuffer with same samples as color renderbuffer.

How you can say this?

Also - do you use glReadPixels when fb1 is active? Because this also is forbbiden. Quoting EXT_framebuffer_multisample spec:

[quote]"ReadPixels generates INVALID_OPERATION if READ_FRAMEBUFFER_BINDING (section 4.4) is non-zero, the read framebuffer is framebuffer complete, and the value of SAMPLE_BUFFERS for the read framebuffer is greater than zero.
[/QUOTE]Should I destroy this before the glReadPixel()?

Thanks,

Alberto

How you can say this?

What exactly I say wrong there? EXT_framebuffer_multisample specification says that all attachments should have same samples. It is strange that you are getting fb_complete_ext. That is why I suggest you to try to create depth renderbuffer with same sample count.

Should I destroy this before the glReadPixel()?

If you don’t read pixels from multisampled fbo then it doesn’t matter. I’m just asking from which framebuffer are you reading pixels. Because you can not read them from multisampled fbo.

      GL_RenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples, GL_RGB8, width, height);

                      GL_RenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples, GL_DEPTH_COMPONENT24, width, height);

These two calls has the same samples value, it is a variable.

We need to read pixels to get an antialiased bitmap and do:

       //Bind the MS FBO
        glBindFramebufferEXT(gl.READ_FRAMEBUFFER_EXT, fb1);
        //Bind the standard FBO
        glBindFramebufferEXT(gl.DRAW_FRAMEBUFFER_EXT, fb);
        gl.BlitFramebufferEXT(0, 0, posterWidth, posterHeight, 0, 0, posterWidth, posterHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST);
        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb);

        DrawScene();

        gl.ReadPixels(0, 0, width, height, GL_BGR, GL_UNSIGNED_BYTE, bitmapData.Scan0);

What do you think? Should we destroy the ms FBO before the glReadPixel() call?

Thanks,

Alberto

Oh, sorry. now I see how you are creating renderbuffers. I missed some lines reading code in that small code box :slight_smile:
In this case you don’t need to call glRenderbufferStorageEXT before glRenderbufferStorageMultisampleEXT. Last one automatically creates correct framebuffer storage. I somehow saw only glRenderbufferStorageEXT call not the MultisampleEXT one.

What do you think? Should we destroy the ms FBO before the glReadPixel() call?

If you are reading pixels from non-multisampled fbo, then it doesn’t matter if you destroy multisampled fbo before or after. As long as correct fbo is bound when you are calling glReadPixels then everything should be fine.

Have you tried checking error value with glGetError function after every OpenGL call? I recommend using GLintercept which do it for you automatically.

I think the best solution would be to use CSAA for NVidia and MSAA for others.

I gave a look to NVidia developer site and I found only references to CSAA approach. I would also hope the code above to get an anti-aliased bitmap will work with CSAA instead of MSAA.

Thanks also for the hint on glRenderbufferStorageEXT()!

Alberto

Yes, as suspected while using CSAA on NVIDIA works perfectly, we cannot use the code above (http://www.opengl.org/wiki/index.php/GL_EXT_framebuffer_multisample) to get an AntiAliased bitmap.

Do you know why or any workaround?

Thanks,

Alberto

What’s CSAA?
Your code works fine on my 8400M GS. I can get antialised image with MSAA FBO -> blit -> noMSAA FBO -> readPixels with no problems.

What’s CSAA?

http://developer.nvidia.com/object/coverage-sampled-aa.html

Don’t you have a residual AntiAliasing even with glDisable(GL_MULTISAMPLE_EXT)?

Thanks,

Alberto

Sorry, my english is not so good - what does “residual antialiasing” means?

Here is test program with source code that will render triangle to simple renderbuffer, msaa renderbuffer and csaa renderbuffer. Then it will read image from each framebuffer and save to tga file. I’ve included also tga images in Release folder that was generated on my laptop with Geforce 8400M GS.

Download it here: http://www.box.net/shared/ol8rz1qg8p

Thanks martinism, I will study your program and let you know.

Sorry, my english is not so good - what does “residual antialiasing” means?

I was meaning that with MSAA on this geForce 8400 you can switch AA off once you created a MultiSample pixel format.