You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
855 lines
26 KiB
855 lines
26 KiB
/*------------------------------------------------------------------------- |
|
* 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
|
|
|