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!
");
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.
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, &flag);
if(flag != 0)
{
gConsole.Printf("ERROR: lost P-buffer!
");
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);
}
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.
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.