| /*------------------------------------------------------------------------- |
| * 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.asAccess()); |
| state.popPrecedence(); |
| return m_rightValueExpr; |
| } |
| else if (m_leftValueExpr == DE_NULL) |
| { |
| state.pushPrecedence(leftPrec); |
| m_leftValueExpr = Expression::createRandom(state, m_leftValueRange.asAccess()); |
| 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-(float)i*scaleStep), dstMin, dstMax) && |
| de::inBounds(aMax*(scale-(float)i*scaleStep), dstMin, dstMax)) |
| bMin = scale-(float)i*scaleStep; |
| |
| if (de::inBounds(aMin*(scale+(float)i*scaleStep), dstMin, dstMax) && |
| de::inBounds(aMax*(scale+(float)i*scaleStep), dstMin, dstMax)) |
| bMax = scale+(float)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 |