Render to texture with floating point pbuffers

OK, I’m hoping I can find a kind soul with some patience – what I am trying to do fits in with “Advanced GL”, even if I don’t

I am trying to do a generic ping-pong simulation. Let me describe how it would work on a CPU, and then move on to my GPU problems:

  1. Two arrays represent the current and previous state of the system. These are flipped at each stage.
  2. Four other arrays carry information about the environment – used in calculation of the current state. These arrays do not change.

This looked like a pretty straightforward thing to move to GPU/fragment program/OpenGL.

All of the arrays can be floating point pbuffers bound into textures with the render-to-texture extensions.

I feel at this point that I should point out that when I started this project I was not aware of the new wglChoosePixelFormatARB() function and the attribute list system. It

took me quite awhile to wrap my brain around the fact that pbuffers, floating point pbuffers, and texture pbuffers are three separate extensions, each of which seems to roll in several other extensions. But I’m up to speed there (at least far enough to load up all the extensions I need and get the extended functions running).

The problems that I KEEP running into are:

  1. All of the extensions are described as deltas from the spec, which makes them nearly impossible to read on their own. But I can work around that given enough time…
  2. I keep running into statements about values that are recognized by wglChoosePixelFormat (in either the Iattrib list OR the Fattrib list, which only adds to my confusion). An example would be:

<quote>
Accepted in the <piAttributes> array of wglGetPixelFormatAttribivARB and
wglGetPixelFormatAttribfvARB and in the <piAttribIList> and
<pfAttribFList> arrays of wglChoosePixelFormatARB:

    WGL_FLOAT_COMPONENTS_NV                         0x20B0
    WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_R_NV        0x20B1
    WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RG_NV       0x20B2
    WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGB_NV      0x20B3
    WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGBA_NV     0x20B4

</quote>

What causes me problems with this kind of statement is that I don’t know if those are keys or values. If they are keys, what values go with them? Should I just assume GL_TRUE/GL_FALSE? If they are values, what key do they belong with?

  1. I also keep running into comments about internal pixel formats, but not seeing anywhere to choose an internal pixel format (sorry if that sounds incredibly ignorant, but I’ve spent about 4 hours digging as hard as I can around web pages, nVidia developer pages, SGI pages, tutorials, etc, and I can’t seem to get this going).

I get the feeling that there is some kind of basic knowledge that somewhere along the way everybody just got, and nobody mentions anymore, and now there’s a gap that I can’t seem to get across.

Here is a dump of the section of code that is currently driving me nuts. The first four wglCreatePbufferARB calls “work”, in that they return an hpbuf. The second two calls

return 0. I do not actually know if the first four calls return the kind of buffer I want (3 component unconstrained 32bit floating point, for the first four calls, and 4 component for the second two calls).

Any help would be GREATLY appreciated. Any pointers to references that do not assume the reader has made their living as an OpenGL programmer for the last three years would also be greatly appreciated, as they would allow me to come up to speed without wasting anymore of your time.

I am trying to get this done in the next couple of days so I can get results for a feasibility study.

Thanks!
Mac

And now, for the code I claimed to have included… (whoops)

int nPixelFormat;
UINT NumFormats;
int fmtIattribs3[] ={
                    // "basic" pbuffer and bind-to-texture stuff
                    PFD_SUPPORT_OPENGL, GL_TRUE,
                    PFD_DEPTH_DONTCARE, GL_TRUE,
                    PFD_DOUBLEBUFFER_DONTCARE, GL_TRUE,
                    WGL_DRAW_TO_PBUFFER_ARB, GL_TRUE,
                    WGL_BIND_TO_TEXTURE_RGB_ARB, GL_TRUE,
                    PFD_TYPE_RGBA, GL_TRUE,

                    // These are here to support floating point pbuffers
                    WGL_TEXTURE_RECTANGLE_NV, GL_TRUE,
                    WGL_FLOAT_COMPONENTS_NV, GL_TRUE,
                    WGL_TEXTURE_FLOAT_RGB_NV, GL_TRUE,
                    WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGB_NV, GL_TRUE,
                    WGL_PIXEL_TYPE_ARB, GL_FLOAT_RGB32_NV,

                    // terminate the list
                    0,0}; // WRONG! still have to set depth, planes, etc...
FLOAT fmtFattribs[] = {0,0}; // WRONG! don't even know how many things belong here...
BOOL formatok = wglChoosePixelFormatARB(OriginalOpenGLDC, 
                                        fmtIattribs3,
                                        fmtFattribs,
                                        1,
                                        &nPixelFormat,
                                        &NumFormats);
// Create the pbuffer
// (wild hairy guess about how attrib lists are supposed to work...)
const int attriblist3[] ={WGL_TEXTURE_FORMAT_ARB, WGL_TEXTURE_RGB_ARB,
                          WGL_TEXTURE_TARGET_ARB, WGL_TEXTURE_RECTANGLE_NV, //WGL_TEXTURE_2D_ARB,
                          //WGL_TEXTURE_RECTANGLE_NV, GL_TRUE,
                          //WGL_FLOAT_COMPONENTS_NV, GL_TRUE,
                          //WGL_TEXTURE_FLOAT_RGB_NV, GL_TRUE,
                          //WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGB_NV, GL_TRUE,
                          0,0};

                          
// The field buffers and the A and B buffers are only 3 component buffers
hpbuf[BUF0] = wglCreatePbufferARB(OriginalOpenGLDC, nPixelFormat, 1024, 1024, attriblist3);
hpbuf[BUF1] = wglCreatePbufferARB(OriginalOpenGLDC, nPixelFormat, 1024, 1024, attriblist3);
hpbuf[ABUF] = wglCreatePbufferARB(OriginalOpenGLDC, nPixelFormat, 1024, 1024, attriblist3);
hpbuf[BBUF] = wglCreatePbufferARB(OriginalOpenGLDC, nPixelFormat, 1024, 1024, attriblist3);


// The EZFB/LR buffers are four component buffers
int fmtIattribs4[] ={
                    // "basic" pbuffer and bind-to-texture stuff
                    PFD_SUPPORT_OPENGL, GL_TRUE,
                    PFD_DEPTH_DONTCARE, GL_TRUE,
                    PFD_DOUBLEBUFFER_DONTCARE, GL_TRUE,
                    WGL_DRAW_TO_PBUFFER_ARB, GL_TRUE,
                    WGL_BIND_TO_TEXTURE_RGBA_ARB, GL_TRUE,
                    PFD_TYPE_RGBA, GL_TRUE,

                    // These are here to support floating point pbuffers
                    WGL_TEXTURE_RECTANGLE_NV, GL_TRUE,
                    WGL_FLOAT_COMPONENTS_NV, GL_TRUE,
                    WGL_TEXTURE_FLOAT_RGBA_NV, GL_TRUE,
                    WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGBA_NV, GL_TRUE,
                    WGL_PIXEL_TYPE_ARB, GL_FLOAT_RGBA32_NV,

                    // terminate the list
                    0,0}; // WRONG! still have to set depth, planes, etc...
formatok = wglChoosePixelFormatARB(OriginalOpenGLDC, 
                                        fmtIattribs4,
                                        fmtFattribs,
                                        1,
                                        &nPixelFormat,
                                        &NumFormats);
// Create the pbuffer
// (wild hairy guess about how attrib lists are supposed to work...)
const int attriblist4[] ={WGL_TEXTURE_FORMAT_ARB, WGL_TEXTURE_RGBA_ARB,
                          WGL_TEXTURE_TARGET_ARB, WGL_TEXTURE_RECTANGLE_NV, //WGL_TEXTURE_2D_ARB,
                          //WGL_TEXTURE_RECTANGLE_NV, GL_TRUE,
                          //WGL_FLOAT_COMPONENTS_NV, GL_TRUE,
                          //WGL_TEXTURE_FLOAT_RGBA_NV, GL_TRUE,
                          //WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGBA_NV, GL_TRUE,
                          0,0};
hpbuf[EZFB] = wglCreatePbufferARB(OriginalOpenGLDC, nPixelFormat, 1024, 1024, attriblist4);
hpbuf[EZLR] = wglCreatePbufferARB(OriginalOpenGLDC, nPixelFormat, 1024, 1024, attriblist4);

http://cvs1.nvidia.com/DEMOS/OpenGL/src/simple_float_pbuffer/float_pbuffer_win.h

Take a look at this class (specifically the create() function), it shows the basic steps needed to create a simple 32 bit floating point pbuffer.

Originally posted by jra101:
[b] http://cvs1.nvidia.com/DEMOS/OpenGL/src/simple_float_pbuffer/float_pbuffer_win.h

Take a look at this class (specifically the create() function), it shows the basic steps needed to create a simple 32 bit floating point pbuffer. [/b]

Thanks jra101. I see some stuff that looks like it might do the trick (I’ll have to wait 'til lunch to find out). I tried looking this stuff up in the nVidia demos, but was having difficulty wading through all the extra “stuff”.

On a related topic – can I make a float32 3 component texture with TexImage2D, or do I have to make a float pbuffer, bind to texture, and glDrawPixels? I am currently using the glDrawPixels approach, but I didn’t know if that was needlessly complicated. It doesn’t matter a great deal, as it is only done during startup, but I thought it might be confusing the resource management slightly.

Thanks again. I’ll try it out.
Mac

Yes, you can definitely create a float32 3 component texture, something like this:

GLuint fptexture;
glGenTextures(1, &fptexture);
glBindTexture(GL_TEXTURE_RECTANGLE_NV, fptexture);
glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_RECTANGLE_NV, 0, GL_FLOAT_RGB32_NV, width, height, 0, GL_RGB, GL_FLOAT, NULL);

[This message has been edited by jra101 (edited 06-09-2003).]

Originally posted by jra101:
Yes, you can definitely create a float32 3 component texture, something like this:

Once again, thank you! That will solve four of my six texture problems, since they are static data and won’t need the bind-to-texture functionality now.

For the remaining two, I am still having problems.

First, in possibly good news : I pulled up the code you mentioned, and found two things that were different from my code:

  1. Specification of the Red/Green/Blue/Alpha bit widths. Dunno why I didn’t think I needed those…
  2. Empty attribute list for the call to wglCreatePbufferARB. This surprised me. It seemed like the few code bits I’d been able to find specified attributes here. Of course, I wondered why I had to specify attributes to the pixel format AND to the create, but figured they were attributes for the buffer as a whole, instead of per-pixel.

All of my pbuffers get created, but now I can’t bind them to textures. I tried adding some of the attributes (BIND_TO_TEXTURE, a few others) to either the ChoosePixelFormat or the CreatePbuffer lists, but nothing seemed to help.

I think I now have a floating point pbuffer of the form I want, but I don’t seem to have a floating point pbuffer that can be bound to a texture. Considering that I need to ping-pong 1024x1024 3 component floating point textures/pbuffers a few million times to run my simulation, I really don’t want to have to fall back on ReadPixels/DrawPixels (or TexImage2d or whatever).

Any thoughts?

Just noticed something from your float texture code that might explain my problem. It’ll be tonight before I can find out for sure.

When you bind the texture object, you bind it as type GL_TEXTURE_RECTANGLE_NV, which is necessary for floating point textures, due to their additional complexity and not wanting to corrupt the fast square integral texture units. Anyway, I remembered the GL_TEXTURE_RECTANGLE_NV stuff when I was doing the attribute lists for pixel formats and pbuffers, but I bet I forgot to do it when I made the textures. So I bet I’ve got a perfectly good pbuffer, but the texture object is the wrong target type, so the binding can’t work.

I’ll give that a shot tonight.

Since I am in a bit of a hurry, I still wouldn’t turn down anyone else’s ideas on what I might be doing wrong

Thanks!
Mac

Mark Harris has written a class to setup pbuffers/rtt/fp. Haven’t used it myself but some people seem to like it.
http://www.cs.unc.edu/~harrism/misc/rendertexture.html

If you want to use the floating point pbuffer with the ARB_render_texture extension, add this to your pixel format attribute list (passed into wglChoosePixelFormatARB):

    WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGBA_NV,    GL_TRUE,

then add this to your pbuffer attribute list (passed into wglCreatePbufferARB):

    WGL_TEXTURE_FORMAT_ARB, WGL_TEXTURE_FLOAT_RGBA_NV,
    WGL_TEXTURE_TARGET_ARB, WGL_TEXTURE_RECTANGLE_NV,

In the hopes that my recent sleep deprivation will assist other researchers…

(some of these may seem obvious, but I hadn’t needed to use them before)

  1. Make a function for checking and decoding glGetError. Call it A LOT, preferably with a breakpoint inside it so that you can step out to find the code that caused the problem. But DO NOT call glGetError between glBegin and glEnd, or you will get an INVALID_OPERATION error from glGetError itself. (removal/optimization of this in release builds is left as an exercise to the reader)

  2. Float PBuffers can ONLY be manipulated by fragment programs. Make sure that you have a fragment program loaded, and that it is valid. Don’t forget to enable GL_FRAGMENT_PROGRAM_NV. If you generate any fragments (with glBegin/glEnd or glDrawPixels) and haven’t got all that, you get errors and the functions are ignored.

  3. Float PBuffers require the rectangle texture extension, and must be processed as GL_TEXTURE_RECTANGLE_NV. This has TWO effects:

3a. If you write your fragment program in Cg, make sure you use samplerRECT and texRECT() instead of sampler2D and tex2D.

3b. Rectangle texture coordinates are NOT normalized to the [0…1] range. Rectangle coordinates go from (0,0) to (width,height). Interestingly, that means there is one more column/row than there are texels, but I haven’t had time to really nail down the details of how to make sure you get your alignment perfect. Float PBuffers can only use GL_NEAREST anyway, so the only concern would be whether or not you got the last column/row right.

There were several other things I had to do, but I’m not sure now how many of them were paranoia, so I’ll keep them to myself. My float pbuffer code is running EXTREMELY slowly (my Athlon XP 1900 can perform exquivalent code in less than half the time than my GeForceFX 5200. That just seems wrong to me, so I figure I’m doing something hideously inefficient and/or redundant), so I don’t feel like I should be suggesting how to do things. But these were the last of my major errors that were keeping the system from working.

Many thanks to everyone who helped me, and I hope this helps other simulator programmers out there in some small way.

Mac

[This message has been edited by MacReiter (edited 06-11-2003).]