PBuffer/RTT Vrt Prog - Vtx Array weirdness (ATI and NVidia)

yo list,

Ive recently added pbuffer support to my engine and am having an issue.

I use an arb vertex program environment for the entire engine, never going into fixed function vertex processing.

On ATI 9500Pro (Catalyst3.9) / WinXP everything works as expected.
I think everything is fine on GGGfx5200Ultra (Forceware5216) as well.

The problem is with my Geforce4 G0 420 / Forceware 5216 (with hacked INF files to get it on my vaio laptop). Im 95% sure its not the hacked INF’s since everything else works fine.

The problem is this: (im guessing some kind of sync issue)

When I RTT(RenderToTexture) with a clear and a couple of fixed func immediate primitives and then bind it as a texture inside the main buffer and draw stuff with that texture, everything works as expected. If I instead use a vertex program and draw arrays with state changes into the RTT, upon return to the main rendering context, the pbuffer seems ok, but I get undefined results in the main buffer (like some of the geom targeted at the pbuffer shows up in the main buffer, matrices are messed up in the main buffer, etc…).

Also, why is clearing in pbuffers slow on my geforce 4 go compared to drawing a full screen quad?

here is some of my rendering code if it helps.

FYI a GfxTargetW32GL class encapsulates an on screen buffer and a pbuffer, as they have similar interfaces inside my engine.

////////////////////////////////////////////
lower level context begin/end blocks

void CGfxTargetW32GL::BeginFrame( void )
{
glFinish();

////////////////////////////////
// Is this a PBuffer ?
if( mhPBRC )
{
mDCStack.push( wglGetCurrentDC() );
mGLRCStack.push( wglGetCurrentContext() );

  CGfxEnv::PushContext( this );

  wglMakeCurrent( mhDC, mhGLRC );

  GL_ERRORCHECK();
  glViewport( 0, 0, miW, miH );
  glDrawBuffer( GL_FRONT );	
  glReadBuffer( GL_FRONT );

#if 1

  glDisable( GL_VERTEX_PROGRAM_ARB );
  glDisable( GL_CULL_FACE );
  glShadeModel( GL_FLAT );

  glMatrixMode( GL_PROJECTION );
  glLoadIdentity();
  gluOrtho2D( 0, miW, 0, miH );
  //glOrtho( 0, miW, 0, miH, -1.0, 1.0 );
  //glFrustum( 0.0, 1.0, 0.0, 1.0, 1.0, 1000.0 );
  //gluPerspective( 45.0, 1.0, 0.0, 1000.0 );

  static f32 frot = 0.0f;

  glMatrixMode( GL_MODELVIEW );
  glLoadIdentity();

  glClearColor( 0.0f, 0.0f, 0.2f, 1.0f );
  glDepthRange( 0.0, 1.0 );
  glClearDepth( 1.0 );
  glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

  glColor4f( 1.0f, 1.0f, 1.0f, 1.0f );

  glStencilFunc( GL_ALWAYS, 0.0f, 0 );
  glAlphaFunc( GL_ALWAYS, 0.0f );
  glDepthFunc( GL_ALWAYS );
  glDepthMask( GL_TRUE );
  glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );

  F32 fClearDepth = 0.5f;
  F32 fV = 100.0f;
  for( int iv=0; iv<32; iv++ )
  {
  	glBegin( GL_LINES );
  		glVertex3f( -fV, -fV, fClearDepth );
  		glVertex3f( fV, fV, fClearDepth );
  		glVertex3f( -fV, fV, fClearDepth );
  		glVertex3f( fV, -fV, fClearDepth );
  	glEnd();
  	glRotatef( frot, 0.0f, 0.0f, frot );
  	frot += 0.001f;
  }

  //		glBegin( GL_QUADS );

// glVertex3f( 0, 0, fClearDepth );
// glVertex3f( miW, 0, fClearDepth );
// glVertex3f( miW, miH, fClearDepth );
// glVertex3f( 0, miH, fClearDepth );
// glEnd();

  //glFinish();

#else

  glClearColor( 1.0f, 0.0f, 1.0f, 1.0f );
  glClearDepth( 1.0f );
  glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

#endif

  GL_ERRORCHECK();

}
else // Window
{
int inumsubbuf = GetNumSubBuffers();

for( int ib=0; ib<inumsubbuf; ib++ )
{
    CGfxBuffer *pBUF = GetSubBuffer( ib );
    pBUF->Draw();
}

}
////////////////////////////////
CGfxTarget::BeginFrame();
SetHWState( gGfxEnv.GetDefaultRenderState(), true );
glEnable( GL_VERTEX_PROGRAM_ARB );
GL_ERRORCHECK();
//glEnable( GL_FRAGMENT_PROGRAM_ARB );
GL_ERRORCHECK();
glPointSize( 3.0f );
GL_ERRORCHECK();
glLineWidth( 1.0f );
GL_ERRORCHECK();

glFinish();

}

///////////////////////////////////////////////////////////////////////////////

void CGfxTargetW32GL::EndFrame( void )
{
////////////////////////////////
// Is this a PBuffer ?
if( mhPBRC )
{
HDC _hdc = mDCStack.top();
HGLRC _hglrc = mGLRCStack.top();

  //PopMaterial();
  glFinish();
  
  wglMakeCurrent( _hdc, _hglrc );

  if( 0 != mpBufferTex )
  {
  	//BindTexture( ETEXSTAGE0, mpBufferTex );
  	glBindTexture( GL_TEXTURE_2D, mpBufferTex->GetTexIH() );
  	wglBindTexImageARB( mhPBRC, WGL_FRONT_LEFT_ARB  );
  	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
  	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
  	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
  	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
  	glBindTexture( GL_TEXTURE_2D, 0 );

  	//wglBindTexImageARB
  }

  glFinish();
  GL_ERRORCHECK();

  mDCStack.pop();
  mGLRCStack.pop();

  CGfxEnv::PopContext( );

}
////////////////////////////////
CGfxTarget::EndFrame();
////////////////////////////////
}

the code below is where a window is drawn, and it calls it’s subbuffers (pbuffers) draw routines. CGfxBuffer: raw Leads back to CGfxTargetW32GL::BeginFrame , therefore CGfxTargetW32GL::BeginFrame is a recursive call with a max recusion depth of 1.

///////////////
from CGfxTargetW32GL::BeginFrame()

else // Window
{
int inumsubbuf = GetNumSubBuffers();
for( int ib=0; ib<inumsubbuf; ib++ )
{ CGfxBuffer *pBUF = GetSubBuffer( ib );
pBUF->Draw(); // render to the pbuffer (pbuffer contains its own CGfxTarget)
}
}
///////////////

here is the pbuffer initialization code

void CGfxTargetW32GL::InitializeContext( CGfxBuffer *pBuf )
{

CGfxTargetW32GL* pTARG = (CGfxTargetW32GL*) CGfxEnv::GetRef().GetCurrentContext();

HDC hWindowDC = pTARG->GetHDC();
HGLRC hWindowGLRC = pTARG->GetHGLRC();

meRenderPath = pTARG->meRenderPath;

//////////////////////////////////////////
// Bind Texture
GLuint hBufferTex = 0;
glGenTextures( 1, & hBufferTex );

mpBufferTex = MagNew CTexture();
mpBufferTex->width = miW;
mpBufferTex->height = miH;
mpBufferTex->miBPP = 4;
mpBufferTex->raw_height = miH;
mpBufferTex->flags = 1;
mpBufferTex->is_tiff = false;

mpBufferTex->SetTexIH( hBufferTex );

TexH _htex = CTexMan::AllocPrsH();
CTexMan::SetTexture( _htex, mpBufferTex );
CTexMan::SetTexIH( _htex, hBufferTex );

pBuf->mpMaterial = (CGfxMaterialVCT *) CClassManager::CreateObject( “CGfxMaterialVCT” );
pBuf->mpMaterial->AddTexture( ETEXDEST_DIFFUSE, _htex );
pBuf->mhTexture = _htex;

//////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////
int format;
int pformat[MAX_PFORMATS];
unsigned int nformats;
////////////////////////////////////////////////////////////////////////////
int iattributes =
{
WGL_DRAW_TO_PBUFFER_ARB, TRUE,
WGL_BIND_TO_TEXTURE_RGBA_ARB, TRUE,
WGL_RED_BITS_ARB, 8,
WGL_GREEN_BITS_ARB, 8,
WGL_BLUE_BITS_ARB, 8,
WGL_ALPHA_BITS_ARB, 8,
WGL_DEPTH_BITS_ARB, 24,
WGL_DOUBLE_BUFFER_ARB, FALSE,
0
};
////////////////////////////////////////////////////////////////////////////
float fattributes =
{
0.0f, 0.0f,
};
////////////////////////////////////////////////////////////////////////////
if ( !wglChoosePixelFormatARB( hWindowDC, iattributes, fattributes, MAX_PFORMATS, pformat, &nformats ) )
{
fprintf( stderr, "pbuffer creation error: wglChoosePixelFormatARB() failed.
" );
exit( -1 );
}
if ( nformats <= 0 )
{
fprintf( stderr, "pbuffer creation error: Couldn’t find a suitable pixel format.
" );
exit( -1 );
}
////////////////////////////////////////////////////////////////////////////
format = pformat[0];
////////////////////////////////////////////////////////////////////////////
// Create the p-buffer.
int properties[7] =
{ WGL_TEXTURE_FORMAT_ARB, WGL_TEXTURE_RGBA_ARB ,
WGL_TEXTURE_TARGET_ARB, WGL_TEXTURE_2D_ARB ,
WGL_MIPMAP_TEXTURE_ARB, 0 ,
0 ,
};
////////////////////////////////////////////////////////////////////////////
mhPBRC = wglCreatePbufferARB( hWindowDC, format, miW, miH, properties );
////////////////////////////////////////////////////////////////////////////
if ( !mhPBRC )
{
DWORD err = GetLastError();
printf( "pbuffer creation error: wglCreatePbufferARB() failed
" );
if ( err == ERROR_INVALID_PIXEL_FORMAT )
{
printf( "error: ERROR_INVALID_PIXEL_FORMAT
" );
}
else if ( err == ERROR_NO_SYSTEM_RESOURCES )
{
printf( "error: ERROR_NO_SYSTEM_RESOURCES
" );
}
else if ( err == ERROR_INVALID_DATA )
{
printf( "error: ERROR_INVALID_DATA
" );
}
exit( -1 );
}
////////////////////////////////////////////////////////////////////////////
// Get the device context.
mhDC = wglGetPbufferDCARB( mhPBRC );
////////////////////////////////////////////////////////////////////////////
if ( ! mhDC )
{
printf( "pbuffer creation error: wglGetPbufferDCARB() failed
" );
exit( -1 );
}
////////////////////////////////////////////////////////////////////////////
// Create a new gl context for the p-buffer.
mhGLRC = wglCreateContext( mhDC );
////////////////////////////////////////////////////////////////////////////
if ( !mhGLRC )
{
printf( "pbuffer creation error: wglCreateContext() failed
" );
exit( -1 );
}
////////////////////////////////////////////////////////////////////////////
if( !wglShareLists( hWindowGLRC, mhGLRC ) )
{
printf( "pbuffer: wglShareLists() failed
" );
exit( -1 );
}
////////////////////////////////////////////////////////////////////////////
// Determine the actual width and height we were able to create.

int iwidth, iheight;
int iOptWidth, iOptHeight;

wglQueryPbufferARB( mhPBRC, WGL_PBUFFER_WIDTH_ARB, &iwidth );
wglQueryPbufferARB( mhPBRC, WGL_PBUFFER_HEIGHT_ARB, &iheight );

//wglQueryPbufferARB( mhPBRC, WGL_OPTIMAL_PBUFFER_WIDTH_ARB, &iOptWidth );
//wglQueryPbufferARB( mhPBRC, WGL_OPTIMAL_PBUFFER_HEIGHT_ARB, &iOptHeight );

printf( "Created a %d x %d pbuffer
", iwidth, iheight );
//printf( "Optimal PBuffer [%dx%d]
", iOptWidth, iOptHeight );

//////////////////////////////////////////////////////////
// vertex buffers and materials

mpVtxBufUILine = new CVtxBuffer( 4096, 8, EPRIM_LINES );
mpVtxBufUIQuad = new CVtxBuffer( 4096, 8, EPRIM_TRIANGLES );
mpVtxBufUITexQuad = new CVtxBuffer( 4096, 8, EPRIM_QUADS );
mpVtxBufUIText = new CVtxBuffer<TEXT_VTXFMT>( 16384, 8, EPRIM_TRIANGLES );

VtxBuf_Init( mpVtxBufUILine );
VtxBuf_Init( mpVtxBufUIQuad );
VtxBuf_Init( mpVtxBufUITexQuad );
VtxBuf_Init( mpVtxBufUIText );

////////////////////////////////////////////////////////////////////////////

pBuf->mpContext = this;
}

thanks,

Michael T. Mayers