void VectorWarp::hashEngine( const Imath::V2i &tileOrigin, const Gaffer::Context *context, IECore::MurmurHash &h ) const { Warp::hashEngine( tileOrigin, context, h ); h.append( tileOrigin ); ConstStringVectorDataPtr channelNames; { ImagePlug::GlobalScope c( context ); channelNames = vectorPlug()->channelNamesPlug()->getValue(); vectorPlug()->dataWindowPlug()->hash( h ); inPlug()->formatPlug()->hash( h ); } ImagePlug::ChannelDataScope channelDataScope( context ); if( ImageAlgo::channelExists( channelNames->readable(), "R" ) ) { channelDataScope.setChannelName( "R" ); vectorPlug()->channelDataPlug()->hash( h ); } if( ImageAlgo::channelExists( channelNames->readable(), "G" ) ) { channelDataScope.setChannelName( "G" ); vectorPlug()->channelDataPlug()->hash( h ); } if( ImageAlgo::channelExists( channelNames->readable(), "A" ) ) { channelDataScope.setChannelName( "A" ); vectorPlug()->channelDataPlug()->hash( h ); } vectorModePlug()->hash( h ); vectorUnitsPlug()->hash( h ); }
void CopyChannels::hashChannelData( const GafferImage::ImagePlug *parent, const Gaffer::Context *context, IECore::MurmurHash &h ) const { ConstCompoundObjectPtr mapping; { ImagePlug::GlobalScope c( context ); mapping = mappingPlug()->getValue(); } if( const IntData *i = mapping->member<const IntData>( context->get<string>( ImagePlug::channelNameContextName ) ) ) { const ImagePlug *inputImage = inPlugs()->getChild<ImagePlug>( i->readable() ); const V2i tileOrigin = context->get<V2i>( ImagePlug::tileOriginContextName ); const Box2i tileBound( tileOrigin, tileOrigin + V2i( ImagePlug::tileSize() ) ); Box2i inputDataWindow; { ImagePlug::GlobalScope c( context ); inputDataWindow = inputImage->dataWindowPlug()->getValue(); } const Box2i validBound = BufferAlgo::intersection( tileBound, inputDataWindow ); if( validBound == tileBound ) { h = inputImage->channelDataPlug()->hash(); } else { ImageProcessor::hashChannelData( parent, context, h ); if( !BufferAlgo::empty( validBound ) ) { inputImage->channelDataPlug()->hash( h ); h.append( BufferAlgo::intersection( inputDataWindow, tileBound ) ); } } } else { h = ImagePlug::blackTile()->Object::hash(); } }
IECore::MurmurHash StringPlug::hash() const { bool performSubstitution = direction()==Plug::In && !getInput<ValuePlug>() && Plug::getFlags( Plug::PerformsSubstitutions ); if( performSubstitution ) { IECore::ConstObjectPtr o = getObjectValue(); const IECore::StringData *s = IECore::runTimeCast<const IECore::StringData>( o.get() ); if( !s ) { throw IECore::Exception( "StringPlug::getObjectValue() didn't return StringData - is the hash being computed correctly?" ); } if( Context::hasSubstitutions( s->readable() ) ) { IECore::MurmurHash result; result.append( Context::current()->substitute( s->readable() ) ); return result; } } // no substitutions return ValuePlug::hash(); }
AtNode *InstancingConverter::convert( const IECore::Primitive *primitive, const IECore::MurmurHash &additionalHash ) { IECore::MurmurHash h = primitive->::IECore::Object::hash(); h.append( additionalHash ); MemberData::Cache::accessor a; if( m_data->cache.insert( a, h ) ) { a->second = NodeAlgo::convert( primitive ); return a->second; } else { if( a->second ) { AtNode *instance = AiNode( "ginstance" ); AiNodeSetPtr( instance, "node", a->second ); return instance; } } return NULL; }
void ImageStats::hash( const ValuePlug *output, const Context *context, IECore::MurmurHash &h ) const { ComputeNode::hash( output, context, h); const int colorIndex = ::colorIndex( output ); if( colorIndex == -1 ) { // Not a plug we know about return; } const std::string channelName = this->channelName( colorIndex ); const Imath::Box2i area = areaPlug()->getValue(); if( channelName.empty() || BufferAlgo::empty( area ) ) { h.append( static_cast<const FloatPlug *>( output )->defaultValue() ); return; } Sampler s( inPlug(), channelName, area ); s.hash( h ); }
void Grid::hashAttributes( const ScenePath &path, const Gaffer::Context *context, const ScenePlug *parent, IECore::MurmurHash &h ) const { Source::hashAttributes( path, context, parent, h ); if( path.size() == 1 ) { h.append( 1 ); } else if( path.size() == 2 ) { if( path.back() == g_gridLinesName ) { gridPixelWidthPlug()->hash( h ); } else if( path.back() == g_centerLinesName ) { centerPixelWidthPlug()->hash( h ); } else if( path.back() == g_borderLinesName ) { borderPixelWidthPlug()->hash( h ); } } }
IECore::MurmurHash contextHash( const Context *context, bool ignoreFrame = false ) const { IECore::MurmurHash result; std::vector<IECore::InternedString> names; context->names( names ); for( std::vector<IECore::InternedString>::const_iterator it = names.begin(); it != names.end(); ++it ) { // Ignore the UI values since they should be irrelevant // to execution. if( boost::starts_with( it->string(), "ui:" ) ) { continue; } if( ignoreFrame && *it == g_frame ) { continue; } result.append( *it ); context->get<const IECore::Data>( *it )->hash( result ); } return result; }
void ColorProcessor::hashChannelData( const GafferImage::ImagePlug *output, const Gaffer::Context *context, IECore::MurmurHash &h ) const { const std::string &channels = channelsPlug()->getValue(); const std::string &channel = context->get<std::string>( ImagePlug::channelNameContextName ); const std::string &baseName = ImageAlgo::baseName( channel ); if( ( baseName != "R" && baseName != "G" && baseName != "B" ) || !StringAlgo::matchMultiple( channel, channels ) ) { // Auxiliary channel, or not in channel mask. Pass through. h = inPlug()->channelDataPlug()->hash(); return; } ImageProcessor::hashChannelData( output, context, h ); h.append( baseName ); { Context::EditableScope layerScope( context ); layerScope.set( g_layerNameKey, ImageAlgo::layerName( channel ) ); colorDataPlug()->hash( h ); } }
void Constant::hashDataWindow( const GafferImage::ImagePlug *output, const Gaffer::Context *context, IECore::MurmurHash &h ) const { ImageNode::hashDataWindow( output, context, h ); h.append( formatPlug()->hash() ); }
void Duplicate::hashBranchSet( const ScenePath &parentPath, const IECore::InternedString &setName, const Gaffer::Context *context, IECore::MurmurHash &h ) const { h.append( inPlug()->setHash( setName ) ); targetPlug()->hash( h ); childNamesPlug()->hash( h ); }
void AlembicSource::hashObject( const ScenePath &path, const Gaffer::Context *context, const ScenePlug *parent, IECore::MurmurHash &h ) const { FileSource::hashObject( path, context, parent, h ); h.append( context->getFrame() ); }
void ValuePlug::hash( IECore::MurmurHash &h ) const { h.append( hash() ); }
void ColorProcessor::hashChannelData( const GafferImage::ImagePlug *output, const Gaffer::Context *context, IECore::MurmurHash &h ) const { ImageProcessor::hashChannelData( output, context, h ); h.append( context->get<std::string>( ImagePlug::channelNameContextName ) ); colorDataPlug()->hash( h ); }
void Mix::hashChannelData( const GafferImage::ImagePlug *output, const Gaffer::Context *context, IECore::MurmurHash &h ) const { const float mix = mixPlug()->getValue(); if( mix == 0.0f ) { h = inPlugs()->getChild< ImagePlug >( 0 )->channelDataPlug()->hash(); return; } else if( mix == 1.0f && !maskPlug()->getInput<ValuePlug>() ) { h = inPlugs()->getChild< ImagePlug >( 1 )->channelDataPlug()->hash(); return; } ImageProcessor::hashChannelData( output, context, h ); h.append( mix ); const std::string channelName = context->get<std::string>( ImagePlug::channelNameContextName ); const V2i tileOrigin = context->get<V2i>( ImagePlug::tileOriginContextName ); const Box2i tileBound( tileOrigin, tileOrigin + V2i( ImagePlug::tileSize() ) ); for( ImagePlugIterator it( inPlugs() ); !it.done(); ++it ) { if( !(*it)->getInput<ValuePlug>() ) { continue; } IECore::ConstStringVectorDataPtr channelNamesData; Box2i dataWindow; { ImagePlug::GlobalScope c( Context::current() ); channelNamesData = (*it)->channelNamesPlug()->getValue(); dataWindow = (*it)->dataWindowPlug()->getValue(); } const std::vector<std::string> &channelNames = channelNamesData->readable(); if( ImageAlgo::channelExists( channelNames, channelName ) ) { (*it)->channelDataPlug()->hash( h ); } // The hash of the channel data we include above represents just the data in // the tile itself, and takes no account of the possibility that parts of the // tile may be outside of the data window. This simplifies the implementation of // nodes like Constant (where all tiles are identical, even the edge tiles) and // Crop (which does no processing of tiles at all). For most nodes this doesn't // matter, because they don't change the data window, or they use a Sampler to // deal with invalid pixels. But because our data window is the union of all // input data windows, we may be using/revealing the invalid parts of a tile. We // deal with this in computeChannelData() by treating the invalid parts as black, // and must therefore hash in the valid bound here to take that into account. const Box2i validBound = boxIntersection( tileBound, dataWindow ); h.append( validBound ); } IECore::ConstStringVectorDataPtr maskChannelNamesData; Box2i maskDataWindow; { ImagePlug::GlobalScope c( Context::current() ); maskChannelNamesData = maskPlug()->channelNamesPlug()->getValue(); maskDataWindow = maskPlug()->dataWindowPlug()->getValue(); } const std::string &maskChannel = maskChannelPlug()->getValue(); if( maskPlug()->getInput<ValuePlug>() && ImageAlgo::channelExists( maskChannelNamesData->readable(), maskChannel ) ) { h.append( maskPlug()->channelDataHash( maskChannel, tileOrigin ) ); } const Box2i maskValidBound = boxIntersection( tileBound, maskDataWindow ); h.append( maskValidBound ); }
void IECoreArnold::RendererImplementation::addPrimitive( const IECore::Primitive *primitive, const std::string &attributePrefix ) { if( !m_motionTimes.empty() ) { // We're in a motion block. Just store samples // until we have all of them. m_motionPrimitives.push_back( primitive ); if( m_motionPrimitives.size() != m_motionTimes.size() ) { return; } } const CompoundDataMap &attributes = m_attributeStack.top().attributes->readable(); AtNode *shape = NULL; if( automaticInstancing() ) { IECore::MurmurHash hash; for( CompoundDataMap::const_iterator it = attributes.begin(), eIt = attributes.end(); it != eIt; it++ ) { if( boost::starts_with( it->first.value(), attributePrefix ) || boost::starts_with( it->first.c_str(), "ai:shape:" ) ) { hash.append( it->first.value() ); it->second->hash( hash ); } } if( !m_motionTimes.empty() ) { vector<const Primitive *> prims; for( vector<ConstPrimitivePtr>::const_iterator it = m_motionPrimitives.begin(), eIt = m_motionPrimitives.end(); it != eIt; ++it ) { prims.push_back( it->get() ); } shape = m_instancingConverter->convert( prims, m_motionTimes, hash ); } else { shape = m_instancingConverter->convert( primitive, hash ); } } else { if( !m_motionTimes.empty() ) { vector<const Object *> prims; for( vector<ConstPrimitivePtr>::const_iterator it = m_motionPrimitives.begin(), eIt = m_motionPrimitives.end(); it != eIt; ++it ) { prims.push_back( it->get() ); } shape = NodeAlgo::convert( prims, m_motionTimes ); } else { shape = NodeAlgo::convert( primitive ); } } if( strcmp( AiNodeEntryGetName( AiNodeGetNodeEntry( shape ) ), "ginstance" ) ) { // it's not an instance, copy over attributes destined for this object type. const CompoundDataMap &attributes = m_attributeStack.top().attributes->readable(); for( CompoundDataMap::const_iterator it = attributes.begin(), eIt = attributes.end(); it != eIt; it++ ) { if( boost::starts_with( it->first.value(), attributePrefix ) ) { ParameterAlgo::setParameter( shape, it->first.value().c_str() + attributePrefix.size(), it->second.get() ); } else if( boost::starts_with( it->first.c_str(), "ai:shape:" ) ) { ParameterAlgo::setParameter( shape, it->first.value().c_str() + 9, it->second.get() ); } } } else { // it's an instance - make sure we don't get double transformations. AiNodeSetBool( shape, "inherit_xform", false ); } addShape( shape ); }
void CompoundObjectSource::hashSet( const IECore::InternedString &setName, const Gaffer::Context *context, const GafferScene::ScenePlug *parent, IECore::MurmurHash &h ) const { SceneNode::hashSet( setName, context, parent, h ); inPlug()->hash( h ); h.append( setName ); }
void SceneNode::hash( const ValuePlug *output, const Context *context, IECore::MurmurHash &h ) const { const ScenePlug *scenePlug = output->parent<ScenePlug>(); if( scenePlug && enabledPlug()->getValue() ) { // We don't call ComputeNode::hash() immediately here, because for subclasses which // want to pass through a specific hash in the hash*() methods it's a waste of time (the // hash will get overwritten anyway). Instead we call ComputeNode::hash() in our // hash*() implementations, and allow subclass implementations to not call the base class // if they intend to overwrite the hash. if( output == scenePlug->boundPlug() ) { const ScenePath &scenePath = context->get<ScenePath>( ScenePlug::scenePathContextName ); hashBound( scenePath, context, scenePlug, h ); } else if( output == scenePlug->transformPlug() ) { const ScenePath &scenePath = context->get<ScenePath>( ScenePlug::scenePathContextName ); if( scenePath.empty() ) { // the result of compute() will actually be different if we're at the root, so // we hash an identity M44fData: h.append( IECore::M44fData::staticTypeId() ); h.append( Imath::M44f() ); } else { hashTransform( scenePath, context, scenePlug, h ); } } else if( output == scenePlug->attributesPlug() ) { const ScenePath &scenePath = context->get<ScenePath>( ScenePlug::scenePathContextName ); if( scenePath.empty() ) { // the result of compute() will actually be different if we're at the root, so // we just hash the default value: scenePlug->attributesPlug()->defaultValue()->hash( h ); } else { hashAttributes( scenePath, context, scenePlug, h ); } } else if( output == scenePlug->objectPlug() ) { const ScenePath &scenePath = context->get<ScenePath>( ScenePlug::scenePathContextName ); if( scenePath.empty() ) { // the result of compute() will actually be different if we're at the root, so // we just hash the default value: scenePlug->objectPlug()->defaultValue()->hash( h ); } else { hashObject( scenePath, context, scenePlug, h ); } } else if( output == scenePlug->childNamesPlug() ) { const ScenePath &scenePath = context->get<ScenePath>( ScenePlug::scenePathContextName ); hashChildNames( scenePath, context, scenePlug, h ); } else if( output == scenePlug->globalsPlug() ) { hashGlobals( context, scenePlug, h ); } else if( output == scenePlug->setNamesPlug() ) { hashSetNames( context, scenePlug, h ); } else if( output == scenePlug->setPlug() ) { const IECore::InternedString &setName = context->get<IECore::InternedString>( ScenePlug::setNameContextName ); hashSet( setName, context, scenePlug, h ); } } else { ComputeNode::hash( output, context, h ); } }
void CompoundDataPlug::hash( IECore::MurmurHash &h ) const { h.append( hash() ); }
void Shader::stateHash( IECore::MurmurHash &h ) const { h.append( stateHash() ); }
void ImageStats::hash( const ValuePlug *output, const Context *context, IECore::MurmurHash &h ) const { ComputeNode::hash( output, context, h); bool earlyOut = true; for( int i = 0; i < 4; ++i ) { if ( output == minPlug()->getChild(i) || output == maxPlug()->getChild(i) || output == averagePlug()->getChild(i) ) { earlyOut = false; break; } } if( earlyOut ) { return; } const Imath::Box2i regionOfInterest( regionOfInterestPlug()->getValue() ); regionOfInterestPlug()->hash( h ); inPlug()->channelNamesPlug()->hash( h ); inPlug()->dataWindowPlug()->hash( h ); IECore::ConstStringVectorDataPtr channelNamesData = inPlug()->channelNamesPlug()->getValue(); std::vector<std::string> maskChannels = channelNamesData->readable(); channelsPlug()->maskChannels( maskChannels ); const int nChannels( maskChannels.size() ); if ( nChannels > 0 ) { std::vector<std::string> uniqueChannels = maskChannels; GafferImage::ChannelMaskPlug::removeDuplicateIndices( uniqueChannels ); std::string channel; channelNameFromOutput( output, channel ); if ( !channel.empty() ) { h.append( channel ); Sampler s( inPlug(), channel, regionOfInterest ); s.hash( h ); return; } } // If our node is not enabled then we just append the default value that we will give the plug. if( output == maxPlug()->getChild(3) || output == minPlug()->getChild(3) || output == averagePlug()->getChild(3) ) { h.append( 0 ); } else { h.append( 1 ); } }
void OSLLight::hashAttributes( const SceneNode::ScenePath &path, const Gaffer::Context *context, const GafferScene::ScenePlug *parent, IECore::MurmurHash &h ) const { ObjectSource::hashAttributes( path, context, parent, h ); h.append( shaderInPlug()->attributesHash() ); attributesPlug()->hash( h ); }
void CompoundObjectSource::hashTransform( const ScenePath &path, const Gaffer::Context *context, const GafferScene::ScenePlug *parent, IECore::MurmurHash &h ) const { SceneNode::hashTransform( path, context, parent, h ); h.append( &path.front(), path.size() ); inPlug()->hash( h ); }
IECore::MurmurHash ImageWriter::executionHash( const Context *context ) const { IECore::MurmurHash h = fileNamePlug()->hash(); h.append( inPlug()->imageHash() ); return h; }
static IECore::MurmurHash hash( const ValuePlug *plug ) { const ValuePlug *p = sourcePlug( plug ); if( const ValuePlug *input = p->getInput<ValuePlug>() ) { // We know that the input is of a different type to the plug, // because that is guaranteed by sourcePlug(). Get the hash from // the input and add a little extra something to represent the // conversion that m_resultPlug->setFrom( input ) will perform, // to break apart the cache entries. IECore::MurmurHash h = input->hash(); h.append( input->typeId() ); h.append( plug->typeId() ); return h; } else if( p->direction() == In || !p->ancestor<ComputeNode>() ) { // No input connection, and no means of computing // a value. There can only ever be a single value, // which is stored directly on the plug - so we return // the hash of that. return p->m_staticValue->hash(); } // A plug with an input connection or an output plug on a ComputeNode. There can be many values - // one per context, computed by ComputeNode::hash(). First we see if we can retrieve the hash // from our cache, and if we can't we'll compute it using a HashProcess instance. ThreadData &threadData = g_threadData.local(); if( !Process::current() ) { // Starting a new root computation. if( ++(threadData.cacheClearCount) == 3200 ) { // Prevent unbounded growth in the hash cache // if many computations are being performed // without any plugs being dirtied in between, // by clearing it after every Nth computation. // N == 3200 was observed to be 6x faster than // N == 100 for a procedural instancing scene at // a memory cost of about 100 mb. threadData.clearCache = 1; } } if( threadData.clearCache ) { threadData.cache.clear(); threadData.cacheClearCount = 0; threadData.clearCache = 0; } const CacheKey key( p, Context::current()->hash() ); Cache::iterator it = threadData.cache.find( key ); if( it != threadData.cache.end() ) { return it->second; } HashProcess process( p, plug ); threadData.cache[key] = process.m_result; return process.m_result; }
IECore::MurmurHash TaskNode::hash( const Context *context ) const { IECore::MurmurHash h; h.append( typeId() ); return h; }
void Seeds::hashBranchBound( const ScenePath &parentPath, const ScenePath &branchPath, const Gaffer::Context *context, IECore::MurmurHash &h ) const { BranchCreator::hashBranchBound( parentPath, branchPath, context, h ); h.append( inPlug()->boundHash( parentPath ) ); }
/// \todo this hash needs to be smarter - it should detect if the scene cache is animated or not void SceneReader::hash( const Gaffer::ValuePlug *output, const Gaffer::Context *context, IECore::MurmurHash &h ) const { FileSource::hash( output, context, h ); h.append( context->getFrame() / g_frameRate ); }