PDA

View Full Version : Using WGL_ARB_pbuffer and glGetTexImage



Arkion
08-27-2004, 04:16 AM
Hello all!
I'm trying to render the scene to a 512x512 pbuffer texture, read it into system RAM using glGetTexImage and then write to a .TGA just to test things out.
The problem is that glGetTexImage seems to always return image that's completely black (ie. all zeros), as if nothing was actually rendered to the texture.

My pbuffer (it's size 512x512) is set up and running properly without errors, so the problem must lie in somewhere else.
I also registered the pbuffer texture via glGenTextures(1, &pbufferTexID) in pbuffer init function.

Below is the code I'm using. renderTarget is set when the screenshot key is pressed:


if(pbufferReady && renderTarget == RENDER_TARGET_PBUFFER)
{
int flag;

// Make sure it's not lost due to a display mode change
gle.wglQueryPbufferARB(hPbuffer, WGL_PBUFFER_LOST_ARB, &flag);

if(flag != 0)
{
gConsole.Printf("ERROR: lost pbuffer!\n");
renderTarget = RENDER_TARGET_FRAMEBUFFER;
}
else
{
// Store the current contexts
hOldDC = wglGetCurrentDC();
hOldRC = wglGetCurrentContext();
gle.wglMakeContextCurrentARB(hPbufferDC, hPbufferDC, hPbufferRC);

glDrawBuffer(GL_FRONT);
glReadBuffer(GL_FRONT);
glViewport(0, 0, 512, 512);
}
}

// Code to render the scene goes here
// ...

if(renderTarget == RENDER_TARGET_PBUFFER)
{
float startTime = gGame.GetTime();
byte *data = new byte[512*512*4];

glBindTexture(GL_TEXTURE_2D, pbufferTexID);
gle.wglBindTexImageARB(hPbuffer, WGL_FRONT_LEFT_ARB);

glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
// data is just all zeros <--
delete [] data;

gle.wglReleaseTexImageARB(hPbuffer, WGL_FRONT_LEFT_ARB);

// Restore framebuffer render target state
gle.wglMakeContextCurrentARB(hOldDC, hOldDC, hOldRC);
glDrawBuffer(GL_BACK);
glReadBuffer(GL_FRONT);
glViewport(0, 0, viewWidth, viewHeight);

renderTarget = RENDER_TARGET_FRAMEBUFFER;
}Is this the right way? Maybe I misunderstood how pbuffers work.
TIA.

V-man
08-27-2004, 09:31 PM
Before I answer this, I make no guarantee I have the right answer.

In the part following

if(renderTarget == RENDER_TARGET_PBUFFER)

the context should be the main context, not the p-buffer context. You should create the texture object in the main context or apply resource sharing.

I don't see why you are using glGetTexImage when you can use glReadPixels, and why you use a render able texture.

Another issue is that when you release the p-buffer, the contents become undefined. You have to re-render everything.

Arkion
08-28-2004, 02:36 AM
Ok, I tried what you suggested, but it still comes out as completely black image.

Also, what's the difference between wglMakeContextCurrentARB() and wglMakeCurrent()? Almost all examples seem to use the latter only, but it doesn't help me either.

I have ATI Radeon 9700 with newest drivers installed.

Here's the new code:


void Render()
{
if(renderTarget == RENDER_TARGET_SCREENSHOT)
EnablePBuffer(512, 512);

// Render the scene here
// ...

// Disable PBuffer after rendering to it once and set context back to framebuffer
if(renderTarget == RENDER_TARGET_SCREENSHOT)
{
byte *data = new byte[512*512*3];

DisablePBuffer(); // <-- set context back to the framebuffer
renderTarget = RENDER_TARGET_FRAMEBUFFER;

// Get the data
glBindTexture(GL_TEXTURE_2D, pbufferTexID);
gle.wglBindTexImageARB(hPbuffer, WGL_FRONT_LEFT_ARB);

glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, data);

// It's still all zeros
delete [] data;
gle.wglReleaseTexImageARB(hPbuffer, WGL_FRONT_LEFT_ARB);
}
}

void EnablePBuffer(int width, int height)
{
if(!pbufferReady)
return;

int flag = 0;
gle.wglQueryPbufferARB(hPbuffer, WGL_PBUFFER_LOST_ARB, &amp;flag);

if(flag != 0)
{
gConsole.Printf("ERROR: lost P-buffer!\n");
return;
}

// Store the window contexts
hOldDC = wglGetCurrentDC();
hOldRC = wglGetCurrentContext();

// set read/write context to pbuffer
wglMakeCurrent(hPbufferDC, hPbufferRC);

// draw & read the front buffer of pbuffer
glEnable(GL_TEXTURE_2D);
glEnable(GL_DEPTH_TEST);
glDrawBuffer(GL_FRONT);
glReadBuffer(GL_FRONT);
glViewport(0.0, 0.0, width, height);
}

void DisablePBuffer()
{
if(!pbufferReady)
return;

wglMakeCurrent(hOldDC, hOldRC);

glDrawBuffer(GL_BACK);
glReadBuffer(GL_FRONT);
glViewport(0, 0, viewWidth, viewHeight);
}

V-man
08-28-2004, 07:23 AM
I do pretty much the same thing, except I check what wglBindTexImageARB and wglReleaseTexImageARB return. Use GetLastError on them if they return error.

Are you able to apply the texture to a quad or something to see if it doesn't come out black?

Also, ATI drivers seem sensitive. Make sure all other parts of your code are error free. Make sure no other WGL function fail.

Arkion
08-29-2004, 05:32 AM
I figured out the reason for this behavior. The problem is that the textures used in the scene don't seem to be shared between the framebuffer rendering context and the pbuffer rendering context. Thus, only the framebuffer context can use them initially.

Using wglShareLists() fixes the problem. In MSDN OpenGL reference they only talk about display lists, but it's seems to share textures too.

V-man
08-29-2004, 01:19 PM
FYI, MSDN was outdated a long time ago.