PDA

View Full Version : FBO and multisampling



Dragon89
01-25-2008, 03:31 AM
how do one do multisampling on a FBO?

CrazyButcher
01-25-2008, 03:41 AM
GL_EXT_framebuffer_multisample

although I am not sure how many cards support it (geforce8 for sure)

Dragon89
01-25-2008, 03:45 AM
my card supports "GL_EXT_framebuffer_multisample"... ive read the documentation but i dont rly understand how to use it...?

-NiCo-
01-25-2008, 06:13 AM
It's just like you create renderbuffers in GL_EXT_framebuffer_object (http://www.opengl.org/registry/specs/EXT/framebuffer_object.txt), but for mutisampling you use
glRenderbufferStorageMultisampleEXT(...)
instead of
glRenderbufferStorageEXT(...)

N.

Dragon89
01-25-2008, 06:25 AM
thats it? i dont have to render the fbo multiple times for each sample etc...?

Zengar
01-25-2008, 06:31 AM
Yes, that's it :)

-NiCo-
01-25-2008, 06:36 AM
That was only the first half, the second half is that you have to put glEnable(GL_MULTISAMPLE_ARB) in your code before rendering ;)

N.

bobvodka
01-25-2008, 06:59 AM
hmmmm, I wonder if leaving that out would have the same effect as it does in D3D10 allowing you to use that stencil routing algo for translucancy...

noncopyable
01-25-2008, 01:36 PM
or http://http.download.nvidia.com/develope...tProcessing.zip (http://http.download.nvidia.com/developer/SDK/Individual_Samples/DEMOS/OpenGL/AntiAliasingWithPostProcessing.zip)

Chris Lux
01-26-2008, 04:27 PM
That was only the first half, the second half is that you have to put glEnable(GL_MULTISAMPLE_ARB) in your code before rendering ;)
...and the third half is that you can not use the multisample fbo for RTT directly. you have to use GL_framebuffer_blit to blit the contents from the multisample FBO to a normal FBO to use the attached textures...

for example, like this:


glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, _fbo_ms_draw_id);

// draw some stuff

// blit contents into textures
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, _fbo_ms_draw_id);
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, _fbo_id);
glBlitFramebufferEXT(0, 0, width, height,
0, 0, width, height,
GL_COLOR_BUFFER_BIT |
GL_DEPTH_BUFFER_BIT,
GL_NEAREST);

glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0);
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);


the first FBO is the multisample fbo with the multisample renderbuffers as color0 and depth attachment. the second fbo, target of the blit operation, is a nornal FBO with textures bound to color0 and depth attachment points.

tamlin
01-26-2008, 11:27 PM
Re. the "third 50%" :), wouldn't that actually make it both more straightforward and faster to just render to back FB and copy that to a texture (old-school "RTT")? I mean, a blit is a blit is a blit.

Chris Lux
01-27-2008, 03:44 AM
wouldn't that actually make it both more straightforward and faster to just render to back FB and copy that to a texture (old-school "RTT")? I mean, a blit is a blit is a blit.
yes this would still work, but with the multisample fbo you have a common way to do AA without the WGL, GLX, AGL platform stuff and without limiting yourself to the framebuffer dimensions and pixel types. this way multisample MRTs and multisample floating point buffers are also on the menu.

another advantage is, that you have the new nVidia coverage AA modes available which can not be used otherways.

Dragon89
01-28-2008, 01:57 AM
ok.. ive made a try.. but the result is all gray...



#ifndef _FBOMULTISAMPLE
#define _FBOMULTISAMPLE

#include "stdafx.h"

#include <boost/shared_ptr.hpp>

namespace nbase{
namespace graphics{
namespace opengl{

class ShadowMap;

class FBOMultiSample
{
friend class ShadowMap;

public:

inline FBOMultiSample(){}

inline FBOMultiSample(int _width, int _height, GLint type, bool mipmap = false)
{
Create(_width, _height, type, mipmap);
}

inline void Create(int _width, int _height, GLint type, bool mipmap = false)
{
mipmap_ = mipmap;
width_ = _width;
height_ = _height;
type_ = type;

// Create First normal FBO

glActiveTexture(GL_TEXTURE15);

glGenFramebuffersEXT(1, &amp;fbo);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);

glGenRenderbuffersEXT(1, &amp;depthBuffer);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depthBuffer);

glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, width_, height_);

glGenTextures(1, &amp;img);
glBindTexture(GL_TEXTURE_2D, img);

glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, img, 0);

glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depthBuffer);

glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);

GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);

glTexImage2D(GL_TEXTURE_2D, 0, type, _width, height_, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);

if (mipmap_)
{
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
glGenerateMipmapEXT(GL_TEXTURE_2D);
}
else
{
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}

glTexParameterf(GL_TEXTURE_2D, 0x84FE, 8); // ANISTROPY

// Create second multismaple FBO

glActiveTexture(GL_TEXTURE16);

glGenFramebuffersEXT(1, &amp;fbo);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, draw_fbo);

glGenRenderbuffersEXT(1, &amp;draw_depthBuffer);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, draw_depthBuffer);

glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFE R_EXT, 8, GL_DEPTH_COMPONENT, width_, height_);

glGenTextures(1, &amp;draw_img);
glBindTexture(GL_TEXTURE_2D, draw_img);

glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, draw_img, 0);

glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, draw_depthBuffer);

glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);



}

inline ~FBOMultiSample()
{
if (img != NULL)
glDeleteTextures(1, &amp;img);

if (!fbo != NULL)
glDeleteFramebuffersEXT(1, &amp;fbo);

if (!depthBuffer != NULL)
glDeleteRenderbuffersEXT(1, &amp;depthBuffer);
}


inline void Begin(GLenum texture)
{

glDisable(GL_ALPHA_TEST);
glDisable(GL_BLEND);

glActiveTexture(texture);
glBindTexture(GL_TEXTURE_2D, draw_img);

glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, draw_fbo);

glPushAttrib(GL_VIEWPORT_BIT);
glViewport(0,0,width_,height_);

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

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

inline void End()
{
if (mipmap_)
glGenerateMipmapEXT(GL_TEXTURE_2D);

glPopAttrib();

glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, draw_fbo);
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, fbo);
glBlitFramebufferEXT(0, 0, width_, height_,
0, 0, width_, height_,
GL_COLOR_BUFFER_BIT |
GL_DEPTH_BUFFER_BIT,
GL_NEAREST);

glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0);
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);

glEnable(GL_ALPHA_TEST);
glEnable(GL_BLEND);
}

inline void Use(GLenum texture)
{
glActiveTexture(texture);
glBindTexture(GL_TEXTURE_2D, img);
}

inline void Bind(GLenum texture)
{
glActiveTexture(texture);
glBindTexture(GL_TEXTURE_2D, img);

if (mipmap_)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
}

inline int GetHeight() { return height_; }
inline int GetWidth() { return width_; }
inline GLenum GetType() { return type_; }

private:
GLuint fbo;
GLuint depthBuffer;
GLuint img;

GLuint draw_fbo;
GLuint draw_depthBuffer;
GLuint draw_img;

int width_;
int height_;
GLint type_;

bool mipmap_;
};

typedef boost::shared_ptr<FBOMultiSample> FBOMultiSamplePtr;



}
}
}

#endif

Chris Lux
01-29-2008, 01:35 PM
I did not test your code, but some remarks:

- you create a texture object and bind it to the fbo. try initializing the texture before binding it (glTexImage, glTexParameteri...).
- you get the fbo status but never ask if everything went ok. like this for example:



unsigned fbo_status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
if (fbo_status != GL_FRAMEBUFFER_COMPLETE_EXT) {
std::cout << "error creating fbo, framebufferstatus is not complete:" << std::endl;
std::string error;

switch (fbo_status) {
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: error.assign("GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT");break;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: error.assign("GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT");break;
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: error.assign("GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT");break;
case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: error.assign("GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT");break;
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: error.assign("GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT");break;
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: error.assign("GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT");break;
case GL_FRAMEBUFFER_UNSUPPORTED_EXT: error.assign("GL_FRAMEBUFFER_UNSUPPORTED_EXT");break;
}
std::cout << "error: " << error << std::endl;
return (false);
}


- then you create the first fbo to the variable 'fbo' with the seconf one you overwrite the same variable, so you can not bind the first ever again...
- you create and bind a texture for the second fbo. a multisample fbo can not have texture attachments only plain renderbuffers...

i attach my testcode for this kind of thing, i hope this helps you:



bool init_geometry_fbo()
{
if (!init_geometry_textures())
return (false);

// create framebuffer object
glGenFramebuffersEXT(1, &amp;_fbo_id);
if (_fbo_id == 0) {
std::cout << "error generating fbo id" << std::endl;
return (false);
}
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, _fbo_id);

// attach depth texture
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, _fbo_depth_id, 0);

// attach color texture
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, _fbo_color_id, 0);

unsigned fbo_status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
if (fbo_status != GL_FRAMEBUFFER_COMPLETE_EXT) {
std::cout << "error creating fbo, framebufferstatus is not complete:" << std::endl;
std::string error;

switch (fbo_status) {
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: error.assign("GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT");break;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: error.assign("GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT");break;
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: error.assign("GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT");break;
case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: error.assign("GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT");break;
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: error.assign("GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT");break;
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: error.assign("GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT");break;
case GL_FRAMEBUFFER_UNSUPPORTED_EXT: error.assign("GL_FRAMEBUFFER_UNSUPPORTED_EXT");break;
}
std::cout << "error: " << error << std::endl;
return (false);
}

glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);

// create framebuffer object
glGenFramebuffersEXT(1, &amp;_fbo_ms_draw_id);

glGenRenderbuffersEXT(1, &amp;_fbo_ms_draw_depth_id);
glGenRenderbuffersEXT(1, &amp;_fbo_ms_draw_color_id);

if ( _fbo_ms_draw_id == 0
|| _fbo_ms_draw_depth_id == 0
|| _fbo_ms_draw_color_id == 0) {
std::cout << "error generating fbo ms draw id" << std::endl;
return (false);
}


glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, _fbo_ms_draw_depth_id);
//glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFE R_EXT, 4, GL_DEPTH_COMPONENT24, _gl_widget->width(), _gl_widget->height());
glRenderbufferStorageMultisampleCoverageNV(GL_REND ERBUFFER_EXT, 16, 8, GL_DEPTH_COMPONENT24, _gl_widget->width(), _gl_widget->height());

glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, _fbo_ms_draw_color_id);
//glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFE R_EXT, 4, GL_RGBA, _gl_widget->width(), _gl_widget->height());
glRenderbufferStorageMultisampleCoverageNV(GL_REND ERBUFFER_EXT, 16, 8, GL_RGBA, _gl_widget->width(), _gl_widget->height());

glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);

glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, _fbo_ms_draw_id);

glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
GL_DEPTH_ATTACHMENT_EXT,
GL_RENDERBUFFER_EXT, _fbo_ms_draw_depth_id);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
GL_COLOR_ATTACHMENT0_EXT,
GL_RENDERBUFFER_EXT, _fbo_ms_draw_color_id);

fbo_status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
if (fbo_status != GL_FRAMEBUFFER_COMPLETE_EXT) {
std::cout << "error creating fbo ms draw, framebufferstatus is not complete:" << std::endl;
std::string error;

switch (fbo_status) {
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: error.assign("GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT");break;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: error.assign("GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT");break;
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: error.assign("GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT");break;
case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: error.assign("GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT");break;
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: error.assign("GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT");break;
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: error.assign("GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT");break;
case GL_FRAMEBUFFER_UNSUPPORTED_EXT: error.assign("GL_FRAMEBUFFER_UNSUPPORTED_EXT");break;
}
std::cout << "error: " << error << std::endl;
return (false);
}

glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);

return (true);
}

void use()
{
// geometry pass
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, _fbo_ms_draw_id);
{
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);

render_geometry();
}
//glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);

// blit contents into textures
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, _fbo_ms_draw_id);
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, _fbo_id);
glBlitFramebufferEXT(0, 0, _gl_widget->width(), _gl_widget->height(),
0, 0, _gl_widget->width(), _gl_widget->height(),
GL_COLOR_BUFFER_BIT |
GL_DEPTH_BUFFER_BIT,
GL_NEAREST);

glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0);
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
}


but careful this code is ripped completely out of context and is from my testbed application.