FBO, stencil buffers, and AA

Hi All,
Just thought I’d ask a few questions about the above…

Firstly, the FBO spec goes on and on about how you can attach stencil buffers… I’ve seen some posts on here saying you cant, but havent found a link or something to an nvidia or ati document about it?

I’ve tried it myself, and the sample code from the extension spec fails with invalid enum, as someone here had. I’m only asking because those were old posts, figured maybe newer drivers have fixed it?

I’ve even stepped through the nvidia gl dll with the VC disassembler, they dont even have if statements for stencil_index (or the other stencil options)… so it looks to me like the 77.77 & 78.01 drivers completely dont support it?? Just wanted some confirmation.

Finally, AA - whats the going method for having AA in your rendered textures? Doing post processing is all well and good, but since (as it seems to be) no hardware at the moment can render-to-texture with multisample, from what I gather we have 2 options:

supersample: either render a bloody massive image and scale down, or render slightly offset passes and blend them together.

render to back buffer then copy to texture: this way you get to use all the hardware AA stuff but incur a copy.

To me it seems like the second option is going to be much faster, supersampling is all well and good but its so 90’s :slight_smile: Seriously, if your framerate is like 45fps, you cant afford to render it at twice the res, or render it 3x and blend together. I think a 1280x1024 texture copy wouldnt incur more then say a 3fps cost… I’ve been doing copys of 128x128x32bpp images for creating blurred bloom textures, and that runs very very fast, barely noticable slowdown!

What do other people do to have AA in their render-to-textures? :slight_smile:

Thanks!

Originally posted by ChiefWiggum:
Finally, AA - whats the going method for having AA in your rendered textures? Doing post processing is all well and good, but since (as it seems to be) no hardware at the moment can render-to-texture with multisample, from what I gather we have 2 options:
Actually, the hardware can use multisampling when rendering to render targets, but there’s just no API for it with FBOs yet. It was one of the stuff that was deferred in the initial spec, but is being worked on by the ARB. Hopefully a future extension / core promotion should have multisampling included.

Yes, I’ve read about this stencil/fbo problem here before, and it seems that people have definitely been hitting a brick wall in this area. What I’d like to clarify is; is it just attaching a texture image to the stencil buffer that is problematic, or is even using a render buffer for it busted (i.e. no stencil at all while rendering to an fbo)?

If this is a case then it really should be on the top of the todo list for the driver authors. First vendor to do it gets a popsicle!

Does anyone have any authoritative info on where we stand here?

You’re kidding me, there IS hardware support for AA into a rendered texture? What the hell am I using OpenGL for then, surely directx has had support for this for ages then… I heard HL2’s hdr is going to support AA as well, if theyre doing it through directx, obviously DX would have the functionality :frowning:

As for the stencil problem, the sample code I tried is trying to attach a render buffer as a stencil buffer for the framebuffer, so yeah, that doesnt work at all. I wouldnt even dream of asking for a stencil texture!!

Good God, am I right in saying that FBO will only report “complete” and work on a 6800 with 78.01 drivers if you are binding a GL_TEXTURE_RECTANGLE as the color buffer??? I spent all day trying to get it to work with a GL_TEXTURE_2D (with and without depth buffers bound) to no avail, found some sample code that does everything like I do but it uses TEXTURE_RECTANGLE, I put TEXTURE_2D in there and it also fails with incomplete… I put TEXTURE_RECTANGLE in my program, and voila, it works…

I’m getting a bit sick of this new extension already! Granted, its nowhere near as bad as PBuffers were… I spent about 3 days getting them to be reliable with 2D and cubemap textures sigh

Why hasnt nvidia posted something somewhere saying OK we have FBO support but these things dont work: Stencil, TEXTURE_2D (and probably everything else :slight_smile: )… It’d save everyone so much hassle.

TEXTURE_2D with FBO absolutely should work.

Can you send me a copy of your modified sample code that reports incomplete when using TEXTURE_2D?

Originally posted by Jeff Russell:
[b]Yes, I’ve read about this stencil/fbo problem here before, and it seems that people have definitely been hitting a brick wall in this area. What I’d like to clarify is; is it just attaching a texture image to the stencil buffer that is problematic, or is even using a render buffer for it busted (i.e. no stencil at all while rendering to an fbo)?

If this is a case then it really should be on the top of the todo list for the driver authors. First vendor to do it gets a popsicle!

Does anyone have any authoritative info on where we stand here?[/b]
Stencil render buffers should work fine. I tested this on a GeForce 6800 GT running 78.01 drivers and glCheckFramebufferStatusEXT returned GL_FRAMEBUFFER_COMPLETE_EXT.

GLuint stencil;
glGenRenderbuffersEXT(1, &stencil);
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_STENCIL_INDEX8_EXT, 16, 16);

...
    
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, color, 0);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, stencil);

jra101: Heres the sample code, its just the code from http://openvidia.sourceforge.net/simpleFBO.c . When I run the code as it is on the site, I get complete FBO’s and it all works. If I replace GL_TEXTURE_RECTANGLE_NV’s with GL_TEXTURE_2D’s, it reports FBO incomplete!

As for stencil buffers - I dont know how on earth you’re getting them to work, because I’m using the same hardware and drivers, and the experience I and others on this forum have had simply point to the driver not supporting it at all? As I’ve said, i’ve stepped through the nvidia GL dll with the VC++ disassembler, and theres what must be a switch statement on the type you’re passing in, DEPTH_COMPONENT, RGB, RGBA and a few similar ones are in there, but the STENCIL_INDEX ones arent! So I cannot understand how you could be initializing a working stencil buffer? :slight_smile:

Thanks for any help though, becaues I would absolutely LOVE for them to work!

Oh, and what GL driver settings are you using? Somewhere either on this forum or on gamedev someone reported that when they had anisotropic filtering NOT set to “application defined” they got FBO’s returning incomplete, when they set it to that it worked. Maybe whatever settings you’re using enable you to turn TEXTURE_2D & STENCIL_INDEX on, and I cant? I’ve tried all AA modes, and anisotropic to off, user defined, and some of the smaller values for it.

  

#include <GL/glut.h>
#include <GL/glext.h>
#include <stdio.h>
#include <assert.h>

GLuint fb,depth_rb,tex;

#define CHECK_FRAMEBUFFER_STATUS() \
{\
 GLenum status; \
 status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); \
 fprintf(stderr, "%x
", status);\
 switch(status) { \
 case GL_FRAMEBUFFER_COMPLETE_EXT: \
   fprintf(stderr,"framebuffer complete!
");\
   break; \
 case GL_FRAMEBUFFER_UNSUPPORTED_EXT: \
   fprintf(stderr,"framebuffer GL_FRAMEBUFFER_UNSUPPORTED_EXT
");\
    /* you gotta choose different formats */ \
   assert(0); \
   break; \
 case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: \
   fprintf(stderr,"framebuffer INCOMPLETE_ATTACHMENT
");\
   break; \
 case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: \
   fprintf(stderr,"framebuffer FRAMEBUFFER_MISSING_ATTACHMENT
");\
   break; \
 case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: \
   fprintf(stderr,"framebuffer FRAMEBUFFER_DIMENSIONS
");\
   break; \
 case GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT: \
   fprintf(stderr,"framebuffer INCOMPLETE_DUPLICATE_ATTACHMENT
");\
   break; \
 case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: \
   fprintf(stderr,"framebuffer INCOMPLETE_FORMATS
");\
   break; \
 case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: \
   fprintf(stderr,"framebuffer INCOMPLETE_DRAW_BUFFER
");\
   break; \
 case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: \
   fprintf(stderr,"framebuffer INCOMPLETE_READ_BUFFER
");\
   break; \
 case GL_FRAMEBUFFER_BINDING_EXT: \
   fprintf(stderr,"framebuffer BINDING_EXT
");\
   break; \
/* 
 case GL_FRAMEBUFFER_STATUS_ERROR_EXT: \
   fprintf(stderr,"framebuffer STATUS_ERROR
");\
   break; \
*/ \
 default: \
   /* programming error; will fail on all hardware */ \
   assert(0); \
 }\
}

PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT = 0;
PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT = 0;
PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT = 0;
PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT = 0;

void InitFBO()
{
	glGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC) wglGetProcAddress("glGenFramebuffersEXT");
	glBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC) wglGetProcAddress("glBindFramebufferEXT");
	glCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) wglGetProcAddress("glCheckFramebufferStatusEXT");
	glFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) wglGetProcAddress("glFramebufferTexture2DEXT");
}

int imageWinWidth = 256;
int imageWinHeight = 256;

void reshape(int w, int h)
{
  glClearColor (0.0, 0.0, 0.0, 0.0);
  glViewport(0, 0, (GLsizei) w, (GLsizei) h);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();

  glFrustum(0.0, 1.0,  1.0, 0.0,   1.0,   100.0);
  gluLookAt(0.0,0.0,0.0,  0.0, 0.0,  -1.0,   0.0, 1.0, 0.0);

  glMatrixMode(GL_MODELVIEW);

  glLoadIdentity();
  glutPostRedisplay();
}

static GLenum errCode;
const GLubyte *errString;

void errcheck() {

  if ((errCode = glGetError()) != GL_NO_ERROR) {
    errString = gluErrorString(errCode);
    fprintf (stderr, "OpenGL Error: %s
", errString);
    exit(1);
  }

}


void myIdle(void)
{
  glutPostRedisplay();
}

void keyboard (unsigned char key, int x, int y)
{
   switch (key) {
      case 27:
         exit(0);
         break;
      default:
         break;
   }
}

void MouseFunc( int button, int state, int x, int y)
{
  switch(button) {
    case GLUT_LEFT_BUTTON :
      break;
    case GLUT_RIGHT_BUTTON :
      break;
  }
}


void render_redirect(void)
{

  //bind the FBO, and the associated texture.
  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb);

  // draw a scene.  the results are being 
  // written into the associated texture,'tex'
  glClearColor(0.0, 0.0, 1.0, 1.0);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  glColor4f( 1.0, 1.0, 1.0, 1.0);
  glLineWidth(5.0);
  glBegin(GL_LINES);
    glColor4f( 1.0, 1.0, 1.0, 1.0);
    glVertex3f( 0.0, 0.0, -1.0);
    glVertex3f( 1.0, 1.0, -1.0);
  glEnd();

  // 'unbind' the FBO. things will now be drawn to screen as usual
  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);


  glClearColor(0.0, 1.0, 0.0, 1.0);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  glColor3f(1.0, 1.0, 1.0); 
  glEnable(GL_TEXTURE_RECTANGLE_NV);
  glBindTexture(GL_TEXTURE_RECTANGLE_NV, tex);
  // draw the 'tex' texture containing the framebuffer rendered drawing.
  glBegin(GL_QUADS); 

    glTexCoord2f(0, 0);
    glVertex3f(0.0, 0.0, -1.0);

    glTexCoord2f(0, 256);
    glVertex3f(0.0, .5, -1.0);

    glTexCoord2f(256,256);
    glVertex3f(.5,.5, -1.0);

    glTexCoord2f(256,0);
    glVertex3f(.5, 0.0, -1.0);
  glEnd();
  glDisable(GL_TEXTURE_RECTANGLE_NV);

  glutSwapBuffers();
}

int main(int argc, char *argv[] )  {

   glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
   glutInitWindowSize(imageWinWidth, imageWinHeight);
   glutCreateWindow(argv[0]);

   InitFBO();

   //gen the frambuffer object (FBO), similar manner as  a texture
   glGenFramebuffersEXT(1, &fb);
   errcheck();
   // make a texture
   glGenTextures(1, &tex);              // texture

   //bind the framebuffer, fb, so operations will now occur on it
   glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb);

   // initialize texture that will store the framebuffer image
   glBindTexture(GL_TEXTURE_RECTANGLE_NV, tex);
   glTexImage2D(GL_TEXTURE_RECTANGLE_NV, 0, GL_RGBA, 256,256, 0,
                GL_RGBA, GL_UNSIGNED_BYTE,NULL);
   errcheck();

   // bind this texture to the current framebuffer obj. as 
   // color_attachement_0 
   glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
              GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_NV, tex, 0);
   errcheck();

   //see if everything is OK
   CHECK_FRAMEBUFFER_STATUS()

   //'unbind' the frambuffer object, so subsequent drawing ops are not
   // drawn into the FBO. 
   // '0' means "windowing system provided framebuffer
   glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);

   glutDisplayFunc(render_redirect);
   glutIdleFunc(myIdle);
   glutReshapeFunc(reshape);
   glutKeyboardFunc(keyboard);
   glutMouseFunc(MouseFunc);
   glutMainLoop();
   return 0;
}

My mistake, I wasn’t checking for OpenGL errors and when I did I noted my glRenderbufferStorageEXT call was causing an OpenGL error. Doesn’t look like this is supported yet.

With regards to the demo that breaks when using TEXTURE_2D, the problem is caused by mipmaps. The default GL_TEXTURE_MIN_FILTER for a 2D texture is GL_LINEAR_MIPMAP_NEAREST while the default for a RECT texture is GL_LINEAR (rectangles do not support mipmapping).

The demo doesn’t initialize the mipmap chain for the 2D texture which means the texture is incomplete. Change the GL_TEXTURE_MIN_FILTER to GL_LINEAR and glCheckFramebufferStatusEXT should return GL_FRAMEBUFFER_COMPLETE.

jra101: Yep youre right about the GL_TEXTURE_2D, surprised I missed it! I know I had tried changing filter modes with my program but by the time I tried the example I forgot!

Anyway, as for the stencil initialization you have, does your glGetError return GL_INVALID_ENUM when creating the stencil_index renderbuffer? Because thats the error I’ve been having, just want to confirm.

Oh and folks, I’ve tried simply copying the texture back from the frame buffer, and this really doesnt seem that slow. I’m timing it with QueryPerformanceCounter, and its taking on the order of 0.0001 seconds to copy a roughly 1024x768 texture out of the frame buffer. I think this is much better performance-wise then implementing your own supersampling!

Oh and folks, I’ve tried simply copying the texture back from the frame buffer, and this really doesnt seem that slow. I’m timing it with QueryPerformanceCounter, and its taking on the order of 0.0001 seconds to copy a roughly 1024x768 texture out of the frame buffer.

Should that be only an RGB texture, it would be almost 22GB/s read speed from FB. Almost 44GB/s combined bandwidth, without taking overhead into account.

Iff that would be true, I’d have to agree - that wouldn’t seem “too slow”. :slight_smile:

I think you’re not measuring what you think. Follow that by reading a pixel from the texture copied to, to make sure the copy is completed.

tamlin:

If i put a glFinish call in there, its 0.0005 seconds. I know it does sound high (as in insanely fast) but how else can I test it?

If I actually do read a pixel out of the texture (by that I assume you mean glGetTexImage2D), that’d force the driver to copy the texture back into main memory. If I just do what I’m doing now:

glFinish();
TimeCounter copytime;
glCopyTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB, v_x, v_y, v_w, v_h, 0);
glFinish();
copytime.Tick();

Then the GL driver can do the copy from video memory->video memory. At least that is my assumption?

I’ve put those 2 finish calls in, to ensure nothing else is going on around there…

Oh and that TimeCounter does all the QueryPerformanceCounter stuff internally, and it definitly works! Unless theres something else going on in QueryPerformanceCounter that I dont know about… I’d have to say this is all I can do to test it :slight_smile:

For those interested, I’ve started a thread about glCopyTexImage2D speeds here