//----------------------------------------------------------------------- void CgProgram::buildConstantDefinitions() const { // Derive parameter names from Cg createParameterMappingStructures(true); if ( mProgramString.empty() ) return; mConstantDefs->floatBufferSize = mFloatLogicalToPhysical->bufferSize; mConstantDefs->intBufferSize = mIntLogicalToPhysical->bufferSize; GpuConstantDefinitionMap::const_iterator iter = mParametersMap.begin(); GpuConstantDefinitionMap::const_iterator iterE = mParametersMap.end(); for (; iter != iterE ; iter++) { const String & paramName = iter->first; GpuConstantDefinition def = iter->second; mConstantDefs->map.insert(GpuConstantDefinitionMap::value_type(iter->first, iter->second)); // 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; } // Deal with array indexing mConstantDefs->generateConstantDefinitionArrayEntries(paramName, def); } }
//--------------------------------------------------------------------- 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); } }
//--------------------------------------------------------------------- void GLSLProgramManagerCommon::parseIndividualConstant(const String& src, GpuNamedConstants& defs, String::size_type currPos, const String& filename, GpuSharedParametersPtr sharedParams) { GpuConstantDefinition def; String paramName = ""; String::size_type endPos = src.find(";", currPos); String line = src.substr(currPos, endPos - currPos); // Remove spaces before opening square braces, otherwise // the following split() can split the line at inappropriate // places (e.g. "vec3 something [3]" won't work). for (String::size_type sqp = line.find (" ["); sqp != String::npos; sqp = line.find (" [")) line.erase (sqp, 1); // Split into tokens StringVector parts = StringUtil::split(line, ", \t\r\n"); for (StringVector::iterator i = parts.begin(); i != parts.end(); ++i) { // Is this a type? StringToEnumMap::iterator typei = mTypeEnumMap.find(*i); if (typei != mTypeEnumMap.end()) { completeDefInfo(typei->second, def); } else { // if this is not a type, and not empty, it should be a name StringUtil::trim(*i); if (i->empty()) continue; // Skip over precision keywords if(StringUtil::match((*i), "lowp") || StringUtil::match((*i), "mediump") || StringUtil::match((*i), "highp")) continue; String::size_type arrayStart = i->find("[", 0); if (arrayStart != String::npos) { // potential name (if butted up to array) String name = i->substr(0, arrayStart); StringUtil::trim(name); if (!name.empty()) paramName = name; String::size_type arrayEnd = i->find("]", arrayStart); String arrayDimTerm = i->substr(arrayStart + 1, arrayEnd - arrayStart - 1); StringUtil::trim(arrayDimTerm); // the array term might be a simple number or it might be // an expression (e.g. 24*3) or refer to a constant expression // we'd have to evaluate the expression which could get nasty // TODO def.arraySize = StringConverter::parseInt(arrayDimTerm); } else { paramName = *i; def.arraySize = 1; } // Name should be after the type, so complete def and add // We do this now so that comma-separated params will do // this part once for each name mentioned if (def.constType == GCT_UNKNOWN) { LogManager::getSingleton().logMessage("Problem parsing the following GLSL Uniform: '" + line + "' in file " + filename); // next uniform break; } // Special handling for shared parameters if(sharedParams.isNull()) { // Complete def and add // increment physical buffer location def.logicalIndex = 0; // not valid in GLSL if (def.isFloat()) { def.physicalIndex = defs.floatBufferSize; defs.floatBufferSize += def.arraySize * def.elementSize; } else { def.physicalIndex = defs.intBufferSize; defs.intBufferSize += def.arraySize * def.elementSize; } defs.map.insert(GpuConstantDefinitionMap::value_type(paramName, def)); // Generate array accessors defs.generateConstantDefinitionArrayEntries(paramName, def); } else { try { const GpuConstantDefinition &sharedDef = sharedParams->getConstantDefinition(paramName); (void)sharedDef; // Silence warning } catch (Exception& e) { // This constant doesn't exist so we'll create a new one sharedParams->addConstantDefinition(paramName, def.constType); } } } } }
//--------------------------------------------------------------------- void GLSLESProgramManagerCommon::extractConstantDefs(const String& src, GpuNamedConstants& defs, const String& filename) { // Parse the output string and collect all uniforms // NOTE this relies on the source already having been preprocessed // which is done in GLSLESProgram::loadFromSource String line; String::size_type currPos = src.find("uniform"); while (currPos != String::npos) { GpuConstantDefinition def; String paramName; // Now check for using the word 'uniform' in a larger string & ignore bool inLargerString = false; if (currPos != 0) { char prev = src.at(currPos - 1); if (prev != ' ' && prev != '\t' && prev != '\r' && prev != '\n' && prev != ';') inLargerString = true; } if (!inLargerString && currPos + 7 < src.size()) { char next = src.at(currPos + 7); if (next != ' ' && next != '\t' && next != '\r' && next != '\n') inLargerString = true; } // skip 'uniform' currPos += 7; if (!inLargerString) { // find terminating semicolon String::size_type endPos = src.find(";", currPos); if (endPos == String::npos) { // problem, missing semicolon, abort break; } line = src.substr(currPos, endPos - currPos); // Remove spaces before opening square braces, otherwise // the following split() can split the line at inappropriate // places (e.g. "vec3 something [3]" won't work). for (String::size_type sqp = line.find (" ["); sqp != String::npos; sqp = line.find (" [")) line.erase (sqp, 1); // Split into tokens StringVector parts = StringUtil::split(line, ", \t\r\n"); for (StringVector::iterator i = parts.begin(); i != parts.end(); ++i) { // Is this a type? StringToEnumMap::iterator typei = mTypeEnumMap.find(*i); if (typei != mTypeEnumMap.end()) { completeDefInfo(typei->second, def); } else { // if this is not a type, and not empty, it should be a name StringUtil::trim(*i); if (i->empty()) continue; // Skip over precision keywords if(StringUtil::match((*i), "lowp") || StringUtil::match((*i), "mediump") || StringUtil::match((*i), "highp")) continue; String::size_type arrayStart = i->find("[", 0); if (arrayStart != String::npos) { // potential name (if butted up to array) String name = i->substr(0, arrayStart); StringUtil::trim(name); if (!name.empty()) paramName = name; String::size_type arrayEnd = i->find("]", arrayStart); String arrayDimTerm = i->substr(arrayStart + 1, arrayEnd - arrayStart - 1); StringUtil::trim(arrayDimTerm); // the array term might be a simple number or it might be // an expression (e.g. 24*3) or refer to a constant expression // we'd have to evaluate the expression which could get nasty // TODO def.arraySize = StringConverter::parseUnsignedLong(arrayDimTerm); } else { paramName = *i; def.arraySize = 1; } // Name should be after the type, so complete def and add // We do this now so that comma-separated params will do // this part once for each name mentioned if (def.constType == GCT_UNKNOWN) { LogManager::getSingleton().logMessage( "Problem parsing the following GLSL Uniform: '" + line + "' in file " + filename); // next uniform break; } // Complete def and add // increment physical buffer location def.logicalIndex = 0; // not valid in GLSL if (def.isFloat()) { def.physicalIndex = defs.floatBufferSize; defs.floatBufferSize += def.arraySize * def.elementSize; } else { def.physicalIndex = defs.intBufferSize; defs.intBufferSize += def.arraySize * def.elementSize; } defs.map.insert(GpuConstantDefinitionMap::value_type(paramName, def)); // Generate array accessors defs.generateConstantDefinitionArrayEntries(paramName, def); } } } // not commented or a larger symbol // Find next one currPos = src.find("uniform", currPos); } }
//----------------------------------------------------------------------- void D3D10HLSLProgram::processParamElement(String prefix, LPCSTR pName, size_t paramIndex, ID3D10ShaderReflectionType* varRefType) const { D3D10_SHADER_TYPE_DESC varRefTypeDesc; HRESULT hr = varRefType->GetDesc(&varRefTypeDesc); // Since D3D HLSL doesn't deal with naming of array and struct parameters // automatically, we have to do it by hand if (FAILED(hr)) { OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "Cannot retrieve constant description from HLSL program.", "D3D10HLSLProgram::processParamElement"); } String paramName = pName; // trim the odd '$' which appears at the start of the names in HLSL if (paramName.at(0) == '$') paramName.erase(paramName.begin()); // Also 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); } if (varRefTypeDesc.Class == D3D10_SVC_STRUCT) { // work out a new prefix for nested members, if it's an array, we need an index prefix = prefix + paramName + "."; // Cascade into struct for (unsigned int i = 0; i < varRefTypeDesc.Members; ++i) { processParamElement(prefix, varRefType->GetMemberTypeName(i), i, varRefType->GetMemberTypeByIndex(i)); } } else { // Process params if (varRefTypeDesc.Type == D3D10_SVT_FLOAT || varRefTypeDesc.Type == D3D10_SVT_INT || varRefTypeDesc.Type == D3D10_SVT_BOOL) { String name = prefix + paramName; GpuConstantDefinition def; // populate type, array size & element size populateDef(varRefTypeDesc, def); if (def.isFloat()) { def.physicalIndex = mFloatLogicalToPhysical.bufferSize; OGRE_LOCK_MUTEX(mFloatLogicalToPhysical.mutex) mFloatLogicalToPhysical.map.insert( GpuLogicalIndexUseMap::value_type(paramIndex, GpuLogicalIndexUse(def.physicalIndex, def.arraySize * def.elementSize))); mFloatLogicalToPhysical.bufferSize += def.arraySize * def.elementSize; mConstantDefs.floatBufferSize = mFloatLogicalToPhysical.bufferSize; } else { def.physicalIndex = mIntLogicalToPhysical.bufferSize; OGRE_LOCK_MUTEX(mIntLogicalToPhysical.mutex) mIntLogicalToPhysical.map.insert( GpuLogicalIndexUseMap::value_type(paramIndex, GpuLogicalIndexUse(def.physicalIndex, def.arraySize * def.elementSize))); mIntLogicalToPhysical.bufferSize += def.arraySize * def.elementSize; mConstantDefs.intBufferSize = mIntLogicalToPhysical.bufferSize; } mConstantDefs.map.insert(GpuConstantDefinitionMap::value_type(name, def)); // Now deal with arrays mConstantDefs.generateConstantDefinitionArrayEntries(name, def); } } }