| #ifndef _RSGBUILTINFUNCTIONS_HPP |
| #define _RSGBUILTINFUNCTIONS_HPP |
| /*------------------------------------------------------------------------- |
| * 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 Built-in Functions. |
| *//*--------------------------------------------------------------------*/ |
| |
| #include "rsgDefs.hpp" |
| #include "rsgExpression.hpp" |
| #include "rsgUtils.hpp" |
| #include "deMath.h" |
| |
| namespace rsg |
| { |
| |
| // Template for built-in functions with form "GenType func(GenType val)". |
| template <class GetValueRangeWeight, class ComputeValueRange, class Evaluate> |
| class UnaryBuiltinVecFunc : public Expression |
| { |
| public: |
| UnaryBuiltinVecFunc (GeneratorState& state, const char* function, ConstValueRangeAccess valueRange); |
| virtual ~UnaryBuiltinVecFunc (void); |
| |
| Expression* createNextChild (GeneratorState& state); |
| void tokenize (GeneratorState& state, TokenStream& str) const; |
| |
| void evaluate (ExecutionContext& execCtx); |
| ExecConstValueAccess getValue (void) const { return m_value.getValue(m_inValueRange.getType()); } |
| |
| static float getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange); |
| |
| private: |
| std::string m_function; |
| ValueRange m_inValueRange; |
| ExecValueStorage m_value; |
| Expression* m_child; |
| }; |
| |
| template <class GetValueRangeWeight, class ComputeValueRange, class Evaluate> |
| UnaryBuiltinVecFunc<GetValueRangeWeight, ComputeValueRange, Evaluate>::UnaryBuiltinVecFunc (GeneratorState& state, const char* function, ConstValueRangeAccess valueRange) |
| : m_function (function) |
| , m_inValueRange (valueRange.getType()) |
| , m_child (DE_NULL) |
| { |
| DE_UNREF(state); |
| DE_ASSERT(valueRange.getType().isFloatOrVec()); |
| |
| m_value.setStorage(valueRange.getType()); |
| |
| // Compute input value range |
| for (int ndx = 0; ndx < m_inValueRange.getType().getNumElements(); ndx++) |
| { |
| ConstValueRangeAccess outRange = valueRange.component(ndx); |
| ValueRangeAccess inRange = m_inValueRange.asAccess().component(ndx); |
| |
| ComputeValueRange()(outRange.getMin().asFloat(), outRange.getMax().asFloat(), inRange.getMin().asFloat(), inRange.getMax().asFloat()); |
| } |
| } |
| |
| template <class GetValueRangeWeight, class ComputeValueRange, class Evaluate> |
| UnaryBuiltinVecFunc<GetValueRangeWeight, ComputeValueRange, Evaluate>::~UnaryBuiltinVecFunc (void) |
| { |
| delete m_child; |
| } |
| |
| template <class GetValueRangeWeight, class ComputeValueRange, class Evaluate> |
| Expression* UnaryBuiltinVecFunc<GetValueRangeWeight, ComputeValueRange, Evaluate>::createNextChild (GeneratorState& state) |
| { |
| if (m_child) |
| return DE_NULL; |
| |
| m_child = Expression::createRandom(state, m_inValueRange.asAccess()); |
| return m_child; |
| } |
| |
| template <class GetValueRangeWeight, class ComputeValueRange, class Evaluate> |
| void UnaryBuiltinVecFunc<GetValueRangeWeight, ComputeValueRange, Evaluate>::tokenize (GeneratorState& state, TokenStream& str) const |
| { |
| str << Token(m_function.c_str()) << Token::LEFT_PAREN; |
| m_child->tokenize(state, str); |
| str << Token::RIGHT_PAREN; |
| } |
| |
| template <class GetValueRangeWeight, class ComputeValueRange, class Evaluate> |
| void UnaryBuiltinVecFunc<GetValueRangeWeight, ComputeValueRange, Evaluate>::evaluate (ExecutionContext& execCtx) |
| { |
| m_child->evaluate(execCtx); |
| |
| ExecConstValueAccess srcValue = m_child->getValue(); |
| ExecValueAccess dstValue = m_value.getValue(m_inValueRange.getType()); |
| |
| for (int elemNdx = 0; elemNdx < m_inValueRange.getType().getNumElements(); elemNdx++) |
| { |
| ExecConstValueAccess srcComp = srcValue.component(elemNdx); |
| ExecValueAccess dstComp = dstValue.component(elemNdx); |
| |
| for (int compNdx = 0; compNdx < EXEC_VEC_WIDTH; compNdx++) |
| dstComp.asFloat(compNdx) = Evaluate()(srcComp.asFloat(compNdx)); |
| } |
| } |
| |
| template <class GetValueRangeWeight, class ComputeValueRange, class Evaluate> |
| float UnaryBuiltinVecFunc<GetValueRangeWeight, ComputeValueRange, Evaluate>::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange) |
| { |
| // \todo [2011-06-14 pyry] Void support? |
| if (!valueRange.getType().isFloatOrVec()) |
| return 0.0f; |
| |
| int availableLevels = state.getShaderParameters().maxExpressionDepth - state.getExpressionDepth(); |
| |
| if (availableLevels < getConservativeValueExprDepth(state, valueRange) + 1) |
| return 0.0f; |
| |
| // Compute value range weight |
| float combinedWeight = 1.0f; |
| for (int elemNdx = 0; elemNdx < valueRange.getType().getNumElements(); elemNdx++) |
| { |
| float elemWeight = GetValueRangeWeight()(valueRange.component(elemNdx).getMin().asFloat(), valueRange.component(elemNdx).getMax().asFloat()); |
| combinedWeight *= elemWeight; |
| } |
| |
| return combinedWeight; |
| } |
| |
| // Proxy template. |
| template <class C> |
| struct GetUnaryBuiltinVecWeight |
| { |
| inline float operator() (float outMin, float outMax) const { return C::getCompWeight(outMin, outMax); } |
| }; |
| |
| template <class C> |
| struct ComputeUnaryBuiltinVecRange |
| { |
| inline void operator() (float outMin, float outMax, float& inMin, float& inMax) const { C::computeValueRange(outMin, outMax, inMin, inMax); } |
| }; |
| |
| template <class C> |
| struct EvaluateUnaryBuiltinVec |
| { |
| inline float operator() (float inVal) const { return C::evaluateComp(inVal); } |
| }; |
| |
| template <class C> |
| class UnaryBuiltinVecTemplateProxy : public UnaryBuiltinVecFunc<GetUnaryBuiltinVecWeight<C>, ComputeUnaryBuiltinVecRange<C>, EvaluateUnaryBuiltinVec<C> > |
| { |
| public: |
| UnaryBuiltinVecTemplateProxy (GeneratorState& state, const char* function, ConstValueRangeAccess valueRange) |
| : UnaryBuiltinVecFunc<GetUnaryBuiltinVecWeight<C>, ComputeUnaryBuiltinVecRange<C>, EvaluateUnaryBuiltinVec<C> >(state, function, valueRange) |
| { |
| } |
| }; |
| |
| // Template for trigonometric function group. |
| template <class C> |
| class UnaryTrigonometricFunc : public UnaryBuiltinVecTemplateProxy<C> |
| { |
| public: |
| UnaryTrigonometricFunc (GeneratorState& state, const char* function, ConstValueRangeAccess valueRange) |
| : UnaryBuiltinVecTemplateProxy<C>(state, function, valueRange) |
| { |
| } |
| |
| static inline float getCompWeight (float outMin, float outMax) |
| { |
| if (Scalar::min<float>() == outMin || Scalar::max<float>() == outMax) |
| return 1.0f; // Infinite value range, anything goes |
| |
| // Transform range |
| float inMin, inMax; |
| if (!C::transformValueRange(outMin, outMax, inMin, inMax)) |
| return 0.0f; // Not possible to transform value range (out of range perhaps) |
| |
| // Quantize |
| if (!quantizeFloatRange(inMin, inMax)) |
| return 0.0f; // Not possible to quantize - would cause accuracy issues |
| |
| if (outMin == outMax) |
| return 1.0f; // Constant value and passed quantization |
| |
| // Evaluate new intersection |
| float intersectionLen = C::evaluateComp(inMax) - C::evaluateComp(inMin); |
| float valRangeLen = outMax - outMin; |
| |
| return deFloatMax(0.1f, intersectionLen/valRangeLen); |
| } |
| |
| static inline void computeValueRange (float outMin, float outMax, float& inMin, float& inMax) |
| { |
| DE_VERIFY(C::transformValueRange(outMin, outMax, inMin, inMax)); |
| DE_VERIFY(quantizeFloatRange(inMin, inMax)); |
| DE_ASSERT(inMin <= inMax); |
| } |
| |
| static float getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange) |
| { |
| if (state.getProgramParameters().trigonometricBaseWeight <= 0.0f) |
| return 0.0f; |
| |
| return UnaryBuiltinVecTemplateProxy<C>::getWeight(state, valueRange) * state.getProgramParameters().trigonometricBaseWeight; |
| } |
| }; |
| |
| class SinOp : public UnaryTrigonometricFunc<SinOp> |
| { |
| public: |
| SinOp (GeneratorState& state, ConstValueRangeAccess valueRange) |
| : UnaryTrigonometricFunc<SinOp>(state, "sin", valueRange) |
| { |
| } |
| |
| static inline bool transformValueRange (float outMin, float outMax, float& inMin, float& inMax) |
| { |
| if (outMax < -1.0f || outMin > 1.0f) |
| return false; |
| |
| inMin = (outMin >= -1.0f) ? deFloatAsin(outMin) : -0.5f*DE_PI; |
| inMax = (outMax <= +1.0f) ? deFloatAsin(outMax) : +0.5f*DE_PI; |
| |
| return true; |
| } |
| |
| static inline float evaluateComp (float inVal) |
| { |
| return deFloatSin(inVal); |
| } |
| }; |
| |
| class CosOp : public UnaryTrigonometricFunc<CosOp> |
| { |
| public: |
| CosOp (GeneratorState& state, ConstValueRangeAccess valueRange) |
| : UnaryTrigonometricFunc<CosOp>(state, "cos", valueRange) |
| { |
| } |
| |
| static inline bool transformValueRange (float outMin, float outMax, float& inMin, float& inMax) |
| { |
| if (outMax < -1.0f || outMin > 1.0f) |
| return false; |
| |
| inMax = (outMin >= -1.0f) ? deFloatAcos(outMin) : +DE_PI; |
| inMin = (outMax <= +1.0f) ? deFloatAcos(outMax) : -DE_PI; |
| |
| return true; |
| } |
| |
| static inline float evaluateComp (float inVal) |
| { |
| return deFloatCos(inVal); |
| } |
| }; |
| |
| class TanOp : public UnaryTrigonometricFunc<TanOp> |
| { |
| public: |
| TanOp (GeneratorState& state, ConstValueRangeAccess valueRange) |
| : UnaryTrigonometricFunc<TanOp>(state, "tan", valueRange) |
| { |
| } |
| |
| static inline bool transformValueRange (float outMin, float outMax, float& inMin, float& inMax) |
| { |
| // \note Currently tan() is limited to -4..4 range. Otherwise we will run into accuracy issues |
| const float rangeMin = -4.0f; |
| const float rangeMax = +4.0f; |
| |
| if (outMax < rangeMin || outMin > rangeMax) |
| return false; |
| |
| inMin = deFloatAtanOver(deFloatMax(outMin, rangeMin)); |
| inMax = deFloatAtanOver(deFloatMin(outMax, rangeMax)); |
| |
| return true; |
| } |
| |
| static inline float evaluateComp (float inVal) |
| { |
| return deFloatTan(inVal); |
| } |
| }; |
| |
| class AsinOp : public UnaryTrigonometricFunc<AsinOp> |
| { |
| public: |
| AsinOp (GeneratorState& state, ConstValueRangeAccess valueRange) |
| : UnaryTrigonometricFunc<AsinOp>(state, "asin", valueRange) |
| { |
| } |
| |
| static inline bool transformValueRange (float outMin, float outMax, float& inMin, float& inMax) |
| { |
| const float rangeMin = -DE_PI/2.0f; |
| const float rangeMax = +DE_PI/2.0f; |
| |
| if (outMax < rangeMin || outMin > rangeMax) |
| return false; // Out of range |
| |
| inMin = deFloatSin(deFloatMax(outMin, rangeMin)); |
| inMax = deFloatSin(deFloatMin(outMax, rangeMax)); |
| |
| return true; |
| } |
| |
| static inline float evaluateComp (float inVal) |
| { |
| return deFloatAsin(inVal); |
| } |
| }; |
| |
| class AcosOp : public UnaryTrigonometricFunc<AcosOp> |
| { |
| public: |
| AcosOp (GeneratorState& state, ConstValueRangeAccess valueRange) |
| : UnaryTrigonometricFunc<AcosOp>(state, "acos", valueRange) |
| { |
| } |
| |
| static inline bool transformValueRange (float outMin, float outMax, float& inMin, float& inMax) |
| { |
| const float rangeMin = 0.0f; |
| const float rangeMax = DE_PI; |
| |
| if (outMax < rangeMin || outMin > rangeMax) |
| return false; // Out of range |
| |
| inMax = deFloatCos(deFloatMax(outMin, rangeMin)); |
| inMin = deFloatCos(deFloatMin(outMax, rangeMax)); |
| |
| return true; |
| } |
| |
| static inline float evaluateComp (float inVal) |
| { |
| return deFloatAcos(inVal); |
| } |
| }; |
| |
| class AtanOp : public UnaryTrigonometricFunc<AtanOp> |
| { |
| public: |
| AtanOp (GeneratorState& state, ConstValueRangeAccess valueRange) |
| : UnaryTrigonometricFunc<AtanOp>(state, "atan", valueRange) |
| { |
| } |
| |
| static inline bool transformValueRange (float outMin, float outMax, float& inMin, float& inMax) |
| { |
| // \note For accuracy reasons output range is limited to -1..1 |
| const float rangeMin = -1.0f; |
| const float rangeMax = +1.0f; |
| |
| if (outMax < rangeMin || outMin > rangeMax) |
| return false; // Out of range |
| |
| inMin = deFloatTan(deFloatMax(outMin, rangeMin)); |
| inMax = deFloatTan(deFloatMin(outMax, rangeMax)); |
| |
| return true; |
| } |
| |
| static inline float evaluateComp (float inVal) |
| { |
| return deFloatAtanOver(inVal); |
| } |
| }; |
| |
| // Template for exponential function group. |
| // \todo [2011-07-07 pyry] Shares most of the code with Trigonometric variant.. |
| template <class C> |
| class UnaryExponentialFunc : public UnaryBuiltinVecTemplateProxy<C> |
| { |
| public: |
| UnaryExponentialFunc (GeneratorState& state, const char* function, ConstValueRangeAccess valueRange) |
| : UnaryBuiltinVecTemplateProxy<C>(state, function, valueRange) |
| { |
| } |
| |
| static inline float getCompWeight (float outMin, float outMax) |
| { |
| if (Scalar::min<float>() == outMin || Scalar::max<float>() == outMax) |
| return 1.0f; // Infinite value range, anything goes |
| |
| // Transform range |
| float inMin, inMax; |
| if (!C::transformValueRange(outMin, outMax, inMin, inMax)) |
| return 0.0f; // Not possible to transform value range (out of range perhaps) |
| |
| // Quantize |
| if (!quantizeFloatRange(inMin, inMax)) |
| return 0.0f; // Not possible to quantize - would cause accuracy issues |
| |
| if (outMin == outMax) |
| return 1.0f; // Constant value and passed quantization |
| |
| // Evaluate new intersection |
| float intersectionLen = C::evaluateComp(inMax) - C::evaluateComp(inMin); |
| float valRangeLen = outMax - outMin; |
| |
| return deFloatMax(0.1f, intersectionLen/valRangeLen); |
| } |
| |
| static inline void computeValueRange (float outMin, float outMax, float& inMin, float& inMax) |
| { |
| DE_VERIFY(C::transformValueRange(outMin, outMax, inMin, inMax)); |
| DE_VERIFY(quantizeFloatRange(inMin, inMax)); |
| DE_ASSERT(inMin <= inMax); |
| } |
| |
| static float getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange) |
| { |
| if (state.getProgramParameters().exponentialBaseWeight <= 0.0f) |
| return 0.0f; |
| |
| return UnaryBuiltinVecTemplateProxy<C>::getWeight(state, valueRange) * state.getProgramParameters().exponentialBaseWeight; |
| } |
| }; |
| |
| class ExpOp : public UnaryExponentialFunc<ExpOp> |
| { |
| public: |
| ExpOp (GeneratorState& state, ConstValueRangeAccess valueRange) |
| : UnaryExponentialFunc<ExpOp>(state, "exp", valueRange) |
| { |
| } |
| |
| static inline bool transformValueRange (float outMin, float outMax, float& inMin, float& inMax) |
| { |
| // Limited due to accuracy reasons, should be 0..+inf |
| const float rangeMin = 0.1f; |
| const float rangeMax = 10.0f; |
| |
| if (outMax < rangeMin || outMin > rangeMax) |
| return false; // Out of range |
| |
| inMin = deFloatLog(deFloatMax(outMin, rangeMin)); |
| inMax = deFloatLog(deFloatMin(outMax, rangeMax)); |
| |
| return true; |
| } |
| |
| static inline float evaluateComp (float inVal) |
| { |
| return deFloatExp(inVal); |
| } |
| }; |
| |
| class LogOp : public UnaryExponentialFunc<LogOp> |
| { |
| public: |
| LogOp (GeneratorState& state, ConstValueRangeAccess valueRange) |
| : UnaryExponentialFunc<LogOp>(state, "log", valueRange) |
| { |
| } |
| |
| static inline bool transformValueRange (float outMin, float outMax, float& inMin, float& inMax) |
| { |
| // Limited due to accuracy reasons, should be -inf..+inf |
| const float rangeMin = 0.1f; |
| const float rangeMax = 6.0f; |
| |
| if (outMax < rangeMin || outMin > rangeMax) |
| return false; // Out of range |
| |
| inMin = deFloatExp(deFloatMax(outMin, rangeMin)); |
| inMax = deFloatExp(deFloatMin(outMax, rangeMax)); |
| |
| return true; |
| } |
| |
| static inline float evaluateComp (float inVal) |
| { |
| return deFloatLog(inVal); |
| } |
| }; |
| |
| class Exp2Op : public UnaryExponentialFunc<Exp2Op> |
| { |
| public: |
| Exp2Op (GeneratorState& state, ConstValueRangeAccess valueRange) |
| : UnaryExponentialFunc<Exp2Op>(state, "exp2", valueRange) |
| { |
| } |
| |
| static inline bool transformValueRange (float outMin, float outMax, float& inMin, float& inMax) |
| { |
| // Limited due to accuracy reasons, should be 0..+inf |
| const float rangeMin = 0.1f; |
| const float rangeMax = 10.0f; |
| |
| if (outMax < rangeMin || outMin > rangeMax) |
| return false; // Out of range |
| |
| inMin = deFloatLog2(deFloatMax(outMin, rangeMin)); |
| inMax = deFloatLog2(deFloatMin(outMax, rangeMax)); |
| |
| return true; |
| } |
| |
| static inline float evaluateComp (float inVal) |
| { |
| return deFloatExp2(inVal); |
| } |
| }; |
| |
| class Log2Op : public UnaryExponentialFunc<Log2Op> |
| { |
| public: |
| Log2Op (GeneratorState& state, ConstValueRangeAccess valueRange) |
| : UnaryExponentialFunc<Log2Op>(state, "log2", valueRange) |
| { |
| } |
| |
| static inline bool transformValueRange (float outMin, float outMax, float& inMin, float& inMax) |
| { |
| // Limited due to accuracy reasons, should be -inf..+inf |
| const float rangeMin = 0.1f; |
| const float rangeMax = 6.0f; |
| |
| if (outMax < rangeMin || outMin > rangeMax) |
| return false; // Out of range |
| |
| inMin = deFloatExp2(deFloatMax(outMin, rangeMin)); |
| inMax = deFloatExp2(deFloatMin(outMax, rangeMax)); |
| |
| return true; |
| } |
| |
| static inline float evaluateComp (float inVal) |
| { |
| return deFloatLog2(inVal); |
| } |
| }; |
| |
| class SqrtOp : public UnaryExponentialFunc<SqrtOp> |
| { |
| public: |
| SqrtOp (GeneratorState& state, ConstValueRangeAccess valueRange) |
| : UnaryExponentialFunc<SqrtOp>(state, "sqrt", valueRange) |
| { |
| } |
| |
| static inline bool transformValueRange (float outMin, float outMax, float& inMin, float& inMax) |
| { |
| // Limited due to accuracy reasons, should be 0..+inf |
| const float rangeMin = 0.0f; |
| const float rangeMax = 4.0f; |
| |
| if (outMax < rangeMin || outMin > rangeMax) |
| return false; // Out of range |
| |
| inMin = deFloatMax(outMin, rangeMin); |
| inMax = deFloatMin(outMax, rangeMax); |
| |
| inMin *= inMin; |
| inMax *= inMax; |
| |
| return true; |
| } |
| |
| static inline float evaluateComp (float inVal) |
| { |
| return deFloatSqrt(inVal); |
| } |
| }; |
| |
| class InvSqrtOp : public UnaryExponentialFunc<InvSqrtOp> |
| { |
| public: |
| InvSqrtOp (GeneratorState& state, ConstValueRangeAccess valueRange) |
| : UnaryExponentialFunc<InvSqrtOp>(state, "inversesqrt", valueRange) |
| { |
| } |
| |
| static inline bool transformValueRange (float outMin, float outMax, float& inMin, float& inMax) |
| { |
| // Limited due to accuracy reasons |
| const float rangeMin = 0.4f; |
| const float rangeMax = 3.0f; |
| |
| if (outMax < rangeMin || outMin > rangeMax) |
| return false; // Out of range |
| |
| inMax = 1.0f/deFloatMax(outMin, rangeMin); |
| inMin = 1.0f/deFloatMin(outMax, rangeMax); |
| |
| inMin *= inMin; |
| inMax *= inMax; |
| |
| return true; |
| } |
| |
| static inline float evaluateComp (float inVal) |
| { |
| return 1.0f/deFloatSqrt(inVal); |
| } |
| }; |
| |
| } // rsg |
| |
| #endif // _RSGBUILTINFUNCTIONS_HPP |