Original Post
I've implemented a pBuffer (taken from ATI's example) to be able to render reflections and such. However, I have noticed I'm leaking memory (and quite a lot too).
I've narrowed it down, and it seems to come from the wglMakeContextCurrentARB functions. So I'm guessing I'm doing something wrong.
Here's my pbuffer class:
#include <windows.h>
#include "GL/glfw.h"
#include "GL/wglext.h"
#include "pbuffer.h"
#include "../rndrBase.h"
#define GL_CLAMP_TO_EDGE_EXT 0x812F
// handle, device context and render context for pbuffer buffer
HPBUFFERARB hPBuffer = NULL;
HDC hPBufferDC = NULL;
HGLRC hPBufferRC = NULL;
// variables to hold pbuffers dimensions
int pbufferWidth = 0;
int pbufferHeight = 0;
// texture object ID for binding pbuffer to a texture
GLuint pbufferTextureID = 0;
// allows us to foolproof the interface to prevent using the pbuffer before
// it is initialized
bool pbufferInitialized = false;
// pbuffer function prototypes
PFNWGLMAKECONTEXTCURRENTARBPROC wglMakeContextCurrentARB = NULL;
PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = NULL;
PFNWGLCREATEPBUFFERARBPROC wglCreatePbufferARB = NULL;
PFNWGLDESTROYPBUFFERARBPROC wglDestroyPbufferARB = NULL;
PFNWGLGETPBUFFERDCARBPROC wglGetPbufferDCARB = NULL;
PFNWGLRELEASEPBUFFERDCARBPROC wglReleasePbufferDCARB = NULL;
PFNWGLQUERYPBUFFERARBPROC wglQueryPbufferARB = NULL;
PFNWGLBINDTEXIMAGEARBPROC wglBindTexImageARB = NULL;
PFNWGLRELEASETEXIMAGEARBPROC wglReleaseTexImageARB = NULL;
PFNWGLSETPBUFFERATTRIBARBPROC wglSetPbufferAttribARB = NULL;
bool pbufferInit (int width, int height);
void pbufferEnable ();
void pbufferDisable ();
void pbufferBind (void);
void pbufferRelease (void);
void pbufferDestroy (void);
void printError(const char*)
{
}
bool pbufferInit (int width, int height)
{
// initialize extension entry points
wglMakeContextCurrentARB = (PFNWGLMAKECONTEXTCURRENTARBPROC)
wglGetProcAddress("wglMakeContextCurrentARB");
wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)
wglGetProcAddress("wglChoosePixelFormatARB");
wglCreatePbufferARB = (PFNWGLCREATEPBUFFERARBPROC)
wglGetProcAddress("wglCreatePbufferARB");
wglDestroyPbufferARB = (PFNWGLDESTROYPBUFFERARBPROC)
wglGetProcAddress("wglDestroyPbufferARB");
wglGetPbufferDCARB = (PFNWGLGETPBUFFERDCARBPROC)
wglGetProcAddress("wglGetPbufferDCARB");
wglReleasePbufferDCARB = (PFNWGLRELEASEPBUFFERDCARBPROC)
wglGetProcAddress("wglReleasePbufferDCARB");
wglQueryPbufferARB = (PFNWGLQUERYPBUFFERARBPROC)
wglGetProcAddress("wglQueryPbufferARB");
wglBindTexImageARB =(PFNWGLBINDTEXIMAGEARBPROC)wglGetProcAddress("wglBindTexImageARB");
wglReleaseTexImageARB = (PFNWGLRELEASETEXIMAGEARBPROC)
wglGetProcAddress("wglReleaseTexImageARB");
wglSetPbufferAttribARB = (PFNWGLSETPBUFFERATTRIBARBPROC)
wglGetProcAddress("wglSetPbufferAttribARB");
// do some error checking to make sure function pointers were initialized correctly
if (wglMakeContextCurrentARB == NULL)
{
printError ("Can't init wglMakeContextCurrentARB");
return(false);
}
if (wglChoosePixelFormatARB == NULL)
{
printError ("Can't init wglChoosePixelFormatARB");
return(false);
}
if (wglCreatePbufferARB == NULL)
{
printError ("Can't init wglCreatePbufferARB");
return(false);
}
if (wglDestroyPbufferARB == NULL)
{
printError ("Can't init wglDestroyPbufferARB");
return(false);
}
if (wglGetPbufferDCARB == NULL)
{
printError ("Can't init wglGetPbufferDCARB");
return(false);
}
if (wglReleasePbufferDCARB == NULL)
{
printError ("Can't init wglReleasePbufferDCARB");
return(false);
}
if (wglQueryPbufferARB == NULL)
{
printError ("Can't init wglQueryPbufferARB");
return(false);
}
if (wglBindTexImageARB == NULL)
{
printError ("Can't init wglBindTexImageATIX");
return(false);
}
if (wglReleaseTexImageARB == NULL)
{
printError ("Can't init wglReleaseTexImageATIX");
return(false);
}
if (wglSetPbufferAttribARB == NULL)
{
printError ("Can't init wglSetPbufferAttribATIX");
return(false);
}
// if the pbuffer is already initialized make sure the previous buffer
// is freed before allocating a new one.
if (pbufferInitialized)
{
pbufferDestroy();
}
// keep track of the pbuffer size incase we have to create a new one
// because of a display mode change.
pbufferWidth = width;
pbufferHeight = height;
// define the minimum pixel format requirements we will need for our pbuffer
// a pbuffer is just like a frame buffer, it can have a depth buffer associated
// with it and it can be double buffered.
int attr[] =
{
WGL_SUPPORT_OPENGL_ARB, TRUE, // pbuffer will be used with gl
WGL_DRAW_TO_PBUFFER_ARB, TRUE, // enable render to pbuffer
WGL_BIND_TO_TEXTURE_RGBA_ARB, TRUE, // pbuffer will be used as a texture
//WGL_RED_BITS_ARB, 8, // at least 8 bits for RED channel
//WGL_GREEN_BITS_ARB, 8, // at least 8 bits for GREEN channel
//WGL_BLUE_BITS_ARB, 8, // at least 8 bits for BLUE channel
//WGL_ALPHA_BITS_ARB, 8, // at least 8 bits for ALPHA channel
WGL_COLOR_BITS_ARB, 32,
WGL_DEPTH_BITS_ARB, 24, // at least 24 bits for depth buffer
WGL_DOUBLE_BUFFER_ARB, FALSE, // we don’t require double buffering
0 // zero terminates the list
};
// choose a pixel format that meets our minimum requirements
unsigned int count = 0;
int pixelFormat;
wglChoosePixelFormatARB(renderer->window.dc,(const int*)attr, NULL, 1,&pixelFormat,&count);
if(count == 0)
{
printError("P-buffer Error: Unable to find an acceptable pixel format");
return(false);
}
// set some pbuffer attributes so that we can use this pbuffer as a
// 2D RGBA texture target
int pAttrib[] =
{
WGL_TEXTURE_FORMAT_ARB, // our pbuffer will have texture format RGBA
WGL_TEXTURE_RGBA_ARB,
WGL_TEXTURE_TARGET_ARB, // of texture type GL_TEXTURE_2D
WGL_TEXTURE_2D_ARB,
0 // zero terminates the list
};
// allocate the pbuffer
hPBuffer = wglCreatePbufferARB(renderer->window.dc, pixelFormat, width, height, pAttrib);
hPBufferDC = wglGetPbufferDCARB(hPBuffer);
hPBufferRC = wglCreateContext(hPBufferDC);
if(!hPBuffer)
{
printError("P-buffer Error: Unable to create P-buffer");
return(false);
}
glShadeModel(GL_SMOOTH); // Enable Smooth Shading
glClearColor(0.0f, 0.1f, 0.0f, 1.f); // Black Background
glClearDepth(1.0f); // Depth Buffer Setup
glEnable(GL_DEPTH_TEST); // Enables Depth Testing
glDepthFunc(GL_LEQUAL); // The Type Of Depth Testing To Do
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really Nice Perspective Calculations
glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST); // Really Nice Perspective Calculations
// make a texture object for binding the pbuffer to
glGenTextures(1, &pbufferTextureID);
glBindTexture(GL_TEXTURE_2D, pbufferTextureID);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE_EXT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE_EXT);
//glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);//GL_CLAMP_TO_EDGE_EXT);
//glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);//GL_CLAMP_TO_EDGE_EXT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
pbufferInitialized = true;
return(true);
}
// ****************************************************************************
// pbufferEnable: change the current context such that we will now be writing
// to the pbuffer. also, resize viewport to size width by height.
// ****************************************************************************
void pbufferEnable ()
{
// make sure the pbuffer has been initialized
if (!(pbufferInitialized))
{
return;
}
// make sure we haven't lost our pbuffer due to a display mode change
int flag = 0;
wglQueryPbufferARB(hPBuffer, WGL_PBUFFER_LOST_ARB, &flag);
if (flag != 0)
{
return;
}
// set read/write context to pbuffer
wglMakeContextCurrentARB(hPBufferDC, hPBufferDC, hPBufferRC);
//wglMakeCurrent(hPBufferDC, hPBufferRC);
// draw & read the front buffer of pbuffer
glDrawBuffer(GL_FRONT);
glReadBuffer(GL_FRONT);
// resize view port. generally you'll want to set this to the
// size of your pbuffer so that you render to the entire pbuffer
// but there are cases where you might want to render to just a
// sub-region of the pbuffer.
glViewport(0.0, 0.0, pbufferWidth, pbufferHeight);
return;
}
// ****************************************************************************
// pbufferDisable: change the current context such that we will now be writing
// to the framebuffer again. also, resize viewport to size width by height.
// ****************************************************************************
void pbufferDisable ()
{
// make sure the pbuffer has been initialized
if (!(pbufferInitialized))
{
return;
}
// make sure we haven't lost our pbuffer due to a display mode change
int flag = 0;
wglQueryPbufferARB(hPBuffer, WGL_PBUFFER_LOST_ARB, &flag);
if (flag != 0)
{
return;
}
// set read/write context back to gl device
wglMakeContextCurrentARB(renderer->window.dc, renderer->window.dc, renderer->window.rc);
//wglMakeCurrent(renderer->window.dc, renderer->window.rc);
// draw to the back buffer of frame buffer
// read from the front buffer of the frame buffer
glDrawBuffer(GL_BACK);
glReadBuffer(GL_FRONT);
// reset the view port
glViewport(0.0, 0.0, renderer->window.width, renderer->window.height);
return;
}
// ****************************************************************************
// pbufferBind: bind the pbuffer to a texture. while the pbuffer is bound to a
// texture object, it is illegal to read or write to the pbuffer until it is
// released.
// ****************************************************************************
void pbufferBind (void)
{
// make sure the pbuffer has been initialized
if (!(pbufferInitialized))
{
return;
}
// make sure we haven't lost our pbuffer due to a display mode change
int flag = 0;
wglQueryPbufferARB(hPBuffer, WGL_PBUFFER_LOST_ARB, &flag);
if (flag != 0)
{
pbufferInit(pbufferWidth, pbufferHeight);
}
// bind a texture object that we will associate a pbuffer with
glBindTexture (GL_TEXTURE_2D, pbufferTextureID);
// bind pbuffer to the currently bound texture object
// while the pbuffer is bound to a texture it is illegal
// to read or write from the pbuffer until it is released
wglBindTexImageARB(hPBuffer, WGL_FRONT_LEFT_ARB);
return;
}
// ****************************************************************************
// pbufferRelease: release the pbuffer from the texture it was bound to. once
// the pbuffer is released you will be able to render to it again by calling
// pbufferEnable()
// ****************************************************************************
void pbufferRelease (void)
{
// make sure the pbuffer has been initialized
if (!(pbufferInitialized))
{
return;
}
// release the pbuffer so that it can be rendered to again
wglReleaseTexImageARB(hPBuffer, WGL_FRONT_LEFT_ARB);
return;
}
// ****************************************************************************
// pbufferDestroy: free all resources associated with the pbuffer
// ****************************************************************************
void pbufferDestroy (void)
{
glDeleteTextures(1, &pbufferTextureID);
// make sure the pbuffer has been initialized
if (!(pbufferInitialized))
{
return;
}
if (! wglReleaseTexImageARB(hPBuffer, WGL_FRONT_LEFT_ARB))
int i=5;
if (! wglDeleteContext(hPBufferRC))
int i=5;
if (! wglReleasePbufferDCARB(hPBuffer, hPBufferDC))
int i=5;
if (! wglDestroyPbufferARB(hPBuffer))
int i=5;
pbufferInitialized = false;
return;
}
and how I use it:
#include "shdrCubemap.h"
#include "GL/glfw.h"
#include "pbuffer.h"
VALUE_ID Cubemap_Shader::CUBEMAP_ID;
TextureInfo *tmp;
void Cubemap_Shader::Enter( TextureInfo *texInfo )
{
texInfo->isVisible = false;
tmp = texInfo;
pbufferEnable ();
glShadeModel(GL_SMOOTH); // Enable Smooth Shading
glClearColor(0.f, 0.f, 0.2f, 1.f); // Black Background
glClearDepth(1.0f); // Depth Buffer Setup
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Screen And Depth Buffer
glEnable(GL_DEPTH_TEST); // Enables Depth Testing
glDepthFunc(GL_LEQUAL); // The Type Of Depth Testing To Do
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really Nice Perspective Calculations
glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST); // Really Nice Perspective Calculations
glEnable(GL_POLYGON_SMOOTH);
glMatrixMode(GL_MODELVIEW);
float matrix[] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1};
glPushMatrix();
glLoadMatrixf(&matrix[0]);
// Cliplane on the reflector
double equation[] = {0., 0., 1., 0.};
glClipPlane(GL_CLIP_PLANE0, &equation[0]);
glEnable(GL_CLIP_PLANE0);
// Call main rendering function
renderer->RenderGroup(SG_MAIN);
renderer->RenderGroup(SG_TRANSPARENT);
glDisable(GL_CLIP_PLANE0);
glPopMatrix();
if (!propMap->AddProperty("rendertotextureID", &texIDCubemap))
propMap->SetProperty("rendertotextureID", texIDCubemap);
}
void Cubemap_Shader::Exit( void )
{
pbufferDisable ();
tmp->isVisible = true;
}
void Cubemap_Shader::GetValue( VALUE_ID id, long *value )
{
if (id==CUBEMAP_ID)
*value = (long)texIDCubemap;
}
void Cubemap_Shader::Init( void )
{
bool okay = pbufferInit(1024,1024);
if (!okay)
exit(0);
texIDCubemap = pbufferTextureID;
}
void Cubemap_Shader::DeInit( void )
{
pbufferDestroy ();
}
Cubemap_Shader::~Cubemap_Shader( void )
{
DeInit();
}
Yes, I know it's not a cubemap, but I'm still working on it.
If you have any idea, I'll welcome it.
[edited by - rick_appleton on April 26, 2004 5:49:53 PM]