IOGLBaseShader::IOGLBaseShader(CRefPtr<COGLDevice> pDevice, const Graphic::ShaderType uType, const Graphic::ShaderVersion uVersion, CGenum uSourceType, CGprofile uProfile, const CString& strSource, const CString& strEntryPoint) : m_uVersion(uVersion), m_uType(uType), m_uProgram(0), m_bBinded(false), Manage::IManagedObject<COGLDevice, IOGLBaseShader>(pDevice) { if(!cgIsProfileSupported(uProfile)){ throw Exception::CInvalidArgumentException(L"uProfile", String::FromANSI(reinterpret_cast<const int8*>(cgGetProfileString(uProfile))), L"Unsupported shader profile.", CR_INFO()); } auto szSource = String::ToANSI(strSource); auto szEntryPoint = String::ToANSI(strEntryPoint); this->m_uProgram = cgCreateProgram(this->GetParent()->GetCGC().Get(), uSourceType, reinterpret_cast<const char*>(szSource.GetPointer()), uProfile, reinterpret_cast<const char*>(szEntryPoint.GetPointer()), 0); if(!cgIsProgram(this->m_uProgram)){ CR_THROW(L"Failed to create shader program."); } cgCompileProgram(this->m_uProgram); if(!cgIsProgramCompiled(this->m_uProgram)){ CR_THROW(L"Failed to compile program."); } cgGLLoadProgram(this->m_uProgram); }
void CGShader::init(const char *filename, const char *funcname, const char **options) { char* gpopt[3]={0,"-profileopts Vertices=16",0}; assert(cgIsContext(*m_pCgContext)); //if (*m_pCGProfile == cgGLGetLatestProfile(CG_GL_GEOMETRY)){ // options = &gpopt[0]; //} m_program = cgCreateProgramFromFile(*m_pCgContext, CG_SOURCE, filename, *m_pCGProfile, funcname, (const char**)gpopt); if (!cgIsProgramCompiled(m_program)) cgCompileProgram(m_program); cgGLLoadProgram(m_program); }
void cgtk::load_fragment_program(CGprogram &f_program,char *shader_path, char *program_name) { assert(cgIsContext(context)); f_program = cgCreateProgramFromFile(context, CG_SOURCE, shader_path, fragmentProfile,program_name, NULL); if (!cgIsProgramCompiled(f_program)) cgCompileProgram(f_program); cgGLEnableProfile(fragmentProfile); cgGLLoadProgram(f_program); cgGLDisableProfile(fragmentProfile); }
void cgtk::load_vertex_program(CGprogram &v_program,char *shader_path, char *program_name) { assert(cgIsContext(context)); v_program = cgCreateProgramFromFile(context, CG_SOURCE,shader_path, vertexProfile,program_name, NULL); if (!cgIsProgramCompiled(v_program)) cgCompileProgram(v_program); cgGLEnableProfile(vertexProfile); cgGLLoadProgram(v_program); cgGLDisableProfile(vertexProfile); }
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 }
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; }
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; }
// // 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; } }