void csShaderGLCGCommon::DebugDumpParam (csString& output, CGparameter param) { output << "Parameter: " << cgGetParameterName (param) << "\n"; output << " Type: " << cgGetTypeString (cgGetParameterNamedType (param)) << "\n"; output << " Direction: " << cgGetEnumString (cgGetParameterDirection (param)) << "\n"; output << " Semantic: " << cgGetParameterSemantic (param) << "\n"; const CGenum var = cgGetParameterVariability (param); output << " Variability: " << cgGetEnumString (var) << "\n"; output << " Resource: " << cgGetResourceString (cgGetParameterResource (param)) << "\n"; output << " Resource index: " << cgGetParameterResourceIndex (param) << "\n"; // Cg 2.0 seems to not like CG_DEFAULT for uniforms if (/*(var == CG_UNIFORM) || */(var == CG_CONSTANT)) { int nValues; const double* values = cgGetParameterValues (param, (var == CG_UNIFORM) ? CG_DEFAULT : CG_CONSTANT, &nValues); if (nValues != 0) { output << " Values:"; for (int v = 0; v < nValues; v++) { output << ' ' << values[v]; } output << "\n"; } } if (!cgIsParameterUsed (param, program)) output << " not used\n"; if (!cgIsParameterReferenced (param)) output << " not referenced\n"; }
inline void cgfxVaryingParameter::addRecursive( CGparameter parameter, cgfxVaryingParameter**& nextParameter ) { if( cgGetParameterVariability( parameter) == CG_VARYING) { if( cgGetParameterType( parameter) == CG_STRUCT) { CGparameter input = cgGetFirstStructParameter( parameter); while( input) { addRecursive( input, nextParameter); input = cgGetNextParameter( input); } } else if( cgIsParameterReferenced( parameter)) { *nextParameter = new cgfxVaryingParameter( parameter); nextParameter = &(*nextParameter)->fNext; } } }
//--------------------------------------------------------------------- void CgProgram::recurseParams(CGparameter parameter, size_t contextArraySize) { while (parameter != 0) { // Look for uniform parameters only // Don't bother enumerating unused parameters, especially since they will // be optimised out and therefore not in the indexed versions CGtype paramType = cgGetParameterType(parameter); if (cgGetParameterVariability(parameter) == CG_UNIFORM && paramType != CG_SAMPLER1D && paramType != CG_SAMPLER2D && paramType != CG_SAMPLER3D && paramType != CG_SAMPLERCUBE && paramType != CG_SAMPLERRECT && cgGetParameterDirection(parameter) != CG_OUT && cgIsParameterReferenced(parameter)) { int arraySize; switch(paramType) { case CG_STRUCT: recurseParams(cgGetFirstStructParameter(parameter)); break; case CG_ARRAY: // Support only 1-dimensional arrays arraySize = cgGetArraySize(parameter, 0); recurseParams(cgGetArrayParameter(parameter, 0), (size_t)arraySize); break; default: // Normal path (leaf) String paramName = cgGetParameterName(parameter); size_t logicalIndex = cgGetParameterResourceIndex(parameter); // Get the parameter resource, to calculate the physical index CGresource res = cgGetParameterResource(parameter); bool isRegisterCombiner = false; size_t regCombinerPhysicalIndex = 0; switch (res) { case CG_COMBINER_STAGE_CONST0: // register combiner, const 0 // the index relates to the texture stage; store this as (stage * 2) + 0 regCombinerPhysicalIndex = logicalIndex * 2; isRegisterCombiner = true; break; case CG_COMBINER_STAGE_CONST1: // register combiner, const 1 // the index relates to the texture stage; store this as (stage * 2) + 1 regCombinerPhysicalIndex = (logicalIndex * 2) + 1; isRegisterCombiner = true; break; default: // normal constant break; } // Trim the '[0]' suffix if it exists, we will add our own indexing later if (StringUtil::endsWith(paramName, "[0]", false)) { paramName.erase(paramName.size() - 3); } GpuConstantDefinition def; def.arraySize = contextArraySize; mapTypeAndElementSize(paramType, isRegisterCombiner, def); if (def.constType == GCT_UNKNOWN) { LogManager::getSingleton().logMessage( "Problem parsing the following Cg Uniform: '" + paramName + "' in file " + mName); // next uniform parameter = cgGetNextParameter(parameter); continue; } if (isRegisterCombiner) { def.physicalIndex = regCombinerPhysicalIndex; } else { // base position on existing buffer contents if (def.isFloat()) { def.physicalIndex = mFloatLogicalToPhysical->bufferSize; } else { def.physicalIndex = mIntLogicalToPhysical->bufferSize; } } def.logicalIndex = logicalIndex; if( mParametersMap.find(paramName) == mParametersMap.end()) { mParametersMap.insert(GpuConstantDefinitionMap::value_type(paramName, def)); mParametersMapSizeAsBuffer += sizeof(size_t); mParametersMapSizeAsBuffer += paramName.size(); mParametersMapSizeAsBuffer += sizeof(GpuConstantDefinition); } // Record logical / physical mapping if (def.isFloat()) { OGRE_LOCK_MUTEX(mFloatLogicalToPhysical->mutex); mFloatLogicalToPhysical->map.insert( GpuLogicalIndexUseMap::value_type(def.logicalIndex, GpuLogicalIndexUse(def.physicalIndex, def.arraySize * def.elementSize, GPV_GLOBAL))); mFloatLogicalToPhysical->bufferSize += def.arraySize * def.elementSize; } else { OGRE_LOCK_MUTEX(mIntLogicalToPhysical->mutex); mIntLogicalToPhysical->map.insert( GpuLogicalIndexUseMap::value_type(def.logicalIndex, GpuLogicalIndexUse(def.physicalIndex, def.arraySize * def.elementSize, GPV_GLOBAL))); mIntLogicalToPhysical->bufferSize += def.arraySize * def.elementSize; } break; } } // now handle uniform samplers. This is needed to fix their register positions // if delegating to a GLSL shader. if (mDelegate && cgGetParameterVariability(parameter) == CG_UNIFORM && ( paramType == CG_SAMPLER1D || paramType == CG_SAMPLER2D || paramType == CG_SAMPLER3D || paramType == CG_SAMPLERCUBE || paramType == CG_SAMPLERRECT) && cgGetParameterDirection(parameter) != CG_OUT && cgIsParameterReferenced(parameter)) { String paramName = cgGetParameterName(parameter); CGresource res = cgGetParameterResource(parameter); int pos = -1; switch (res) { case CG_TEXUNIT0: pos = 0; break; case CG_TEXUNIT1: pos = 1; break; case CG_TEXUNIT2: pos = 2; break; case CG_TEXUNIT3: pos = 3; break; case CG_TEXUNIT4: pos = 4; break; case CG_TEXUNIT5: pos = 5; break; case CG_TEXUNIT6: pos = 6; break; case CG_TEXUNIT7: pos = 7; break; case CG_TEXUNIT8: pos = 8; break; case CG_TEXUNIT9: pos = 9; break; case CG_TEXUNIT10: pos = 10; break; case CG_TEXUNIT11: pos = 11; break; case CG_TEXUNIT12: pos = 12; break; case CG_TEXUNIT13: pos = 13; break; case CG_TEXUNIT14: pos = 14; break; case CG_TEXUNIT15: pos = 15; break; #if(CG_VERSION_NUM >= 3000) case CG_TEXUNIT16: pos = 16; break; case CG_TEXUNIT17: pos = 17; break; case CG_TEXUNIT18: pos = 18; break; case CG_TEXUNIT19: pos = 19; break; case CG_TEXUNIT20: pos = 20; break; case CG_TEXUNIT21: pos = 21; break; case CG_TEXUNIT22: pos = 22; break; case CG_TEXUNIT23: pos = 23; break; case CG_TEXUNIT24: pos = 24; break; case CG_TEXUNIT25: pos = 25; break; case CG_TEXUNIT26: pos = 26; break; case CG_TEXUNIT27: pos = 27; break; case CG_TEXUNIT28: pos = 28; break; case CG_TEXUNIT29: pos = 29; break; case CG_TEXUNIT30: pos = 30; break; case CG_TEXUNIT31: pos = 31; break; #endif default: break; } if (pos != -1) { mSamplerRegisterMap.insert(std::make_pair(paramName, pos)); } } // Get next parameter = cgGetNextParameter(parameter); } }
//--------------------------------------------------------------------- void CgProgram::recurseParams(CGparameter parameter, size_t contextArraySize) const { while (parameter != 0) { // Look for uniform (non-sampler) parameters only // Don't bother enumerating unused parameters, especially since they will // be optimised out and therefore not in the indexed versions CGtype paramType = cgGetParameterType(parameter); if (cgGetParameterVariability(parameter) == CG_UNIFORM && paramType != CG_SAMPLER1D && paramType != CG_SAMPLER2D && paramType != CG_SAMPLER3D && paramType != CG_SAMPLERCUBE && paramType != CG_SAMPLERRECT && cgGetParameterDirection(parameter) != CG_OUT && cgIsParameterReferenced(parameter)) { int arraySize; switch(paramType) { case CG_STRUCT: recurseParams(cgGetFirstStructParameter(parameter)); break; case CG_ARRAY: // Support only 1-dimensional arrays arraySize = cgGetArraySize(parameter, 0); recurseParams(cgGetArrayParameter(parameter, 0), (size_t)arraySize); break; default: // Normal path (leaf) String paramName = cgGetParameterName(parameter); size_t logicalIndex = cgGetParameterResourceIndex(parameter); // Get the parameter resource, to calculate the physical index CGresource res = cgGetParameterResource(parameter); bool isRegisterCombiner = false; size_t regCombinerPhysicalIndex = 0; switch (res) { case CG_COMBINER_STAGE_CONST0: // register combiner, const 0 // the index relates to the texture stage; store this as (stage * 2) + 0 regCombinerPhysicalIndex = logicalIndex * 2; isRegisterCombiner = true; break; case CG_COMBINER_STAGE_CONST1: // register combiner, const 1 // the index relates to the texture stage; store this as (stage * 2) + 1 regCombinerPhysicalIndex = (logicalIndex * 2) + 1; isRegisterCombiner = true; break; default: // normal constant break; } // Trim the '[0]' suffix if it exists, we will add our own indexing later if (StringUtil::endsWith(paramName, "[0]", false)) { paramName.erase(paramName.size() - 3); } GpuConstantDefinition def; def.arraySize = contextArraySize; mapTypeAndElementSize(paramType, isRegisterCombiner, def); if (def.constType == GCT_UNKNOWN) { LogManager::getSingleton().logMessage( "Problem parsing the following Cg Uniform: '" + paramName + "' in file " + mName); // next uniform continue; } if (isRegisterCombiner) { def.physicalIndex = regCombinerPhysicalIndex; } else { // base position on existing buffer contents if (def.isFloat()) { def.physicalIndex = mFloatLogicalToPhysical.bufferSize; } else { def.physicalIndex = mIntLogicalToPhysical.bufferSize; } } mConstantDefs.map.insert(GpuConstantDefinitionMap::value_type(paramName, def)); // Record logical / physical mapping if (def.isFloat()) { OGRE_LOCK_MUTEX(mFloatLogicalToPhysical.mutex) mFloatLogicalToPhysical.map.insert( GpuLogicalIndexUseMap::value_type(logicalIndex, GpuLogicalIndexUse(def.physicalIndex, def.arraySize * def.elementSize))); mFloatLogicalToPhysical.bufferSize += def.arraySize * def.elementSize; mConstantDefs.floatBufferSize = mFloatLogicalToPhysical.bufferSize; } else { OGRE_LOCK_MUTEX(mIntLogicalToPhysical.mutex) mIntLogicalToPhysical.map.insert( GpuLogicalIndexUseMap::value_type(logicalIndex, GpuLogicalIndexUse(def.physicalIndex, def.arraySize * def.elementSize))); mIntLogicalToPhysical.bufferSize += def.arraySize * def.elementSize; mConstantDefs.intBufferSize = mIntLogicalToPhysical.bufferSize; } // Deal with array indexing mConstantDefs.generateConstantDefinitionArrayEntries(paramName, def); break; } } // Get next parameter = cgGetNextParameter(parameter); } }
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; }