/*------------------------------------------------------------------------- * drawElements Quality Program Random Shader Generator * ---------------------------------------------------- * * Copyright 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *//*! * \file * \brief Binary ops. *//*--------------------------------------------------------------------*/ #include "rsgBinaryOps.hpp" #include "rsgVariableManager.hpp" #include "rsgUtils.hpp" #include "deMath.h" using std::vector; namespace rsg { template <int Precedence, Associativity Assoc> BinaryOp<Precedence, Assoc>::BinaryOp (Token::Type operatorToken) : m_operator (operatorToken) , m_leftValueRange (m_type) , m_rightValueRange (m_type) , m_leftValueExpr (DE_NULL) , m_rightValueExpr (DE_NULL) { } template <int Precedence, Associativity Assoc> BinaryOp<Precedence, Assoc>::~BinaryOp (void) { delete m_leftValueExpr; delete m_rightValueExpr; } template <int Precedence, Associativity Assoc> Expression* BinaryOp<Precedence, Assoc>::createNextChild (GeneratorState& state) { int leftPrec = Assoc == ASSOCIATIVITY_LEFT ? Precedence : Precedence-1; int rightPrec = Assoc == ASSOCIATIVITY_LEFT ? Precedence-1 : Precedence; if (m_rightValueExpr == DE_NULL) { state.pushPrecedence(rightPrec); m_rightValueExpr = Expression::createRandom(state, m_rightValueRange); state.popPrecedence(); return m_rightValueExpr; } else if (m_leftValueExpr == DE_NULL) { state.pushPrecedence(leftPrec); m_leftValueExpr = Expression::createRandom(state, m_leftValueRange); state.popPrecedence(); return m_leftValueExpr; } else return DE_NULL; } template <int Precedence, Associativity Assoc> float BinaryOp<Precedence, Assoc>::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange) { if (state.getPrecedence() < Precedence) return 0.0f; int availableLevels = state.getShaderParameters().maxExpressionDepth - state.getExpressionDepth(); if (valueRange.getType().isVoid()) return availableLevels >= 2 ? unusedValueWeight : 0.0f; if (availableLevels < getConservativeValueExprDepth(state, valueRange) + 1) return 0.0f; return 1.0f; } template <int Precedence, Associativity Assoc> void BinaryOp<Precedence, Assoc>::tokenize (GeneratorState& state, TokenStream& str) const { m_leftValueExpr->tokenize(state, str); str << m_operator; m_rightValueExpr->tokenize(state, str); } template <int Precedence, Associativity Assoc> void BinaryOp<Precedence, Assoc>::evaluate (ExecutionContext& execCtx) { m_leftValueExpr->evaluate(execCtx); m_rightValueExpr->evaluate(execCtx); ExecConstValueAccess leftVal = m_leftValueExpr->getValue(); ExecConstValueAccess rightVal = m_rightValueExpr->getValue(); ExecValueAccess dst = m_value.getValue(m_type); evaluate(dst, leftVal, rightVal); } template <int Precedence, bool Float, bool Int, bool Bool, class ComputeValueRange, class EvaluateComp> BinaryVecOp<Precedence, Float, Int, Bool, ComputeValueRange, EvaluateComp>::BinaryVecOp (GeneratorState& state, Token::Type operatorToken, ConstValueRangeAccess inValueRange) : BinaryOp<Precedence, ASSOCIATIVITY_LEFT>(operatorToken) { ValueRange valueRange = inValueRange; if (valueRange.getType().isVoid()) { int availableLevels = state.getShaderParameters().maxExpressionDepth - state.getExpressionDepth(); vector<VariableType::Type> baseTypes; if (Float) baseTypes.push_back(VariableType::TYPE_FLOAT); if (Int) baseTypes.push_back(VariableType::TYPE_INT); if (Bool) baseTypes.push_back(VariableType::TYPE_BOOL); VariableType::Type baseType = state.getRandom().choose<VariableType::Type>(baseTypes.begin(), baseTypes.end()); int numElements = state.getRandom().getInt(1, availableLevels >= 3 ? 4 : 1); valueRange = ValueRange(VariableType(baseType, numElements)); computeRandomValueRange(state, valueRange.asAccess()); } // Choose type, allocate storage for execution this->m_type = valueRange.getType(); this->m_value.setStorage(this->m_type); // Initialize storage for value ranges this->m_rightValueRange = ValueRange(this->m_type); this->m_leftValueRange = ValueRange(this->m_type); VariableType::Type baseType = this->m_type.getBaseType(); // Compute range for b that satisfies requested value range for (int elemNdx = 0; elemNdx < this->m_type.getNumElements(); elemNdx++) { ConstValueRangeAccess dst = valueRange.asAccess().component(elemNdx); ValueRangeAccess a = this->m_leftValueRange.asAccess().component(elemNdx); // \todo [2011-03-25 pyry] Commutative: randomize inputs ValueRangeAccess b = this->m_rightValueRange.asAccess().component(elemNdx); // Just pass undefined ranges if ((baseType == VariableType::TYPE_FLOAT || baseType == VariableType::TYPE_INT) && isUndefinedValueRange(dst)) { a.getMin() = dst.getMin().value(); b.getMin() = dst.getMin().value(); a.getMax() = dst.getMax().value(); b.getMax() = dst.getMax().value(); continue; } if (baseType == VariableType::TYPE_FLOAT) ComputeValueRange()(state.getRandom(), dst.getMin().asFloat(), dst.getMax().asFloat(), a.getMin().asFloat(), a.getMax().asFloat(), b.getMin().asFloat(), b.getMax().asFloat()); else if (baseType == VariableType::TYPE_INT) ComputeValueRange()(state.getRandom(), dst.getMin().asInt(), dst.getMax().asInt(), a.getMin().asInt(), a.getMax().asInt(), b.getMin().asInt(), b.getMax().asInt()); else { DE_ASSERT(baseType == VariableType::TYPE_BOOL); ComputeValueRange()(state.getRandom(), dst.getMin().asBool(), dst.getMax().asBool(), a.getMin().asBool(), a.getMax().asBool(), b.getMin().asBool(), b.getMax().asBool()); } } } template <int Precedence, bool Float, bool Int, bool Bool, class ComputeValueRange, class EvaluateComp> BinaryVecOp<Precedence, Float, Int, Bool, ComputeValueRange, EvaluateComp>::~BinaryVecOp (void) { } template <int Precedence, bool Float, bool Int, bool Bool, class ComputeValueRange, class EvaluateComp> void BinaryVecOp<Precedence, Float, Int, Bool, ComputeValueRange, EvaluateComp>::evaluate (ExecValueAccess dst, ExecConstValueAccess a, ExecConstValueAccess b) { DE_ASSERT(dst.getType() == a.getType()); DE_ASSERT(dst.getType() == b.getType()); switch (dst.getType().getBaseType()) { case VariableType::TYPE_FLOAT: for (int elemNdx = 0; elemNdx < dst.getType().getNumElements(); elemNdx++) { for (int compNdx = 0; compNdx < EXEC_VEC_WIDTH; compNdx++) dst.component(elemNdx).asFloat(compNdx) = EvaluateComp()(a.component(elemNdx).asFloat(compNdx), b.component(elemNdx).asFloat(compNdx)); } break; case VariableType::TYPE_INT: for (int elemNdx = 0; elemNdx < dst.getType().getNumElements(); elemNdx++) { for (int compNdx = 0; compNdx < EXEC_VEC_WIDTH; compNdx++) dst.component(elemNdx).asInt(compNdx) = EvaluateComp()(a.component(elemNdx).asInt(compNdx), b.component(elemNdx).asInt(compNdx)); } break; default: DE_ASSERT(DE_FALSE); // Invalid type for multiplication } } void ComputeMulRange::operator() (de::Random& rnd, float dstMin, float dstMax, float& aMin, float& aMax, float& bMin, float& bMax) const { const float minScale = 0.25f; const float maxScale = 2.0f; const float subRangeStep = 0.25f; const float scaleStep = 0.25f; float scale = getQuantizedFloat(rnd, minScale, maxScale, scaleStep); float scaledMin = dstMin/scale; float scaledMax = dstMax/scale; // Quantize scaled value range if possible if (!quantizeFloatRange(scaledMin, scaledMax)) { // Fall back to 1.0 as a scale scale = 1.0f; scaledMin = dstMin; scaledMax = dstMax; } float subRangeLen = getQuantizedFloat(rnd, 0.0f, scaledMax-scaledMin, subRangeStep); aMin = scaledMin + getQuantizedFloat(rnd, 0.0f, (scaledMax-scaledMin)-subRangeLen, subRangeStep); aMax = aMin + subRangeLen; // Find scale range bMin = scale; bMax = scale; for (int i = 0; i < 5; i++) { if (de::inBounds(aMin*(scale-i*scaleStep), dstMin, dstMax) && de::inBounds(aMax*(scale-i*scaleStep), dstMin, dstMax)) bMin = scale-i*scaleStep; if (de::inBounds(aMin*(scale+i*scaleStep), dstMin, dstMax) && de::inBounds(aMax*(scale+i*scaleStep), dstMin, dstMax)) bMax = scale+i*scaleStep; } // Negative scale? if (rnd.getBool()) { std::swap(aMin, aMax); std::swap(bMin, bMax); aMin *= -1.0f; aMax *= -1.0f; bMin *= -1.0f; bMax *= -1.0f; } #if defined(DE_DEBUG) const float eps = 0.001f; DE_ASSERT(aMin <= aMax && bMin <= bMax); DE_ASSERT(de::inRange(aMin*bMin, dstMin-eps, dstMax+eps)); DE_ASSERT(de::inRange(aMin*bMax, dstMin-eps, dstMax+eps)); DE_ASSERT(de::inRange(aMax*bMin, dstMin-eps, dstMax+eps)); DE_ASSERT(de::inRange(aMax*bMax, dstMin-eps, dstMax+eps)); #endif } void ComputeMulRange::operator() (de::Random& rnd, int dstMin, int dstMax, int& aMin, int& aMax, int& bMin, int& bMax) const { DE_UNREF(rnd); aMin = dstMin; aMax = dstMax; bMin = 1; bMax = 1; } MulOp::MulOp (GeneratorState& state, ConstValueRangeAccess valueRange) : MulBase(state, Token::MUL, valueRange) { } float MulOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange) { if (valueRange.getType().isVoid() || valueRange.getType().isFloatOrVec() || valueRange.getType().isIntOrVec()) return MulBase::getWeight(state, valueRange); else return 0.0f; } template <typename T> void ComputeAddRange::operator() (de::Random& random, T dstMin, T dstMax, T& aMin, T& aMax, T& bMin, T& bMax) const { struct GetRandom { int operator() (de::Random& rnd, int min, int max) const { return rnd.getInt(min, max); } float operator() (de::Random& rnd, float min, float max) const { return getQuantizedFloat(rnd, min, max, 0.5f); } }; T rangeLen = dstMax-dstMin; T subRangeLen = GetRandom()(random, T(0), rangeLen); T aOffset = GetRandom()(random, T(-8), T(8)); aMin = dstMin+aOffset; aMax = aMin+subRangeLen; bMin = -aOffset; bMax = -aOffset+(rangeLen-subRangeLen); #if defined(DE_DEBUG) T eps = T(0.001); DE_ASSERT(aMin <= aMax && bMin <= bMax); DE_ASSERT(de::inRange(aMin+bMin, dstMin-eps, dstMax+eps)); DE_ASSERT(de::inRange(aMin+bMax, dstMin-eps, dstMax+eps)); DE_ASSERT(de::inRange(aMax+bMin, dstMin-eps, dstMax+eps)); DE_ASSERT(de::inRange(aMax+bMax, dstMin-eps, dstMax+eps)); #endif } template <> void ComputeAddRange::operator()<bool> (de::Random&, bool, bool, bool&, bool&, bool&, bool&) const { DE_ASSERT(DE_FALSE); } AddOp::AddOp (GeneratorState& state, ConstValueRangeAccess valueRange) : AddBase(state, Token::PLUS, valueRange) { } float AddOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange) { if (valueRange.getType().isVoid() || valueRange.getType().isFloatOrVec() || valueRange.getType().isIntOrVec()) return AddBase::getWeight(state, valueRange); else return 0.0f; } template <typename T> void ComputeSubRange::operator() (de::Random& random, T dstMin, T dstMax, T& aMin, T& aMax, T& bMin, T& bMax) const { struct GetRandom { int operator() (de::Random& rnd, int min, int max) const { return rnd.getInt(min, max); } float operator() (de::Random& rnd, float min, float max) const { return getQuantizedFloat(rnd, min, max, 0.5f); } }; T rangeLen = dstMax-dstMin; T subRangeLen = GetRandom()(random, T(0), rangeLen); T aOffset = GetRandom()(random, T(-8), T(8)); aMin = dstMin+aOffset; aMax = aMin+subRangeLen; bMin = aOffset-(rangeLen-subRangeLen); bMax = aOffset; #if defined(DE_DEBUG) T eps = T(0.001); DE_ASSERT(aMin <= aMax && bMin <= bMax); DE_ASSERT(de::inRange(aMin-bMin, dstMin-eps, dstMax+eps)); DE_ASSERT(de::inRange(aMin-bMax, dstMin-eps, dstMax+eps)); DE_ASSERT(de::inRange(aMax-bMin, dstMin-eps, dstMax+eps)); DE_ASSERT(de::inRange(aMax-bMax, dstMin-eps, dstMax+eps)); #endif } template <> void ComputeSubRange::operator()<bool> (de::Random&, bool, bool, bool&, bool&, bool&, bool&) const { DE_ASSERT(DE_FALSE); } SubOp::SubOp (GeneratorState& state, ConstValueRangeAccess valueRange) : SubBase(state, Token::MINUS, valueRange) { } float SubOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange) { if (valueRange.getType().isVoid() || valueRange.getType().isFloatOrVec() || valueRange.getType().isIntOrVec()) return SubBase::getWeight(state, valueRange); else return 0.0f; } template <class ComputeValueRange, class EvaluateComp> RelationalOp<ComputeValueRange, EvaluateComp>::RelationalOp (GeneratorState& state, Token::Type operatorToken, ConstValueRangeAccess inValueRange) : BinaryOp<7, ASSOCIATIVITY_LEFT>(operatorToken) { ValueRange valueRange = inValueRange; if (valueRange.getType().isVoid()) { valueRange = ValueRange(VariableType(VariableType::TYPE_BOOL, 1)); computeRandomValueRange(state, valueRange.asAccess()); } // Choose type, allocate storage for execution this->m_type = valueRange.getType(); this->m_value.setStorage(this->m_type); // Choose random input type VariableType::Type inBaseTypes[] = { VariableType::TYPE_FLOAT, VariableType::TYPE_INT }; VariableType::Type inBaseType = state.getRandom().choose<VariableType::Type>(&inBaseTypes[0], &inBaseTypes[DE_LENGTH_OF_ARRAY(inBaseTypes)]); // Initialize storage for input value ranges this->m_rightValueRange = ValueRange(VariableType(inBaseType, 1)); this->m_leftValueRange = ValueRange(VariableType(inBaseType, 1)); // Compute range for b that satisfies requested value range { bool dstMin = valueRange.getMin().asBool(); bool dstMax = valueRange.getMax().asBool(); ValueRangeAccess a = this->m_leftValueRange.asAccess(); ValueRangeAccess b = this->m_rightValueRange.asAccess(); if (inBaseType == VariableType::TYPE_FLOAT) ComputeValueRange()(state.getRandom(), dstMin, dstMax, a.getMin().asFloat(), a.getMax().asFloat(), b.getMin().asFloat(), b.getMax().asFloat()); else if (inBaseType == VariableType::TYPE_INT) ComputeValueRange()(state.getRandom(), dstMin, dstMax, a.getMin().asInt(), a.getMax().asInt(), b.getMin().asInt(), b.getMax().asInt()); } } template <class ComputeValueRange, class EvaluateComp> RelationalOp<ComputeValueRange, EvaluateComp>::~RelationalOp (void) { } template <class ComputeValueRange, class EvaluateComp> void RelationalOp<ComputeValueRange, EvaluateComp>::evaluate (ExecValueAccess dst, ExecConstValueAccess a, ExecConstValueAccess b) { DE_ASSERT(a.getType() == b.getType()); switch (a.getType().getBaseType()) { case VariableType::TYPE_FLOAT: for (int compNdx = 0; compNdx < EXEC_VEC_WIDTH; compNdx++) dst.asBool(compNdx) = EvaluateComp()(a.asFloat(compNdx), b.asFloat(compNdx)); break; case VariableType::TYPE_INT: for (int compNdx = 0; compNdx < EXEC_VEC_WIDTH; compNdx++) dst.asBool(compNdx) = EvaluateComp()(a.asInt(compNdx), b.asInt(compNdx)); break; default: DE_ASSERT(DE_FALSE); } } template <class ComputeValueRange, class EvaluateComp> float RelationalOp<ComputeValueRange, EvaluateComp>::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange) { if (!state.getProgramParameters().useComparisonOps) return 0.0f; if (valueRange.getType().isVoid() || (valueRange.getType().getBaseType() == VariableType::TYPE_BOOL && valueRange.getType().getNumElements() == 1)) return BinaryOp<7, ASSOCIATIVITY_LEFT>::getWeight(state, valueRange); else return 0.0f; } namespace { template <typename T> T getStep (void); template <> inline float getStep (void) { return 0.25f; } template <> inline int getStep (void) { return 1; } } // anonymous template <typename T> void ComputeLessThanRange::operator () (de::Random& rnd, bool dstMin, bool dstMax, T& aMin, T& aMax, T& bMin, T& bMax) const { struct GetRandom { int operator() (de::Random& random, int min, int max) const { return random.getInt(min, max); } float operator() (de::Random& random, float min, float max) const { return getQuantizedFloat(random, min, max, getStep<float>()); } }; // One random range T rLen = GetRandom()(rnd, T(0), T(8)); T rMin = GetRandom()(rnd, T(-4), T(4)); T rMax = rMin+rLen; if (dstMin == false && dstMax == true) { // Both values are possible, use same range for both inputs aMin = rMin; aMax = rMax; bMin = rMin; bMax = rMax; } else if (dstMin == true && dstMax == true) { // Compute range that is less than rMin..rMax T aLen = GetRandom()(rnd, T(0), T(8)-rLen); aMax = rMin - getStep<T>(); aMin = aMax - aLen; bMin = rMin; bMax = rMax; } else { // Compute range that is greater than or equal to rMin..rMax T aLen = GetRandom()(rnd, T(0), T(8)-rLen); aMin = rMax; aMax = aMin + aLen; bMin = rMin; bMax = rMax; } } LessThanOp::LessThanOp (GeneratorState& state, ConstValueRangeAccess valueRange) : LessThanBase(state, Token::CMP_LT, valueRange) { } float LessThanOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange) { return LessThanBase::getWeight(state, valueRange); } template <typename T> void ComputeLessOrEqualRange::operator () (de::Random& rnd, bool dstMin, bool dstMax, T& aMin, T& aMax, T& bMin, T& bMax) const { struct GetRandom { int operator() (de::Random& random, int min, int max) const { return random.getInt(min, max); } float operator() (de::Random& random, float min, float max) const { return getQuantizedFloat(random, min, max, getStep<float>()); } }; // One random range T rLen = GetRandom()(rnd, T(0), T(8)); T rMin = GetRandom()(rnd, T(-4), T(4)); T rMax = rMin+rLen; if (dstMin == false && dstMax == true) { // Both values are possible, use same range for both inputs aMin = rMin; aMax = rMax; bMin = rMin; bMax = rMax; } else if (dstMin == true && dstMax == true) { // Compute range that is less than or equal to rMin..rMax T aLen = GetRandom()(rnd, T(0), T(8)-rLen); aMax = rMin; aMin = aMax - aLen; bMin = rMin; bMax = rMax; } else { // Compute range that is greater than rMin..rMax T aLen = GetRandom()(rnd, T(0), T(8)-rLen); aMin = rMax + getStep<T>(); aMax = aMin + aLen; bMin = rMin; bMax = rMax; } } LessOrEqualOp::LessOrEqualOp (GeneratorState& state, ConstValueRangeAccess valueRange) : LessOrEqualBase(state, Token::CMP_LE, valueRange) { } float LessOrEqualOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange) { return LessOrEqualBase::getWeight(state, valueRange); } GreaterThanOp::GreaterThanOp (GeneratorState& state, ConstValueRangeAccess valueRange) : GreaterThanBase(state, Token::CMP_GT, valueRange) { } float GreaterThanOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange) { return GreaterThanBase::getWeight(state, valueRange); } GreaterOrEqualOp::GreaterOrEqualOp (GeneratorState& state, ConstValueRangeAccess valueRange) : GreaterOrEqualBase(state, Token::CMP_GE, valueRange) { } float GreaterOrEqualOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange) { return GreaterOrEqualBase::getWeight(state, valueRange); } namespace { template <bool IsEqual, typename T> void computeEqualityValueRange (de::Random& rnd, bool dstMin, bool dstMax, T& aMin, T& aMax, T& bMin, T& bMax) { if (dstMin == false && dstMax == true) ComputeLessThanRange()(rnd, false, true, aMin, aMax, bMin, bMax); else if (IsEqual && dstMin == false) ComputeLessThanRange()(rnd, true, true, aMin, aMax, bMin, bMax); else if (!IsEqual && dstMin == true) ComputeLessThanRange()(rnd, true, true, aMin, aMax, bMin, bMax); else { // Must have exactly same values. struct GetRandom { int operator() (de::Random& random, int min, int max) const { return random.getInt(min, max); } float operator() (de::Random& random, float min, float max) const { return getQuantizedFloat(random, min, max, 0.5f); } }; T val = GetRandom()(rnd, T(-1), T(1)); aMin = val; aMax = val; bMin = val; bMax = val; } } template <> void computeEqualityValueRange<true, bool> (de::Random& rnd, bool dstMin, bool dstMax, bool& aMin, bool& aMax, bool& bMin, bool& bMax) { if (dstMin == false && dstMax == true) { aMin = false; aMax = true; bMin = false; bMax = true; } else if (dstMin == false) { DE_ASSERT(dstMax == false); bool val = rnd.getBool(); aMin = val; aMax = val; bMin = !val; bMax = !val; } else { DE_ASSERT(dstMin == true && dstMax == true); bool val = rnd.getBool(); aMin = val; aMax = val; bMin = val; bMax = val; } } template <> void computeEqualityValueRange<false, bool> (de::Random& rnd, bool dstMin, bool dstMax, bool& aMin, bool& aMax, bool& bMin, bool& bMax) { if (dstMin == false && dstMax == true) computeEqualityValueRange<true>(rnd, dstMin, dstMax, aMin, aMax, bMin, bMax); else computeEqualityValueRange<true>(rnd, !dstMin, !dstMax, aMin, aMax, bMin, bMax); } } // anonymous template <bool IsEqual> EqualityComparisonOp<IsEqual>::EqualityComparisonOp (GeneratorState& state, ConstValueRangeAccess inValueRange) : BinaryOp<8, ASSOCIATIVITY_LEFT>(IsEqual ? Token::CMP_EQ : Token::CMP_NE) { ValueRange valueRange = inValueRange; if (valueRange.getType().isVoid()) { valueRange = ValueRange(VariableType(VariableType::TYPE_BOOL, 1)); computeRandomValueRange(state, valueRange.asAccess()); } // Choose type, allocate storage for execution this->m_type = valueRange.getType(); this->m_value.setStorage(this->m_type); // Choose random input type VariableType::Type inBaseTypes[] = { VariableType::TYPE_FLOAT, VariableType::TYPE_INT }; VariableType::Type inBaseType = state.getRandom().choose<VariableType::Type>(&inBaseTypes[0], &inBaseTypes[DE_LENGTH_OF_ARRAY(inBaseTypes)]); int availableLevels = state.getShaderParameters().maxExpressionDepth - state.getExpressionDepth(); int numElements = state.getRandom().getInt(1, availableLevels >= 3 ? 4 : 1); // Initialize storage for input value ranges this->m_rightValueRange = ValueRange(VariableType(inBaseType, numElements)); this->m_leftValueRange = ValueRange(VariableType(inBaseType, numElements)); // Compute range for b that satisfies requested value range for (int elementNdx = 0; elementNdx < numElements; elementNdx++) { bool dstMin = valueRange.getMin().asBool(); bool dstMax = valueRange.getMax().asBool(); ValueRangeAccess a = this->m_leftValueRange.asAccess().component(elementNdx); ValueRangeAccess b = this->m_rightValueRange.asAccess().component(elementNdx); if (inBaseType == VariableType::TYPE_FLOAT) computeEqualityValueRange<IsEqual>(state.getRandom(), dstMin, dstMax, a.getMin().asFloat(), a.getMax().asFloat(), b.getMin().asFloat(), b.getMax().asFloat()); else if (inBaseType == VariableType::TYPE_INT) computeEqualityValueRange<IsEqual>(state.getRandom(), dstMin, dstMax, a.getMin().asInt(), a.getMax().asInt(), b.getMin().asInt(), b.getMax().asInt()); else { DE_ASSERT(inBaseType == VariableType::TYPE_BOOL); computeEqualityValueRange<IsEqual>(state.getRandom(), dstMin, dstMax, a.getMin().asBool(), a.getMax().asBool(), b.getMin().asBool(), b.getMax().asBool()); } } } template <bool IsEqual> float EqualityComparisonOp<IsEqual>::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange) { if (!state.getProgramParameters().useComparisonOps) return 0.0f; // \todo [2011-06-13 pyry] Weight down cases that would force constant inputs. if (valueRange.getType().isVoid() || (valueRange.getType().getBaseType() == VariableType::TYPE_BOOL && valueRange.getType().getNumElements() == 1)) return BinaryOp<8, ASSOCIATIVITY_LEFT>::getWeight(state, valueRange); else return 0.0f; } namespace { template <bool IsEqual> struct EqualityCompare { template <typename T> static bool compare (T a, T b); static bool combine (bool a, bool b); }; template <> template <typename T> inline bool EqualityCompare<true>::compare (T a, T b) { return a == b; } template <> inline bool EqualityCompare<true>::combine (bool a, bool b) { return a && b; } template <> template <typename T> inline bool EqualityCompare<false>::compare (T a, T b) { return a != b; } template <> inline bool EqualityCompare<false>::combine (bool a, bool b) { return a || b; } } // anonymous template <bool IsEqual> void EqualityComparisonOp<IsEqual>::evaluate (ExecValueAccess dst, ExecConstValueAccess a, ExecConstValueAccess b) { DE_ASSERT(a.getType() == b.getType()); switch (a.getType().getBaseType()) { case VariableType::TYPE_FLOAT: for (int compNdx = 0; compNdx < EXEC_VEC_WIDTH; compNdx++) { bool result = IsEqual ? true : false; for (int elemNdx = 0; elemNdx < a.getType().getNumElements(); elemNdx++) result = EqualityCompare<IsEqual>::combine(result, EqualityCompare<IsEqual>::compare(a.component(elemNdx).asFloat(compNdx), b.component(elemNdx).asFloat(compNdx))); dst.asBool(compNdx) = result; } break; case VariableType::TYPE_INT: for (int compNdx = 0; compNdx < EXEC_VEC_WIDTH; compNdx++) { bool result = IsEqual ? true : false; for (int elemNdx = 0; elemNdx < a.getType().getNumElements(); elemNdx++) result = EqualityCompare<IsEqual>::combine(result, EqualityCompare<IsEqual>::compare(a.component(elemNdx).asInt(compNdx), b.component(elemNdx).asInt(compNdx))); dst.asBool(compNdx) = result; } break; case VariableType::TYPE_BOOL: for (int compNdx = 0; compNdx < EXEC_VEC_WIDTH; compNdx++) { bool result = IsEqual ? true : false; for (int elemNdx = 0; elemNdx < a.getType().getNumElements(); elemNdx++) result = EqualityCompare<IsEqual>::combine(result, EqualityCompare<IsEqual>::compare(a.component(elemNdx).asBool(compNdx), b.component(elemNdx).asBool(compNdx))); dst.asBool(compNdx) = result; } break; default: DE_ASSERT(DE_FALSE); } } EqualOp::EqualOp (GeneratorState& state, ConstValueRangeAccess valueRange) : EqualityComparisonOp<true>(state, valueRange) { } float EqualOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange) { return EqualityComparisonOp<true>::getWeight(state, valueRange); } NotEqualOp::NotEqualOp (GeneratorState& state, ConstValueRangeAccess valueRange) : EqualityComparisonOp<false>(state, valueRange) { } float NotEqualOp::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange) { return EqualityComparisonOp<false>::getWeight(state, valueRange); } } // rsg