CD3D9CgMaterialRenderer::~CD3D9CgMaterialRenderer()
{
	if (VertexProgram)
	{
		cgD3D9UnloadProgram(VertexProgram);
		cgDestroyProgram(VertexProgram);
	}
	if (FragmentProgram)
	{
		cgD3D9UnloadProgram(FragmentProgram);
		cgDestroyProgram(FragmentProgram);
	}
	/*if (GeometryProgram)
	{
		cgD3D9UnloadProgram(GeometryProgram);
		cgDestroyProgram(GeometryProgram);
	}*/
}
COpenGLCgMaterialRenderer::~COpenGLCgMaterialRenderer()
{
	if (VertexProgram)
	{
		cgGLUnloadProgram(VertexProgram);
		cgDestroyProgram(VertexProgram);
	}
	if (FragmentProgram)
	{
		cgGLUnloadProgram(FragmentProgram);
		cgDestroyProgram(FragmentProgram);
	}
	if (GeometryProgram)
	{
		cgGLUnloadProgram(GeometryProgram);
		cgDestroyProgram(GeometryProgram);
	}
}
	void CCGShaderSystem::DestroyPixelShader(Resources::IPixelShader* pPS)
	{
		xst_assert( pPS, "(CCGShaderSystem::DestroyPixelShader)" );
		Resources::CCGPixelShader* pShader = (Resources::CCGPixelShader*)pPS;
		if( pShader->m_CGShader != xst_null )
		{
			cgDestroyProgram( pShader->m_CGShader );
		}

	}
void csShaderGLCGCommon::PrecacheClear()
{
  if (program != 0)
  {
    cgDestroyProgram (program);
    program = 0;
  }
  /*objectCode.Empty();
  objectCodeCachePathArc.Empty();
  objectCodeCachePathItem.Empty();*/
}
Beispiel #5
0
//---------------------------------------------------------------------------------
// ~FFxProgram
//---------------------------------------------------------------------------------
FFxProgram::~FFxProgram()
{
	if (mProgram /*&& !mProgramFlags.flags(FFX_PROGRAM_ERROR)*/)
	{
		cgDestroyProgram(mProgram);
		/*
		if (mSourceBuffer)
			delete [] mSourceBuffer;
			*/
	}
}
Beispiel #6
0
	IOGLBaseShader::~IOGLBaseShader(){
		this->UnbindParameters();
		this->UnbindSamplers();
		if(this->m_bBinded){
			this->Unbind();
		}
		if(this->m_uProgram != 0 && cgIsProgram(this->m_uProgram)){
			cgDestroyProgram(this->m_uProgram);
			this->m_uProgram = 0;
		}
	}
static void keyboard(unsigned char c, int x, int y)
{
	switch (c) {
	case 27:  /* Esc key */
		/* Demonstrate proper deallocation of Cg runtime data structures.
		Not strictly necessary if we are simply going to exit. */
		cgDestroyProgram(myCgVertexProgram);
		cgDestroyContext(myCgContext);
		exit(0);
		break;
	}
}
Beispiel #8
0
 //-----------------------------------------------------------------------
 void CgProgram::unloadHighLevelImpl(void)
 {
     // Unload Cg Program
     // Lowlevel program will get unloaded elsewhere
     if (mCgProgram)
     {
         cgDestroyProgram(mCgProgram);
         checkForCgError("CgProgram::unloadImpl", 
             "Error while unloading Cg program " + mName + ": ", 
             mCgContext);
         mCgProgram = 0;
     }
 }
Beispiel #9
0
static void gl_cg_deinit_progs(void)
{
   RARCH_LOG("CG: Destroying programs.\n");
   cgGLUnbindProgram(cgFProf);
   cgGLUnbindProgram(cgVProf);

   // Programs may alias [0].
   for (unsigned i = 1; i < GFX_MAX_SHADERS; i++)
   {
      if (prg[i].fprg && prg[i].fprg != prg[0].fprg)
         cgDestroyProgram(prg[i].fprg);
      if (prg[i].vprg && prg[i].vprg != prg[0].vprg)
         cgDestroyProgram(prg[i].vprg);
   }

   if (prg[0].fprg)
      cgDestroyProgram(prg[0].fprg);
   if (prg[0].vprg)
      cgDestroyProgram(prg[0].vprg);

   memset(prg, 0, sizeof(prg));
}
//[-------------------------------------------------------]
//[ Private virtual PLRenderer::Resource functions        ]
//[-------------------------------------------------------]
void FragmentShaderCg::BackupDeviceData(uint8 **ppBackup)
{
	// Backup data
	const char *pszProgram = m_pCgFragmentProgram ? cgGetProgramString(m_pCgFragmentProgram, CG_PROGRAM_SOURCE) : nullptr;
	if (pszProgram) {
		const uint32 nNumOfBytes = Wrapper::GetStringLength(pszProgram) + 1;
		*ppBackup = new uint8[nNumOfBytes];
		MemoryManager::Copy(*ppBackup, pszProgram, nNumOfBytes);
		cgDestroyProgram(m_pCgFragmentProgram);
		m_pCgFragmentProgram = nullptr;
	} else {
		*ppBackup = nullptr;
	}
}
Beispiel #11
0
void sCompileResult::Reset()
{
#if sCOMP_DX9_ENABLE
  sRelease(D3D9.CTable);
  sRelease(D3D9.Errors);
#endif // sCOMP_DX9_ENABLE
#if sCOMP_CG_ENABLE
  if(Cg.Program)
    cgDestroyProgram(Cg.Program);
#endif // sCOMP_CG_ENABLE
  ShaderBlobs.Reset();
  Valid = sFALSE;
  Errors = L"";
}
void ObjMeshGPUDeformer::DeleteCGShaders()
{
  if (VertexPass2Program) 
    cgDestroyProgram(VertexPass2Program);
  
  if (VertexPass2ProgramShadow)
    cgDestroyProgram(VertexPass2ProgramShadow);

  //if (VertexPass2ProgramDeformedNormals)
    //cgDestroyProgram(VertexPass2ProgramDeformedNormals);

  if (VertexPass2ProgramPoints) 
    cgDestroyProgram(VertexPass2ProgramPoints);
    
  if (VertexPass2ProgramEdges)
    cgDestroyProgram(VertexPass2ProgramEdges);

  if (FragmentPass2Program)
    cgDestroyProgram(FragmentPass2Program);
    
  if (Context)
    cgDestroyContext(Context);
}
Beispiel #13
0
cgShader::~cgShader(){

    SAFE_FREE(code);

    SAFE_FREE(vpmain);
    SAFE_FREE(gpmain);
    SAFE_FREE(fpmain);

    for(int k = 0; k < 3; k++){
        if(cgProgram[k]){
            cgDestroyProgram(cgProgram[k]);
        }
    }
}
	CGprogram CCGShaderSystem::CreateProgram(lpcastr lpszShaderCode, CGprofile Profile, lpcastr lpszEntryPoint, lpcastr lpszShaderName)
	{
		XST_LOG_ERR( lpszShaderCode );
		CGprogram Program = cgCreateProgram( m_CGContext, CG_SOURCE, lpszShaderCode, Profile, lpszEntryPoint, xst_null );
		if( XST_FAILED( this->CheckForErrors( "Program creation", lpszShaderName ) ) )
		{
			if( Program ) 
			{
				cgDestroyProgram( Program );
			}
			return xst_null;
		}

		return Program;
	}
Beispiel #15
0
void CD3DCG::ClearPasses()
{
	/* clean up cg programs, vertex buffers/declarations and textures
	   from all regular passes. pass 0 is the orignal texture, so ignore that
	*/
	if(shaderPasses.size()>1) {
		for(std::vector<shaderPass>::iterator it=(shaderPasses.begin()+1);it!=shaderPasses.end();it++) {
			if(it->cgFragmentProgram)
				cgDestroyProgram(it->cgFragmentProgram);
			if(it->cgVertexProgram)
				cgDestroyProgram(it->cgVertexProgram);
			if(it->tex)
				it->tex->Release();
			if(it->vertexBuffer)
				it->vertexBuffer->Release();
			if(it->vertexDeclaration)
				it->vertexDeclaration->Release();
		}
	}
	for(std::vector<lookupTexture>::iterator it=lookupTextures.begin();it!=lookupTextures.end();it++) {
		if(it->tex)
			it->tex->Release();
	}
	for(std::deque<prevPass>::iterator it=prevPasses.begin();it!=prevPasses.end();it++) {
		if(it->tex)
			it->tex->Release();
		if(it->vertexBuffer)
			it->vertexBuffer->Release();
	}
	prevPasses.clear();
	shaderPasses.clear();
	lookupTextures.clear();
	// prevPasses deque is always filled with PREV + PREV1-6 elements
	prevPasses.resize(7);
	shaderLoaded = false;
}
Beispiel #16
0
void DestroyCg()
{
	cgDestroyProgram(VP_DrawSites);
	cgDestroyProgram(FP_DrawSites);
	cgDestroyProgram(VP_Flood);
	cgDestroyProgram(FP_Flood);
	cgDestroyProgram(VP_FinalRender);
	cgDestroyProgram(FP_FinalRender);
	cgDestroyContext(Context);
}
// keyboard callback
void keyboard(unsigned char key, int x, int y) {

  static bool animation = false;

  switch (key) {
  case 27: 		// Escape
  case 'q':
    cgDestroyProgram(cg_vertex_program);
    cgDestroyContext(cg_context);
    exit(0);
  break;
  case ' ':
    animation = !animation;
    if(animation) glutIdleFunc(idle);
    else glutIdleFunc(NULL); 
  break;
  }
}
Beispiel #18
0
/* THE MAIN */
int main( int argc, char** argv ) {
	
	if( argc == 2 ){
		char *a = argv[1];
		readfile( a );
	}else{
		printf( "Usage: shader <filename>\n" );
		exit(0);
	}
	
	init(argc, argv);
	CgInit();
	glutMainLoop();
	
	cgDestroyProgram( CgProg );
	cgDestroyContext( CgCtxt );

	return 0;
}
bool FragmentShaderCg::SetSourceCode(const String &sSourceCode, const String &sProfile, const String &sArguments, const String &sEntry)
{
	// Destroy the previous Cg fragment program, if there's one
	if (m_pCgFragmentProgram) {
		cgDestroyProgram(m_pCgFragmentProgram);
		m_pCgFragmentProgram = nullptr;
	}

	// Get the profile from a user given string
	m_pCgProfile = cgGetProfile(sProfile.GetLength() ? sProfile : "glslf"); // We're using a GLSL profile as default so ATI users have reasonable shader support when using Cg

	// On unknown or invalid profile, choose a fallback profile
	if (m_pCgProfile == CG_PROFILE_UNKNOWN || (!cgGetProfileProperty(m_pCgProfile, CG_IS_FRAGMENT_PROFILE) && m_pCgProfile != CG_PROFILE_GLSLF)) {
		m_pCgProfile = cgGLGetLatestProfile(CG_GL_FRAGMENT);
		if (m_pCgProfile == CG_PROFILE_UNKNOWN && cgGLIsProfileSupported(CG_PROFILE_GLSLF))
			m_pCgProfile = CG_PROFILE_GLSLF;
	}

	// Create the Cg fragment program
	if (m_pCgProfile != CG_PROFILE_UNKNOWN)
		m_pCgFragmentProgram = CgContext::CreateCgProgram(m_pCgProfile, sSourceCode, sArguments, sEntry);

	// Was the Cg program created successfully?
	if (m_pCgFragmentProgram) {
		// Backup the optional shader compiler arguments and the user defined entry point
		m_sArguments = sArguments;
		m_sEntry     = sEntry;

		// Done
		return true;
	} else {
		m_pCgProfile = CG_PROFILE_UNKNOWN;
		m_sArguments = "";
		m_sEntry     = "";

		// Error!
		return false;
	}
}
Beispiel #20
0
static sBool sCompileCg(sCompileResult &result, sInt stype, sInt dtype, sInt flags, const sChar8 *src, sInt len, const sChar8 *name)
{
#if sCOMP_CG_ENABLE
  if(result.Cg.Program)
    cgDestroyProgram(result.Cg.Program);

  sChar8 *src8 = new sChar8[len];
  sCopyString(src8,src,len);

  CGprofile prof = cgGetProfile(GetProfile(dtype));
  CGprogram program = cgCreateProgram(CGC,CG_SOURCE,src8,prof,name,0);

  if(GetCgError(result.Errors)) goto error;

  cgCompileProgram(program);
  if(GetCgError(result.Errors)) goto error;
  const sChar8 *out8 = cgGetProgramString(program,CG_COMPILED_PROGRAM);
  if(GetCgError(result.Errors)) goto error;
  sInt size = 0;
  while(out8[size]) size++;

  sAddShaderBlob(result.ShaderBlobs,dtype,size,(const sU8*)out8);

  result.Valid = sTRUE;
  sDeleteArray(src8);
  return sTRUE;

error:

  result.Valid = sFALSE;
  sDeleteArray(src8);
  return sFALSE;
#else
  sLogF(L"asc",L"sCOMP_CG_ENABLE == 0 no cg compiler available\n");
  return sFALSE;
#endif // sCOMP_CG_ENABLE
}
Beispiel #21
0
static void keyboard(unsigned char c, int x, int y)
{
  

  switch (c) {
  case ' ':
    animating = !animating; /* Toggle */
    if (animating) {
	  enablestick=0;
	  moving=0;
	    w.xspeed=power*cos(2*angle*myPi/360); 
		w.zspeed=power*sin(2*angle*myPi/360);
      glutIdleFunc(idle);
    } else {
      reset();
      glutIdleFunc(NULL);
    }    
    break;
  case '1':
	  camera[0]=0; camera[1]=200; camera[2]=400;
  	  angle = -90;
	  stickangle = 0;

	glutPostRedisplay();
	  break;
  case  '2':
	  camera[0]=500; camera[1]=200; camera[2]=0;
	  angle = 180;
	  stickangle = 270;
	glutPostRedisplay();
	  break;
  case '3':
	  camera[0]=-500; camera[1]=200; camera[2]=0;
	  angle = 0;
	  stickangle = 90;
	  glutPostRedisplay();
	  break;
  case '4':
	  camera[0]=0; camera[1]=200; camera[2]=-400;
	  angle = 90;
	  stickangle=180;
	  glutPostRedisplay();
	break;
  case 'z':
	 angle = angle + 2;
	 stickangle=90+angle;
	  glutPostRedisplay();
      break;
  case 'x':
	angle = angle - 2;
	stickangle=90+angle;
	  glutPostRedisplay();
       break;
  case 'n':
		  if (camera[0]==0 && camera[1]<=200 && camera[1]>=50 && camera[2]<=400 && camera[2]>100)
	  {
		 camera[1]-=25;
		 camera[2]-=50;
		 glutPostRedisplay();
	  }
	  	  if (camera[0]==0 && camera[1]<=200 && camera[1]>=50 && camera[2]>=-400 && camera[2]<100)
	  {
		 camera[1]-=25;
		 camera[2]+=50;
		 glutPostRedisplay();
	  }
		  if (camera[0]<=500 && camera[0]>100 && camera[1]<=200 && camera[1]>50 && camera[2]==0)
	  {
		 camera[0]-=50;
		 camera[1]-=25;
		 glutPostRedisplay();
	  }
		  if (camera[0]>=-500 && camera[0]<=-100 && camera[1]<=200 && camera[1]>50 && camera[2]==0)
	  {
		 camera[0]+=50;
		 camera[1]-=25;
		 glutPostRedisplay();
	  }
      break;
 case 'm':

	  if (camera[0]==0 && camera[1]<=175 && camera[1]>=25 && camera[2]<=350 && camera[2]>75)
	  {
		 camera[1]+=25;
		 camera[2]+=50;
		 glutPostRedisplay();
	  }
	  	  if (camera[0]==0 && camera[1]<=175 && camera[1]>=25 && camera[2]>=-350 && camera[2]<50)
	  {
		 camera[1]+=25;
		 camera[2]-=50;
		 glutPostRedisplay();
	  }
		  if (camera[0]<=450 && camera[0]>=50 && camera[1]<=175 && camera[1]>25 && camera[2]==0)
	  {
		 camera[0]+=50;
		 camera[1]+=25;
		 glutPostRedisplay();
	  }
		  if (camera[0]>=-450 && camera[0]<=-50 && camera[1]<=175 && camera[1]>25 && camera[2]==0)
	  {
		 camera[0]-=50;
		 camera[1]+=25;
		 glutPostRedisplay();
	  }
      break;
  case 27:  /* Esc key */
    /* Demonstrate proper deallocation of Cg runtime data structures.
       Not strictly necessary if we are simply going to exit. */
    cgDestroyProgram(myCgVertexProgram);
    cgDestroyContext(myCgContext);
    exit(0);
    break;
  }
}
Beispiel #22
0
bool cgShader::Reload(){

    for(int k = 0; k < 3; k++){
        if(cgProgram[k]){
            cgDestroyProgram(cgProgram[k]);
        }
    }

    cgProfile[0] = cgProfile[1] = cgProfile[2] = CG_PROFILE_UNKNOWN;
    cgProgram[0] = cgProgram[1] = cgProgram[2] = NULL;

    bool ret = true;

    if(cgGetContext()){
        for(int i = 0; i < 3; i++){
            if(i == 0 && vpmain == 0){ continue; }
            if(i == 1 && gpmain == 0){ continue; }
            if(i == 2 && fpmain == 0){ continue; }

            switch(i){
                case 0: cgProfile[i] = cgGLGetLatestProfile(CG_GL_VERTEX);   break;
                case 1: cgProfile[i] = cgGLGetLatestProfile(CG_GL_GEOMETRY); break;
                case 2: cgProfile[i] = cgGLGetLatestProfile(CG_GL_FRAGMENT); break;
            }

            if (cgProfile[i] == CG_PROFILE_UNKNOWN){
                printf("Invalid profile type (");
                switch(i){
                    case 0: printf("CG_GL_VERTEX)\n");   break;
                    case 1: printf("CG_GL_GEOMETRY)\n"); break;
                    case 2: printf("CG_GL_FRAGMENT)\n"); break;
                }
                ret = false;
                continue;
            }

            cgGLSetOptimalOptions(cgProfile[i]);

            if(code){
                switch(i){
                    case 0: cgProgram[i] = cgCreateProgram(cgGetContext(), CG_SOURCE, code, cgProfile[i], vpmain, 0); break;
                    case 1: cgProgram[i] = cgCreateProgram(cgGetContext(), CG_SOURCE, code, cgProfile[i], gpmain, 0); break;
                    case 2: cgProgram[i] = cgCreateProgram(cgGetContext(), CG_SOURCE, code, cgProfile[i], fpmain, 0); break;
                }
            }
            else{
                switch(i){
                    case 0: cgProgram[i] = cgCreateProgramFromFile(cgGetContext(), CG_SOURCE, fname, cgProfile[i], vpmain, 0); break;
                    case 1: cgProgram[i] = cgCreateProgramFromFile(cgGetContext(), CG_SOURCE, fname, cgProfile[i], gpmain, 0); break;
                    case 2: cgProgram[i] = cgCreateProgramFromFile(cgGetContext(), CG_SOURCE, fname, cgProfile[i], fpmain, 0); break;
                }
            }

            if (cgProgram[i] == NULL){
                switch(i){
                    case 0: printf("CG ERROR (VERTEX) : %s\n",  cgGetErrorString(cgGetError())); break;
                    case 1: printf("CG ERROR (GEOMETRY) : %s\n",cgGetErrorString(cgGetError())); break;
                    case 2: printf("CG ERROR (FRAGMENT) : %s\n",cgGetErrorString(cgGetError())); break;
                }
                ret = false;
                continue;
            }

            cgGLLoadProgram(cgProgram[i]);
        }
    }

    if(loaded){
        if(ret){    printf("INFO (cgShader): Reloaded %s successfully\n",fname); }
        else{        printf("INFO (cgShader): Reloading %s failed\n",fname); }
    }
    else{
        if(ret){    printf("INFO (cgShader): Loaded %s successfully\n",fname); }
        else{        printf("INFO (cgShader): Loading %s failed\n",fname); }
    }

    loaded = true;

    return ret;
}
Beispiel #23
0
bool cgShader_3::Reload(){

    for(int k = 0; k < 5; k++){
        if(cgProgram[k]){
            cgDestroyProgram(cgProgram[k]);
        }
        cgProfile[k] = CG_PROFILE_UNKNOWN;
        cgProgram[k] = NULL;
    }

    bool ret = true;

    if(cgGetContext()){
        for(int i = 0; i < 5; i++){
            if( main[i] == 0 ){ continue; }

            switch(i){
                case 0: cgProfile[i] = cgGLGetLatestProfile(CG_GL_VERTEX);                    break;
                case 1: cgProfile[i] = cgGLGetLatestProfile(CG_GL_TESSELLATION_CONTROL);    break;
                case 2: cgProfile[i] = cgGLGetLatestProfile(CG_GL_TESSELLATION_EVALUATION);    break;
                case 3: cgProfile[i] = cgGLGetLatestProfile(CG_GL_GEOMETRY);                break;
                case 4: cgProfile[i] = cgGLGetLatestProfile(CG_GL_FRAGMENT);                break;
            }

            if (cgProfile[i] == CG_PROFILE_UNKNOWN){
                printf("Invalid profile type (");
                switch(i){
                    case 0: printf("CG_GL_VERTEX)\n");                    break;
                    case 1: printf("CG_GL_TESSELLATION_CONTROL)\n");    break;
                    case 2: printf("CG_GL_TESSELLATION_EVALUATION)\n");    break;
                    case 3: printf("CG_GL_GEOMETRY)\n");                break;
                    case 4: printf("CG_GL_FRAGMENT)\n");                break;
                }
                ret = false;
                continue;
            }

            cgGLSetOptimalOptions(cgProfile[i]);

            if(code){
                cgProgram[i] = cgCreateProgram(cgGetContext(), CG_SOURCE, code, cgProfile[i], main[i], 0);
            }
            else{
                cgProgram[i] = cgCreateProgramFromFile(cgGetContext(), CG_SOURCE, fname, cgProfile[i], main[i], 0);
            }

            if (cgProgram[i] == NULL){
                switch(i){
                    case 0: printf("CG ERROR (VERTEX) : %s\n",   cgGetErrorString(cgGetError())); break;
                    case 1: printf("CG ERROR (TESS_CTRL) : %s\n",cgGetErrorString(cgGetError())); break;
                    case 2: printf("CG ERROR (TESS_EVAL) : %s\n",cgGetErrorString(cgGetError())); break;
                    case 3: printf("CG ERROR (GEOMETRY) : %s\n", cgGetErrorString(cgGetError())); break;
                    case 4: printf("CG ERROR (FRAGMENT) : %s\n", cgGetErrorString(cgGetError())); break;
                }
                ret = false;
                continue;
            }

            cgGLLoadProgram(cgProgram[i]);
        }
    }

    if(loaded){
        if(ret){    printf("INFO (cgShader): Reloaded %s successfully\n",fname); }
        else{        printf("INFO (cgShader): Reloading %s failed\n",fname); }
    }
    else{
        if(ret){    printf("INFO (cgShader): Loaded %s successfully\n",fname); }
        else{        printf("INFO (cgShader): Loading %s failed\n",fname); }
    }

    loaded = true;

    return ret;
}
Beispiel #24
0
CGShader::~CGShader(void)
{
	cgDestroyProgram(m_program); 
}
bool PixelShaderCache::CompilePixelShader(FRAGMENTSHADER& ps, const char* pstrprogram)
{
	GLenum err = GL_REPORT_ERROR();
	if (err != GL_NO_ERROR)
	{
		ERROR_LOG(VIDEO, "glError %08x before PS!", err);
	}

#if defined HAVE_CG && HAVE_CG
	char stropt[128];
	sprintf(stropt, "MaxLocalParams=224,NumInstructionSlots=%d", s_nMaxPixelInstructions);
	const char *opts[] = {"-profileopts", stropt, "-O2", "-q", NULL};
	CGprogram tempprog = cgCreateProgram(g_cgcontext, CG_SOURCE, pstrprogram, g_cgfProf, "main", opts);

	// handle errors
	if (!cgIsProgram(tempprog))
	{
		cgDestroyProgram(tempprog);

		static int num_failures = 0;
		char szTemp[MAX_PATH];
		sprintf(szTemp, "%sbad_ps_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++);
		std::ofstream file(szTemp);
		file << pstrprogram;
		file.close();

		PanicAlert("Failed to compile pixel shader!\nThis usually happens when trying to use Dolphin with an outdated GPU or integrated GPU like the Intel GMA series.\n\nIf you're sure this is Dolphin's error anyway, post the contents of %s along with this error message at the forums.\n\nDebug info (%d):\n%s",
						szTemp,
						g_cgfProf,
						cgGetLastListing(g_cgcontext));

		return false;
	}

	// handle warnings
	if (cgGetError() != CG_NO_ERROR)
	{
		WARN_LOG(VIDEO, "Warnings on compile ps %s:", cgGetLastListing(g_cgcontext));
		WARN_LOG(VIDEO, "%s", pstrprogram);
	}

	// This looks evil - we modify the program through the const char * we got from cgGetProgramString!
	// It SHOULD not have any nasty side effects though - but you never know...
	char *pcompiledprog = (char*)cgGetProgramString(tempprog, CG_COMPILED_PROGRAM);
	char *plocal = strstr(pcompiledprog, "program.local");
	while (plocal != NULL)
	{
		const char *penv = "  program.env";
		memcpy(plocal, penv, 13);
		plocal = strstr(plocal+13, "program.local");
	}

	glGenProgramsARB(1, &ps.glprogid);
	SetCurrentShader(ps.glprogid);	
	glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(pcompiledprog), pcompiledprog);

	err = GL_REPORT_ERROR();
	if (err != GL_NO_ERROR)
	{
		GLint error_pos, native_limit;
		glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &error_pos);
		glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB, &native_limit);
		// Error occur
		if (error_pos != -1) {
			const char *program_error = (const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB);
			char line[256];
			strncpy(line, (const char *)pcompiledprog + error_pos, 255);
			line[255] = 0;
			ERROR_LOG(VIDEO, "Error at %i: %s", error_pos, program_error);
			ERROR_LOG(VIDEO, "Line dump: \n%s", line);
		} else if (native_limit != -1) {
			ERROR_LOG(VIDEO, "Hit limit? %i", native_limit);
			// TODO
		}
		ERROR_LOG(VIDEO, "%s", pstrprogram);
		ERROR_LOG(VIDEO, "%s", pcompiledprog);
	}

	cgDestroyProgram(tempprog);
#endif

	return true;
}
    //
    // Constructor
    //
    CCgShader::CCgShader( 
                         CGenum SourceType, const string& SourceStr, CGprofile Profile, CGGLenum ProfileClass,
                         const string& Entry, const string& Arguments
                         ):
        m_Program( NULL )
    {
        if (SourceType != CG_SOURCE && SourceType != CG_OBJECT)
            throw Sys::CDeveloperException( "GL::CCgShader", "::CCgShader() : Invalid <SourceType> parameter." );
        if (SourceStr.length() == 0)
            throw Sys::CDeveloperException( "GL::CCgShader", "::CCgShader() : Invalid <SourceStr> parameter." );

        CCgContext::AddRef();

        if (Profile == CG_PROFILE_UNKNOWN)
            Profile = cgGLGetLatestProfile( ProfileClass );
        else 
        {
            CheckDomain( Profile, ProfileClass );
            if (cgGLIsProfileSupported( Profile ) == CG_FALSE)
            {
                const char *ProfileName = GetProfileName( Profile );
                if (!ProfileName)
                    throw Sys::CException( 0, "GL::CCgShader", "::CCgShader() : Unknown shader profile." );
                else
                {
                    throw Sys::CException( 0, "GL::CCgShader", "::CCgShader() : Profile %s unsupported.\n"
                        "A profile may not be supported if required OpenGL extension is not available.", ProfileName );
                }
            }
        }

        try
        {
            const char *TypeName = NULL;
            switch (ProfileClass)
            {
            case CG_GL_VERTEX:
                TypeName = "vertex";
                break;
            case CG_GL_GEOMETRY:
                TypeName = "geometry";
                break;
            case CG_GL_FRAGMENT:
                TypeName = "fragment";
                break;
            }

            const char *Args[ 2 ] =
            {
                Arguments.c_str(),
                NULL
            };
            
            m_Program = cgCreateProgram( CCgContext::GetContext(), SourceType, SourceStr.c_str(), Profile, 
                (Entry.length() == 0) ? NULL : Entry.c_str(), (Arguments.length() == 0) ? NULL : Args );
            if (!m_Program)
            {
                m_LastListing = CCgContext::GetLastListing();
    #ifdef _DEBUG
                OutputDebugLog();
    #endif
                throw CCgException( "GL::CCgShader", cgGetError(), "::CCgShader() : Failed to create Cg %s shader.\nSee program log for more details.", TypeName );
            }

            cgCompileProgram( m_Program );
            CGerror Error = cgGetError();
            if (Error != CG_NO_ERROR)
            {
                m_LastListing = CCgContext::GetLastListing();
    #ifdef _DEBUG
                OutputDebugLog();
    #endif
                throw CCgException( "GL::CCgShader", Error, "::CCgShader() : Failed to compile Cg %s shader.\nSee program log for more details.", TypeName );
            }
        }
        catch (const Sys::CException& Ex)
        {
            if (cgIsProgram( m_Program ))
                cgDestroyProgram( m_Program );

            CCgContext::Release();

            throw Ex;
        }
    }
Beispiel #27
0
//---------------------------------------------------------------------------------
// init
// this function load and compile a vertex/fragment program on the specified context
// if the source file is not found, it assigns a default GREEN color shader
// if the compile failed, it assigns a default RED color shader
//---------------------------------------------------------------------------------
bool FFxProgram::init(CGcontext aContext)
{
	CGenum	fileType;

	// remove existing program (in case a program is already loaded)

	if (mProgram)
	{
		cgDestroyProgram(mProgram);
		mProgram = 0;
	}
	fileType = CG_SOURCE;

#ifdef WIN32
	HRESULT hr;

	if (GDD->GetClassID() == ClassIDZDisplayDeviceDX9)
	{
		const char** profileOpts;
		profileOpts = cgD3D9GetOptimalOptions(mProfile);
		const char *nOpts[16];
		nOpts[0] = COMPILE_ARGS[0];
		int idx =1;
		while ( (idx<15) && profileOpts[idx-1])
		{
			nOpts[idx] = profileOpts[idx-1];
			idx++;
		}
		nOpts[idx] = 0;

		const char *szDXprofile = NULL;

		if (mProfile == CG_PROFILE_VS_2_0)
		{
			szDXprofile = D3DXGetVertexShaderProfile(GDD->GetD3D9Device());
		}
		else
		{
			szDXprofile = D3DXGetPixelShaderProfile(GDD->GetD3D9Device());
		}
/*

		//LPD3DXBUFFER mDXShader;
		D3DXCompileShader(
			mSourceBuffer,
			strlen(mSourceBuffer),
			NULL,
			NULL,
			mEntry.c_str(),
			szDXprofile,
			0,
			&mDXShader,
			NULL,
			NULL
			);
		*/



		mProgram = cgCreateProgram(aContext, fileType, mSourceBuffer, mProfile, mEntry.c_str(), nOpts);
		hr = cgD3D9LoadProgram(mProgram, true, 0);
	}
	else
#endif
	{
		// opengl
		//mProgram = cgCreateProgram(aContext, fileType, mSourceBuffer, mProfile, mEntry.c_str(), COMPILE_ARGS);
		mProfile = (mProfileDomain == CG_VERTEX_DOMAIN) ?cgGLGetLatestProfile(CG_GL_VERTEX):cgGLGetLatestProfile(CG_GL_FRAGMENT );
		assert(cgGLIsProfileSupported(mProfile));
		mProgram = cgCreateProgramFromFile(aContext, fileType, mFileName, mProfile, mEntry.c_str(), COMPILE_ARGS);
		if (mProgram == NULL) {
			CGerror error;
			const char* errTxt = cgGetLastErrorString(&error);
			LOG ("ERROR %x: can't compile %s : %s\n", error, mFileName.c_str(), errTxt);
			useDefaultProgram(aContext);
			assert(false);
			return false;
		}
		cgGLLoadProgram(mProgram);
		checkForCgError("loadprog");
	}
	if (mProgram == 0)
	{
		CGerror error = cgGetError();
		LOG ("ERROR %x: can't load or compile %s : %s\n", error, mFileName.c_str(), cgGetLastErrorString(&error));
		useDefaultProgram(aContext);
		assert(false);
		return false;
	}
	return true;
}
iShaderProgram::CacheLoadResult csShaderGLCGCommon::LoadFromCache (
  iHierarchicalCache* cache, iBase* previous, iDocumentNode* node,
  csRef<iString>* failReason, csRef<iString>* tag,
  ProfileLimitsPair* cacheLimits)
{
  if (!cache) return iShaderProgram::loadFail;

  csRef<iShaderProgramCG> prevCG (scfQueryInterfaceSafe<iShaderProgramCG> (
    previous));

  csRef<iStringArray> allCachedPrograms;
  if ((programType == progVP) && prevCG.IsValid())
  {
    csShaderGLCGFP* prevFP = static_cast<csShaderGLCGFP*> (
      (iShaderProgramCG*)prevCG);
    csString tagStr ("CG");
    tagStr += prevFP->cacheLimits.ToString();
    if (failReason) failReason->AttachNew (
      new scfString ("paired cached programs not found"));
    allCachedPrograms.AttachNew (new scfStringArray);
    allCachedPrograms->Push (tagStr);
  }
  else
    allCachedPrograms = cache->GetSubItems ("/");

  if (!allCachedPrograms.IsValid() || (allCachedPrograms->GetSize() == 0))
  {
    if (failReason) failReason->AttachNew (
      new scfString ("no cached programs found"));
    return iShaderProgram::loadFail;
  }
  
  if (!GetProgramNode (node)) return iShaderProgram::loadFail;
  csRef<iDataBuffer> programBuffer = GetProgramData();
  CS::Utility::Checksum::MD5::Digest progHash = CS::Utility::Checksum::MD5::Encode (
    programBuffer->GetData(), programBuffer->GetSize());
  
  csArray<CachedShaderWrapper> cachedProgWrappers;
  for (size_t i = 0; i < allCachedPrograms->GetSize(); i++)
  {
    const char* tag = allCachedPrograms->Get (i);
    if ((tag[0] != 'C') || (tag[1] != 'G')) continue;

    CachedShaderWrapper wrapper;
    if (!wrapper.limits.FromString (tag+2)) continue;
    wrapper.name = tag;

    csString cachePath ("/");
    cachePath.Append (tag);
    csRef<iDataBuffer> cacheBuf = cache->ReadCache (cachePath);
    if (!cacheBuf.IsValid()) continue;
    
    csRef<iFile> cacheFile;
    cacheFile.AttachNew (new csMemFile (cacheBuf, true));
    wrapper.cacheFile = cacheFile;
  
    uint32 diskMagic;
    if (cacheFile->Read ((char*)&diskMagic, sizeof (diskMagic))
	!= sizeof (diskMagic)) continue;
    if (csLittleEndian::UInt32 (diskMagic) != cacheFileMagic)
      continue;
      
    CS::Utility::Checksum::MD5::Digest diskHash;
    if (cacheFile->Read ((char*)&diskHash, sizeof (diskHash))
	!= sizeof (diskHash)) continue;
    if (diskHash != progHash) continue;
    
    cachedProgWrappers.Push (wrapper);
  }
  
  if (cachedProgWrappers.GetSize() == 0)
  {
    if (failReason && !*failReason) failReason->AttachNew (
      new scfString ("all cached programs failed to read"));
    return iShaderProgram::loadFail;
  }
  
  cachedProgWrappers.Sort ();

  ProfileLimits currentLimits (
    (programType == progVP) ? shaderPlug->currentLimits.vp 
      : shaderPlug->currentLimits.fp);
  bool strictMatch = (programType == progVP) ? shaderPlug->strictMatchVP 
      : shaderPlug->strictMatchFP;
  const char* progTypeNode = 0;
  switch (programType)
  {
    case progVP: progTypeNode = "cgvp"; break;
    case progFP: progTypeNode = "cgfp"; break;
  }
  
  csString allReasons;
  bool oneReadCorrectly = false;
  ProfileLimits bestLimits (
    CS::PluginCommon::ShaderProgramPluginGL::Other,
    CG_PROFILE_UNKNOWN);
  bool bestLimitsSet = false;
  for (size_t i = cachedProgWrappers.GetSize(); i-- > 0;)
  {
    const CachedShaderWrapper& wrapper = cachedProgWrappers[i];
    const ProfileLimits& limits =
      (programType == progVP) ? wrapper.limits.vp : wrapper.limits.fp;

    if (!bestLimitsSet)
    {
      bestLimits = limits;
      bestLimitsSet = true;
    }
      
    if (strictMatch && (limits != currentLimits))
    {
      allReasons += wrapper.name;
      allReasons += ": strict mismatch; ";
      continue;
    }
  
    bool profileSupported =
      (shaderPlug->ProfileNeedsRouting (limits.profile)
        && shaderPlug->IsRoutedProfileSupported (limits.profile))
      || cgGLIsProfileSupported (limits.profile);
    if (!profileSupported)
    {
      allReasons += wrapper.name;
      allReasons += ": Profile unsupported; ";
      continue;
    }
    
    if ((limits.vendor != currentLimits.vendor)
        && (limits.vendor != CS::PluginCommon::ShaderProgramPluginGL::Other))
    {
      allReasons += wrapper.name;
      allReasons += ": vendor mismatch; ";
      continue;
    }
    
    bool limitsSupported = currentLimits >= limits;
    if (!limitsSupported)
    {
      allReasons += wrapper.name;
      allReasons += ": Limits exceeded; ";
      continue;
    }
    
    iFile* cacheFile = wrapper.cacheFile;
    
    {
      uint32 diskState;
      if (cacheFile->Read ((char*)&diskState, sizeof (diskState))
	  != sizeof (diskState)) continue;
      if (csLittleEndian::UInt32 (diskState) != cpsValid)
      {
        oneReadCorrectly = true;
        continue;
      }
    }
  
    
    description = CS::PluginCommon::ShaderCacheHelper::ReadString (cacheFile);
    
    bool breakFail = false;
    csRef<iDocumentNode> cgNode = node->GetNode (progTypeNode);
    if (!cgNode.IsValid()) continue;
    csRef<iDocumentNodeIterator> nodes = cgNode->GetNodes();
    while(nodes->HasNext() && !breakFail)
    {
      csRef<iDocumentNode> child = nodes->Next();
      if(child->GetType() != CS_NODE_ELEMENT) continue;
      const char* value = child->GetValue ();
      csStringID id = xmltokens.Request (value);
      switch(id)
      {
	case XMLTOKEN_VARIABLEMAP:
	  if (!ParseVmap (child))
	    breakFail = true;
	  break;
	case XMLTOKEN_CLIP:
	  if (!ParseClip (child))
	    breakFail = true;
	  break;
	default:
	  /* Ignore unknown nodes. Invalid nodes would have been caught
	     by the first (not from cache) parsing */
	  break;
      }
    }
    if (breakFail) continue;
    
    csString objectCodeCachePathArc =
      CS::PluginCommon::ShaderCacheHelper::ReadString (cacheFile);
    if (objectCodeCachePathArc.IsEmpty()) continue;
    csString objectCodeCachePathItem =
      CS::PluginCommon::ShaderCacheHelper::ReadString (cacheFile);
    if (objectCodeCachePathItem.IsEmpty()) continue;
    
    ProgramObjectID progId (objectCodeCachePathArc, objectCodeCachePathItem);
    ProgramObject programObj;
    //if (!LoadObjectCodeFromCompileCache (limits, cache))
    if (!shaderPlug->progCache.LoadObject (progId, programObj))
      continue;
    
    oneReadCorrectly = true;
    if (program)
    {
      cgDestroyProgram (program);
      program = 0;
    }
    
    if (!programObj.IsValid()) continue;
    
    cgGetError(); // Clear error
    program = cgCreateProgram (shaderPlug->context, 
      CG_OBJECT, programObj.GetObjectCode(), limits.profile, 0, 0);
    if (!program) continue;
    CGerror err = cgGetError();
    if (err != CG_NO_ERROR)
    {
      const char* errStr = cgGetErrorString (err);
      shaderPlug->Report (CS_REPORTER_SEVERITY_WARNING,
	"Cg error %s", errStr);
      continue;
    }
    programProfile = limits.profile;
    programPositionInvariant = programObj.GetFlags() & ProgramObject::flagPositionInvariant;
    unusedParams = programObj.GetUnusedParams();
    
    ClipsToVmap();
    GetParamsFromVmap();

    bool doLoadToGL = !shaderPlug->ProfileNeedsRouting (programProfile);

    cgGetError(); // Clear error
    if (doLoadToGL)
    {
      cgGLLoadProgram (program);
    }
    else
    {
      cgCompileProgram (program);
    }
    
    shaderPlug->PrintAnyListing();
    err = cgGetError();
    if ((err != CG_NO_ERROR)
      || (doLoadToGL && !cgGLIsProgramLoaded (program)))
    {
      //if (shaderPlug->debugDump)
	//DoDebugDump();
	
      const char* errStr = cgGetErrorString (err);
      shaderPlug->Report (CS_REPORTER_SEVERITY_WARNING,
	"Cg error %s", errStr);
  
      if (shaderPlug->doVerbose
	  && (((programType == progVP) && (programProfile >= CG_PROFILE_ARBVP1))
	    || ((programType == progFP) && (programProfile >= CG_PROFILE_ARBFP1))))
      {
	const char* err = (char*)glGetString (GL_PROGRAM_ERROR_STRING_ARB);
	shaderPlug->Report (CS_REPORTER_SEVERITY_WARNING,
	  "OpenGL error string: %s", err);
      }
  
      shaderPlug->SetCompiledSource (0);
      continue;
    }
    
    GetPostCompileParamProps ();
    
    if (shaderPlug->debugDump)
      DoDebugDump();
      
    tag->AttachNew (new scfString (wrapper.name));

    if (cacheLimits != 0)
      *cacheLimits = wrapper.limits;
    
    bool loaded = !shaderPlug->ProfileNeedsRouting (programProfile)
      || LoadProgramWithPS1 ();
    if (loaded && (bestLimits < currentLimits))
    {
      /* The best found program is worse than the current limits, so pretend
         that the shader program failed (instead just being 'invalid') -
         that will make xmlshader try to load the program from scratch,
         ie with current limits, which may just work. */
      if (failReason)
        failReason->AttachNew (new scfString ("Provoking clean load with current limits"));
      return iShaderProgram::loadFail;
    }
    return loaded ? iShaderProgram::loadSuccessShaderValid
        : iShaderProgram::loadSuccessShaderInvalid;
  }
  
  if (oneReadCorrectly)
  {
    if (bestLimits < currentLimits)
    {
      /* The 'invalid' programs may compile with the current limits -
         so again, provoke clean load */
      if (failReason)
        failReason->AttachNew (new scfString ("Provoking clean load with current limits"));
      return iShaderProgram::loadFail;
    }
    else
      return iShaderProgram::loadSuccessShaderInvalid;
  }
  else
    return iShaderProgram::loadFail;
}
Beispiel #29
0
	//-----------------------------------------------------------------------
	void CgProgram::compileMicrocode(void)
	{
		// Create Cg Program
  
		/// Program handle
		CGprogram cgProgram;

		if (mSelectedCgProfile == CG_PROFILE_UNKNOWN)
		{
			LogManager::getSingleton().logMessage(
				"Attempted to load Cg program '" + mName + "', but no supported "
				"profile was found. ");
			return;
		}
		buildArgs();
		// deal with includes
		String sourceToUse = resolveCgIncludes(mSource, this, mFilename);

		cgProgram = cgCreateProgram(mCgContext, CG_SOURCE, sourceToUse.c_str(), 
			mSelectedCgProfile, mEntryPoint.c_str(), const_cast<const char**>(mCgArguments));

		// Test
		//LogManager::getSingleton().logMessage(cgGetProgramString(mCgProgram, CG_COMPILED_PROGRAM));

		// Check for errors
		checkForCgError("CgProgram::compileMicrocode", 
			"Unable to compile Cg program " + mName + ": ", mCgContext);

		CGerror error = cgGetError();
		if (error == CG_NO_ERROR)
		{
			// get program string (result of cg compile)
			mProgramString = cgGetProgramString(cgProgram, CG_COMPILED_PROGRAM);
			checkForCgError("CgProgram::compileMicrocode",
				"Unable to retrieve program code for Cg program " + mName + ": ", mCgContext);

			// get params
			mParametersMap.clear();
			mParametersMapSizeAsBuffer = 0;
			mSamplerRegisterMap.clear();
			recurseParams(cgGetFirstParameter(cgProgram, CG_PROGRAM));
			recurseParams(cgGetFirstParameter(cgProgram, CG_GLOBAL));

			if (mDelegate)
			{
				// Delegating to HLSL or GLSL, need to clean up Cg's output
				fixHighLevelOutput(mProgramString);
				if (mSelectedCgProfile == CG_PROFILE_GLSLG)
				{
					// need to determine input and output operations
					mInputOp = cgGetProgramInput(cgProgram);
					mOutputOp = cgGetProgramOutput(cgProgram);
				}
			}

			// Unload Cg Program - we don't need it anymore
			cgDestroyProgram(cgProgram);
			//checkForCgError("CgProgram::unloadImpl", 
			//  "Error while unloading Cg program " + mName + ": ", 
			//  mCgContext);
			cgProgram = 0;

			if ( GpuProgramManager::getSingleton().getSaveMicrocodesToCache())
			{
				addMicrocodeToCache();
			}
		}


	}
bool csShaderGLCGCommon::DefaultLoadProgram (iShaderProgramCG* cgResolve,
  const char* programStr, ProgramType _type,
  const ProfileLimitsPair& customLimitsPair, uint flags)
{
  if (!programStr || !*programStr) return false;

  const ProfileLimits& customLimits = (_type == progVP) ?
    customLimitsPair.vp : customLimitsPair.fp;
  CGGLenum type = (_type == progVP) ? CG_GL_VERTEX : CG_GL_FRAGMENT;

  size_t i;
  csString augmentedProgramStr = GetAugmentedProgram (programStr,
    (flags & loadFlagUnusedV2FForInit) != 0);
    
  programStr = augmentedProgramStr;
  CGprofile profile = customLimits.profile;
  CS::PluginCommon::ShaderProgramPluginGL::HardwareVendor vendor =
    customLimits.vendor;

  if (shaderPlug->doVerbose || shaderPlug->doVerbosePrecache)
  {
    shaderPlug->Report (CS_REPORTER_SEVERITY_NOTIFY,
      "Cg %s program %s: using profile %s[%d]", GetProgramType(),
      CS::Quote::Single (description.GetData ()),
      cgGetProfileString (profile), profile);
  }

  ArgumentArray args;
  shaderPlug->GetProfileCompilerArgs (GetProgramType(), profile, 
    customLimitsPair,
    vendor,
    (flags & loadIgnoreConfigProgramOpts) ? csGLShader_CG::argsNoConfig
      : csGLShader_CG::argsAll, args);
  for (i = 0; i < compilerArgs.GetSize(); i++) 
    args.Push (compilerArgs[i]);
  programPositionInvariant = false;
  for (i = 0; i < args.GetSize(); ) 
  {
    if (strcmp (args[i], "-posinv") == 0)
    {
      if (profile >= CG_PROFILE_GPU_VP)
      {
	/* Work around Cg 2.0 and above (including 3.0) bug: it emits
	   "OPTION ARB_position_invariant;" AND computes result.position in
	   the VP - doing both is verboten.
	   Affected are the GP4VP and higher profiles.
	   Remedy: remove -posinv argument 
	 */
	args.DeleteIndex (i);
	continue;
      }
      programPositionInvariant = true;
    }
    i++;
  }
  customLimits.ToCgOptions (args);
  args.Push (0);
 
  if (program)
  {
    cgDestroyProgram (program);
  }
  shaderPlug->SetCompiledSource (programStr);
  shaderPlug->SetIgnoreErrors (true);
  program = cgCreateProgram (shaderPlug->context, 
    CG_SOURCE, programStr, 
    profile, !entrypoint.IsEmpty() ? entrypoint : "main", args.GetArray());
  shaderPlug->SetIgnoreErrors (false);
  
  if (!(flags & loadIgnoreErrors)) shaderPlug->PrintAnyListing();

  if (!program)
  {
    shaderPlug->SetCompiledSource (0);
    /*if (shaderPlug->debugDump)
    {
      EnsureDumpFile();
      WriteAdditionalDumpInfo ("Failed program source", programStr);
    }*/
    return false;
  }
  programProfile = cgGetProgramProfile (program);

  GetParamsFromVmapConstants();
  if (flags & loadApplyVmap)
    GetParamsFromVmap();

  if (flags & loadIgnoreErrors) shaderPlug->SetIgnoreErrors (true);
  cgCompileProgram (program);
  if (flags & loadIgnoreErrors)
    shaderPlug->SetIgnoreErrors (false);
  else
    shaderPlug->PrintAnyListing();
  
  if (flags & loadApplyVmap)
    GetPostCompileParamProps ();

  if (flags & loadLoadToGL)
  {
    cgGetError(); // Clear error
    cgGLLoadProgram (program);
    if (!(flags & loadIgnoreErrors)) shaderPlug->PrintAnyListing();
    if ((cgGetError() != CG_NO_ERROR)
      || !cgGLIsProgramLoaded (program)) 
    {
      if (shaderPlug->debugDump)
	DoDebugDump();

      if (shaderPlug->doVerbose
	  && (((type == CG_GL_VERTEX) && (profile >= CG_PROFILE_ARBVP1))
	    || ((type == CG_GL_FRAGMENT) && (profile >= CG_PROFILE_ARBFP1))))
      {
	csString err = (char*)glGetString (GL_PROGRAM_ERROR_STRING_ARB);
	if (!err.IsEmpty())
	  shaderPlug->Report (CS_REPORTER_SEVERITY_WARNING,
	    "OpenGL error string: %s", err.GetData());
      }

      shaderPlug->SetCompiledSource (0);
      return false;
    }
  }

  if (shaderPlug->debugDump)
    DoDebugDump();
  
  shaderPlug->SetCompiledSource (0);

  bool result = true;
  if (programType == progFP)
  {
    int numVaryings = 0;
    CGparameter param = cgGetFirstLeafParameter (program, CG_PROGRAM);
    while (param)
    {
      if (cgIsParameterUsed (param, program)
	&& cgIsParameterReferenced (param))
      {
	const CGenum var = cgGetParameterVariability (param);
	if (var == CG_VARYING)
	  numVaryings++;
      }
  
      param = cgGetNextLeafParameter (param);
    }
    
    /* WORKAROUND: Even NVs G80 doesn't support passing more than 16 attribs
       into an FP, yet Cg happily generates code that uses more (and GL falls 
       back to SW).
       So manually check the number of varying inputs and reject more than 16.
       
       @@@ This should be at least configurable
     */
    const int maxNumVaryings = 16;
    if (numVaryings > maxNumVaryings)
    {
      if (shaderPlug->doVerbose || shaderPlug->doVerbosePrecache)
      {
	shaderPlug->Report (CS_REPORTER_SEVERITY_NOTIFY,
	  "Discarding compiled program for having too much varyings "
	  "(%d, limit is %d)",
	  numVaryings, maxNumVaryings);
      }
      cgDestroyProgram (program);
      program = 0;
      result = false;
    }
  }
  if (!result && !debugFN.IsEmpty())
  {
    csRef<iVFS> vfs = csQueryRegistry<iVFS> (objectReg);
    vfs->DeleteFile (debugFN);
  }
  return result;
}