1106 lines
34 KiB
C++
1106 lines
34 KiB
C++
/*-------------------------------------------------------------------------
|
|
* 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
|
|
{
|
|
|
|
// CustomAbsOp and CustomBinaryOp are used to resolve float comparision corner case.
|
|
// This error happened when two floats with the same value were compared
|
|
// without using epsilon. If result of this comparisment influenced the
|
|
// output color then result and reference images could differ.
|
|
class CustomAbsOp : public Expression
|
|
{
|
|
public:
|
|
CustomAbsOp (void);
|
|
virtual ~CustomAbsOp (void);
|
|
|
|
void setChild (Expression* expression);
|
|
Expression* createNextChild (GeneratorState& state);
|
|
void tokenize (GeneratorState& state, TokenStream& str) const;
|
|
|
|
void evaluate (ExecutionContext& execCtx);
|
|
ExecConstValueAccess getValue (void) const { return m_value.getValue(m_type); }
|
|
|
|
private:
|
|
std::string m_function;
|
|
VariableType m_type;
|
|
ExecValueStorage m_value;
|
|
Expression* m_child;
|
|
};
|
|
|
|
CustomAbsOp::CustomAbsOp (void)
|
|
: m_function ("abs")
|
|
, m_type (VariableType::TYPE_FLOAT, 1)
|
|
, m_child (DE_NULL)
|
|
{
|
|
m_value.setStorage(m_type);
|
|
}
|
|
|
|
CustomAbsOp::~CustomAbsOp (void)
|
|
{
|
|
delete m_child;
|
|
}
|
|
|
|
void CustomAbsOp::setChild(Expression* expression)
|
|
{
|
|
m_child = expression;
|
|
}
|
|
|
|
Expression* CustomAbsOp::createNextChild (GeneratorState&)
|
|
{
|
|
DE_ASSERT(0);
|
|
return DE_NULL;
|
|
}
|
|
|
|
void CustomAbsOp::tokenize (GeneratorState& state, TokenStream& str) const
|
|
{
|
|
str << Token(m_function.c_str()) << Token::LEFT_PAREN;
|
|
m_child->tokenize(state, str);
|
|
str << Token::RIGHT_PAREN;
|
|
}
|
|
|
|
void CustomAbsOp::evaluate (ExecutionContext& execCtx)
|
|
{
|
|
m_child->evaluate(execCtx);
|
|
|
|
ExecConstValueAccess srcValue = m_child->getValue();
|
|
ExecValueAccess dstValue = m_value.getValue(m_type);
|
|
|
|
for (int elemNdx = 0; elemNdx < m_type.getNumElements(); elemNdx++)
|
|
{
|
|
ExecConstValueAccess srcComp = srcValue.component(elemNdx);
|
|
ExecValueAccess dstComp = dstValue.component(elemNdx);
|
|
|
|
for (int compNdx = 0; compNdx < EXEC_VEC_WIDTH; compNdx++)
|
|
dstComp.asFloat(compNdx) = deFloatAbs(srcComp.asFloat(compNdx));
|
|
}
|
|
}
|
|
|
|
typedef BinaryOp<5, ASSOCIATIVITY_LEFT> CustomBinaryBase;
|
|
|
|
// CustomBinaryOp and CustomAbsOp are used to resolve float comparision corner case.
|
|
// CustomBinaryOp supports addition and substraction as only those functionalities
|
|
// were needed.
|
|
template <typename ComputeValue>
|
|
class CustomBinaryOp: public CustomBinaryBase
|
|
{
|
|
public:
|
|
CustomBinaryOp ();
|
|
virtual ~CustomBinaryOp (void) {}
|
|
|
|
void setLeftValue (Expression* expression);
|
|
void setRightValue (Expression* expression);
|
|
|
|
void evaluate (ExecValueAccess dst, ExecConstValueAccess a, ExecConstValueAccess b);
|
|
};
|
|
|
|
template <typename ComputeValue>
|
|
CustomBinaryOp<ComputeValue>::CustomBinaryOp ()
|
|
: CustomBinaryBase(Token::PLUS)
|
|
{
|
|
// By default add operation is assumed, for every other operation
|
|
// separate constructor specialization should be implemented
|
|
m_type = VariableType(VariableType::TYPE_FLOAT, 1);
|
|
m_value.setStorage(m_type);
|
|
}
|
|
|
|
template <>
|
|
CustomBinaryOp<EvaluateSub>::CustomBinaryOp ()
|
|
: CustomBinaryBase(Token::MINUS)
|
|
{
|
|
// Specialization for substraction
|
|
m_type = VariableType(VariableType::TYPE_FLOAT, 1);
|
|
m_leftValueRange = ValueRange(m_type);
|
|
m_rightValueRange = ValueRange(m_type);
|
|
m_value.setStorage(m_type);
|
|
}
|
|
|
|
template <>
|
|
CustomBinaryOp<EvaluateLessThan>::CustomBinaryOp ()
|
|
: CustomBinaryBase(Token::CMP_LT)
|
|
{
|
|
// Specialization for less_then comparision
|
|
m_type = VariableType(VariableType::TYPE_BOOL, 1);
|
|
VariableType floatType = VariableType(VariableType::TYPE_FLOAT, 1);
|
|
m_leftValueRange = ValueRange(floatType);
|
|
m_rightValueRange = ValueRange(floatType);
|
|
m_value.setStorage(m_type);
|
|
}
|
|
|
|
template <typename ComputeValue>
|
|
void CustomBinaryOp<ComputeValue>::setLeftValue(Expression* expression)
|
|
{
|
|
m_leftValueExpr = expression;
|
|
}
|
|
|
|
template <typename ComputeValue>
|
|
void CustomBinaryOp<ComputeValue>::setRightValue(Expression* expression)
|
|
{
|
|
m_rightValueExpr = expression;
|
|
}
|
|
|
|
template <typename ComputeValue>
|
|
void CustomBinaryOp<ComputeValue>::evaluate(ExecValueAccess dst, ExecConstValueAccess a, ExecConstValueAccess b)
|
|
{
|
|
DE_ASSERT(dst.getType() == a.getType());
|
|
DE_ASSERT(dst.getType() == b.getType());
|
|
DE_ASSERT(dst.getType().getBaseType() == 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) = ComputeValue()(a.component(elemNdx).asFloat(compNdx),b.component(elemNdx).asFloat(compNdx));
|
|
}
|
|
}
|
|
|
|
template <>
|
|
void CustomBinaryOp<EvaluateLessThan>::evaluate(ExecValueAccess dst, ExecConstValueAccess a, ExecConstValueAccess b)
|
|
{
|
|
DE_ASSERT(a.getType() == b.getType());
|
|
DE_ASSERT(dst.getType().getBaseType() == VariableType::TYPE_BOOL);
|
|
|
|
for (int elemNdx = 0; elemNdx < dst.getType().getNumElements(); elemNdx++)
|
|
{
|
|
for (int compNdx = 0; compNdx < EXEC_VEC_WIDTH; compNdx++)
|
|
dst.component(elemNdx).asBool(compNdx) = EvaluateLessThan()(a.component(elemNdx).asFloat(compNdx),b.component(elemNdx).asFloat(compNdx));
|
|
}
|
|
}
|
|
|
|
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
|
|
{
|
|
// Check for corrner cases
|
|
switch (m_operator)
|
|
{
|
|
case Token::CMP_LE:
|
|
{
|
|
// When comparing two floats epsilon should be included
|
|
// to eliminate the risk that we get different results
|
|
// because of precission error
|
|
VariableType floatType(VariableType::TYPE_FLOAT, 1);
|
|
if (m_rightValueRange.getType() == floatType)
|
|
{
|
|
FloatLiteral* epsilonLiteral = new FloatLiteral(0.001f);
|
|
|
|
typedef CustomBinaryOp<EvaluateAdd> CustomAddOp;
|
|
CustomAddOp* addOperation = new CustomAddOp();
|
|
addOperation->setLeftValue(m_rightValueExpr);
|
|
addOperation->setRightValue(epsilonLiteral);
|
|
|
|
// add epsilon to right-hand side
|
|
m_rightValueExpr = addOperation;
|
|
}
|
|
break;
|
|
}
|
|
case Token::CMP_GE:
|
|
{
|
|
// When comparing two floats epsilon should be included
|
|
// to eliminate the risk that we get different results
|
|
// because of precission error
|
|
VariableType floatType(VariableType::TYPE_FLOAT, 1);
|
|
if (m_leftValueRange.getType() == floatType)
|
|
{
|
|
FloatLiteral* epsilonLiteral = new FloatLiteral(0.001f);
|
|
|
|
typedef CustomBinaryOp<EvaluateAdd> CustomAddOp;
|
|
CustomAddOp* addOperation = new CustomAddOp();
|
|
addOperation->setLeftValue(m_leftValueExpr);
|
|
addOperation->setRightValue(epsilonLiteral);
|
|
|
|
// add epsilon to left-hand side
|
|
m_leftValueExpr = addOperation;
|
|
}
|
|
break;
|
|
}
|
|
case Token::CMP_EQ:
|
|
{
|
|
// When comparing two floats epsilon should be included
|
|
// to eliminate the risk that we get different results
|
|
// because of precission error
|
|
VariableType floatType(VariableType::TYPE_FLOAT, 1);
|
|
if (m_leftValueRange.getType() == floatType)
|
|
{
|
|
VariableType boolType(VariableType::TYPE_BOOL, 1);
|
|
const ValueRange boolRange(boolType);
|
|
|
|
ParenOp* parenRight = new ParenOp(state, boolRange);
|
|
parenRight->setChild(m_rightValueExpr);
|
|
|
|
typedef CustomBinaryOp<EvaluateSub> CustomSubOp;
|
|
CustomSubOp* subOperation = new CustomSubOp();
|
|
subOperation->setLeftValue(m_leftValueExpr);
|
|
subOperation->setRightValue(parenRight);
|
|
|
|
CustomAbsOp* absOperation = new CustomAbsOp();
|
|
absOperation->setChild(subOperation);
|
|
FloatLiteral* epsilonLiteral = new FloatLiteral(0.001f);
|
|
|
|
typedef CustomBinaryOp<EvaluateLessThan> CustomLessThanOp;
|
|
CustomLessThanOp* lessOperation = new CustomLessThanOp();
|
|
lessOperation->setLeftValue(absOperation);
|
|
lessOperation->setRightValue(epsilonLiteral);
|
|
|
|
ParenOp* parenOperation = new ParenOp(state, boolRange);
|
|
parenOperation->setChild(lessOperation);
|
|
BoolLiteral* trueLiteral = new BoolLiteral(true);
|
|
|
|
// EQ operation cant be removed so it is replaced with:
|
|
// ((abs(lhs-rhs) < epsilon) == true).
|
|
m_leftValueExpr = parenOperation;
|
|
m_rightValueExpr = trueLiteral;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
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
|