GammaCurvePtr GammaCurve::GetMatching(const GammaCurvePtr& newInstance) { GammaCurvePtr oldInstance; bool cached = false; // See if we have a matching gamma curve in our chache already #if POV_MULTITHREADED // make sure the cache doesn't get tampered with while we're working on it boost::mutex::scoped_lock lock(cacheMutex); #endif // Check if we already have created a matching gamma curve object; if so, return that object instead. // Also, make sure we get the new object stored (as we're using weak pointers, we may have stale entries; // it also won't hurt if we store the new instance, even if we decide to discard it) for(list<weak_ptr<GammaCurve> >::iterator i(cache.begin()); i != cache.end(); i++) { oldInstance = (*i).lock(); if (!oldInstance) { // Found a stale entry in the cache where we could store the new instance, in case we don't find any match. // As the cache uses weak pointers, we can just as well store the new instance now right away, // and leave it up to the weak pointer mechanism to clean up in case we find an existing instance. if (!cached) (*i) = newInstance; cached = true; } else if (oldInstance->Matches(newInstance)) { // Found a matching curve in the cache, so use that instead, and (as far as we're concerned) // just forget that the new instance ever existed (allowing the shared_ptr mechanism to garbage-collect it) return oldInstance; } } // No matching gamma curve in the cache yet // Store the new entry in the cache if we haven't done so already. if (!cached) cache.push_back(newInstance); return newInstance; }
GammaCurvePtr TranscodingGammaCurve::Get(const GammaCurvePtr& working, const GammaCurvePtr& encoding) { // if the working gamma space is linear, we only need the encoding gamma if (GammaCurve::IsNeutral(working)) return GammaCurvePtr(encoding); // if both gamma spaces are the same, we can replace them with a neutral gamma curve if (working->Matches(encoding)) return NeutralGammaCurve::Get(); // check if we can replace the combination of gamma curves with a single power-law gamma curve PowerLawGammaCurve* powerLawWork = dynamic_cast<PowerLawGammaCurve*>(working.get()); if (powerLawWork) { // if the encoding gamma space is linear, we only need the inverse of the working gamma if (GammaCurve::IsNeutral(encoding)) return PowerLawGammaCurve::GetByEncodingGamma(powerLawWork->ApproximateDecodingGamma()); // if both gamma spaces are based on a simple power-law, we only need to combine them into a single one PowerLawGammaCurve* powerLawEnc = dynamic_cast<PowerLawGammaCurve*>(encoding.get()); if (powerLawEnc) return PowerLawGammaCurve::GetByEncodingGamma(powerLawWork->ApproximateDecodingGamma() / powerLawEnc->ApproximateDecodingGamma()); } // we really need a combo of two gamma curves return GetMatching(GammaCurvePtr(new TranscodingGammaCurve(working, encoding ? encoding : GammaCurvePtr(NeutralGammaCurve::Get())))); }
bool TranscodingGammaCurve::Matches(const GammaCurvePtr& p) const { TranscodingGammaCurve* other = dynamic_cast<TranscodingGammaCurve*>(p.get()); if (!other) return false; return (this->encGamma->Matches(other->encGamma) && this->workGamma->Matches(other->workGamma)); }
bool ScaledGammaCurve::Matches(const GammaCurvePtr& p) const { ScaledGammaCurve* other = dynamic_cast<ScaledGammaCurve*>(p.get()); if (!other) return false; return (this->baseGamma == other->baseGamma) && IsNeutral(this->encFactor / other->encFactor); }
bool PowerLawGammaCurve::Matches(const GammaCurvePtr& p) const { PowerLawGammaCurve* other = dynamic_cast<PowerLawGammaCurve*>(p.get()); if (!other) return false; return IsNeutral(this->encGamma / other->encGamma); }