void csShaderGLCGCommon::DoDebugDump () { csString output; DumpProgramInfo (output); output << "CG program type: " << programType << "\n"; output << "CG profile: " << cgGetProgramString (program, CG_PROGRAM_PROFILE) << "\n"; output << "CG entry point: " << (entrypoint ? entrypoint : "main") << "\n"; output << "CG program valid: " << IsValid() << "\n"; output << "\n"; output << "Variable mappings:\n"; for (size_t v = 0; v < variablemap.GetSize (); v++) { const VariableMapEntry& vme = variablemap[v]; ShaderParameter* sparam = reinterpret_cast<ShaderParameter*> (vme.userVal); output << stringsSvName->Request (vme.name); output << '(' << vme.name << ") -> "; output << vme.destination << ' '; if (sparam == 0) { output << "(null)"; } else { if (sparam->paramType != 0) output << cgGetTypeString (sparam->paramType) << ' '; if (sparam->param != 0) output << cgGetParameterName (sparam->param) << " "; output << "baseslot " << sparam->baseSlot; if (sparam->assumeConstant) output << " assumed constant"; } output << '\n'; } output << "\n"; output << "Program leaf parameters:\n"; CGparameter param = cgGetFirstLeafParameter (program, CG_PROGRAM); while (param) { DebugDumpParam (output, param); param = cgGetNextLeafParameter (param); } output << "\n"; output << "Program global parameters:\n"; param = cgGetFirstLeafParameter (program, CG_GLOBAL); while (param) { DebugDumpParam (output, param); param = cgGetNextLeafParameter (param); } output << "\n"; output << "Program source:\n"; output << cgGetProgramString (program, CG_PROGRAM_SOURCE); output << "\n"; output << "Compiled program:\n"; output << cgGetProgramString (program, CG_COMPILED_PROGRAM); output << "\n"; csRef<iVFS> vfs = csQueryRegistry<iVFS> (objectReg); EnsureDumpFile(); csRef<iFile> debugFile = vfs->Open (debugFN, VFS_FILE_APPEND); if (!debugFile) { csReport (objectReg, CS_REPORTER_SEVERITY_WARNING, "crystalspace.graphics3d.shader.glcg", "Could not write %s", CS::Quote::Single (debugFN.GetData())); } else { debugFile->Write (output.GetData(), output.Length ()); csReport (objectReg, CS_REPORTER_SEVERITY_NOTIFY, "crystalspace.graphics3d.shader.glcg", "Dumped Cg program info to %s", CS::Quote::Single (debugFN.GetData())); } }
static bool AddPass(CGtechnique technique, JSON &json, CGpass pass, UniformsMap &uniformRemapping) { bool success = true; json.AddObject(NULL); const char * const passName = cgGetPassName(pass); if (NULL != passName) { json.AddString("name", passName); } bool firstParameter = true; #if CG_VERSION_NUM >= 3000 const int CG_NUMBER_OF_DOMAINS = (CG_TESSELLATION_EVALUATION_DOMAIN + 1); #endif for (int domain = CG_FIRST_DOMAIN; domain < CG_NUMBER_OF_DOMAINS; domain++) { const CGprogram program = cgGetPassProgram(pass, (CGdomain)domain); if (NULL != program) { const char * const programString = cgGetProgramString(program, CG_COMPILED_PROGRAM); CGparameter param = cgGetFirstParameter(program, CG_GLOBAL); while (NULL != param) { if (cgIsParameterUsed(param, program) && CG_UNIFORM == cgGetParameterVariability(param)) { if (firstParameter) { firstParameter = false; json.AddArray("parameters", true); json.BeginData(true); } const char * const paramName = cgGetParameterName(param); AddMappedParameter(json, paramName, programString, uniformRemapping); } param = cgGetNextParameter(param); } param = cgGetFirstParameter(program, CG_PROGRAM); while (NULL != param) { if (cgIsParameterUsed(param, program) && CG_UNIFORM == cgGetParameterVariability(param)) { if (firstParameter) { firstParameter = false; json.AddArray("parameters", true); json.BeginData(true); } const char * const paramName = cgGetParameterName(param); AddMappedParameter(json, paramName, programString, uniformRemapping); } param = cgGetNextParameter(param); } } } if (!firstParameter) { json.EndData(); json.CloseArray(true); // parameters } json.AddArray("semantics", true); json.BeginData(true); CGprogram vertexProgram = cgGetPassProgram(pass, CG_VERTEX_DOMAIN); CGparameter vertexInputParameter = cgGetFirstLeafParameter(vertexProgram, CG_PROGRAM); while (NULL != vertexInputParameter) { const CGenum variability = cgGetParameterVariability(vertexInputParameter); if (CG_VARYING == variability) { const CGenum direction = cgGetParameterDirection(vertexInputParameter); if (CG_IN == direction || CG_INOUT == direction) { const char * const semantic = cgGetParameterSemantic(vertexInputParameter); json.AddData(semantic, strlen(semantic)); } } vertexInputParameter = cgGetNextLeafParameter(vertexInputParameter); } json.EndData(); json.CloseArray(true); // semantics json.AddObject("states"); CGstateassignment state = cgGetFirstStateAssignment(pass); if (NULL != state) { do { success &= AddState(json, state); state = cgGetNextStateAssignment(state); } while (NULL != state); } json.CloseObject(); // states json.AddArray("programs", true); json.BeginData(true); for (int domain = CG_FIRST_DOMAIN; domain < CG_NUMBER_OF_DOMAINS; domain++) { const CGprogram program = cgGetPassProgram(pass, (CGdomain)domain); if (NULL != program) { const char * const entryPoint = cgGetProgramString(program, CG_PROGRAM_ENTRY); json.AddData(entryPoint, strlen(entryPoint)); } else if (domain == CG_VERTEX_DOMAIN) { ErrorMessage("%s : No vertex program.", cgGetTechniqueName(technique)); success = false; } else if(domain == CG_FRAGMENT_DOMAIN) { ErrorMessage("%s : No fragment program.", cgGetTechniqueName(technique)); success = false; } } json.EndData(); json.CloseArray(true); // programs json.CloseObject(); // pass return success; }
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; }