1#ifndef _RSGBUILTINFUNCTIONS_HPP 2#define _RSGBUILTINFUNCTIONS_HPP 3/*------------------------------------------------------------------------- 4 * drawElements Quality Program Random Shader Generator 5 * ---------------------------------------------------- 6 * 7 * Copyright 2014 The Android Open Source Project 8 * 9 * Licensed under the Apache License, Version 2.0 (the "License"); 10 * you may not use this file except in compliance with the License. 11 * You may obtain a copy of the License at 12 * 13 * http://www.apache.org/licenses/LICENSE-2.0 14 * 15 * Unless required by applicable law or agreed to in writing, software 16 * distributed under the License is distributed on an "AS IS" BASIS, 17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 * See the License for the specific language governing permissions and 19 * limitations under the License. 20 * 21 *//*! 22 * \file 23 * \brief Built-in Functions. 24 *//*--------------------------------------------------------------------*/ 25 26#include "rsgDefs.hpp" 27#include "rsgExpression.hpp" 28#include "rsgUtils.hpp" 29#include "deMath.h" 30 31namespace rsg 32{ 33 34// Template for built-in functions with form "GenType func(GenType val)". 35template <class GetValueRangeWeight, class ComputeValueRange, class Evaluate> 36class UnaryBuiltinVecFunc : public Expression 37{ 38public: 39 UnaryBuiltinVecFunc (GeneratorState& state, const char* function, ConstValueRangeAccess valueRange); 40 virtual ~UnaryBuiltinVecFunc (void); 41 42 Expression* createNextChild (GeneratorState& state); 43 void tokenize (GeneratorState& state, TokenStream& str) const; 44 45 void evaluate (ExecutionContext& execCtx); 46 ExecConstValueAccess getValue (void) const { return m_value.getValue(m_inValueRange.getType()); } 47 48 static float getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange); 49 50private: 51 std::string m_function; 52 ValueRange m_inValueRange; 53 ExecValueStorage m_value; 54 Expression* m_child; 55}; 56 57template <class GetValueRangeWeight, class ComputeValueRange, class Evaluate> 58UnaryBuiltinVecFunc<GetValueRangeWeight, ComputeValueRange, Evaluate>::UnaryBuiltinVecFunc (GeneratorState& state, const char* function, ConstValueRangeAccess valueRange) 59 : m_function (function) 60 , m_inValueRange (valueRange.getType()) 61 , m_child (DE_NULL) 62{ 63 DE_UNREF(state); 64 DE_ASSERT(valueRange.getType().isFloatOrVec()); 65 66 m_value.setStorage(valueRange.getType()); 67 68 // Compute input value range 69 for (int ndx = 0; ndx < m_inValueRange.getType().getNumElements(); ndx++) 70 { 71 ConstValueRangeAccess outRange = valueRange.component(ndx); 72 ValueRangeAccess inRange = m_inValueRange.asAccess().component(ndx); 73 74 ComputeValueRange()(outRange.getMin().asFloat(), outRange.getMax().asFloat(), inRange.getMin().asFloat(), inRange.getMax().asFloat()); 75 } 76} 77 78template <class GetValueRangeWeight, class ComputeValueRange, class Evaluate> 79UnaryBuiltinVecFunc<GetValueRangeWeight, ComputeValueRange, Evaluate>::~UnaryBuiltinVecFunc (void) 80{ 81 delete m_child; 82} 83 84template <class GetValueRangeWeight, class ComputeValueRange, class Evaluate> 85Expression* UnaryBuiltinVecFunc<GetValueRangeWeight, ComputeValueRange, Evaluate>::createNextChild (GeneratorState& state) 86{ 87 if (m_child) 88 return DE_NULL; 89 90 m_child = Expression::createRandom(state, m_inValueRange.asAccess()); 91 return m_child; 92} 93 94template <class GetValueRangeWeight, class ComputeValueRange, class Evaluate> 95void UnaryBuiltinVecFunc<GetValueRangeWeight, ComputeValueRange, Evaluate>::tokenize (GeneratorState& state, TokenStream& str) const 96{ 97 str << Token(m_function.c_str()) << Token::LEFT_PAREN; 98 m_child->tokenize(state, str); 99 str << Token::RIGHT_PAREN; 100} 101 102template <class GetValueRangeWeight, class ComputeValueRange, class Evaluate> 103void UnaryBuiltinVecFunc<GetValueRangeWeight, ComputeValueRange, Evaluate>::evaluate (ExecutionContext& execCtx) 104{ 105 m_child->evaluate(execCtx); 106 107 ExecConstValueAccess srcValue = m_child->getValue(); 108 ExecValueAccess dstValue = m_value.getValue(m_inValueRange.getType()); 109 110 for (int elemNdx = 0; elemNdx < m_inValueRange.getType().getNumElements(); elemNdx++) 111 { 112 ExecConstValueAccess srcComp = srcValue.component(elemNdx); 113 ExecValueAccess dstComp = dstValue.component(elemNdx); 114 115 for (int compNdx = 0; compNdx < EXEC_VEC_WIDTH; compNdx++) 116 dstComp.asFloat(compNdx) = Evaluate()(srcComp.asFloat(compNdx)); 117 } 118} 119 120template <class GetValueRangeWeight, class ComputeValueRange, class Evaluate> 121float UnaryBuiltinVecFunc<GetValueRangeWeight, ComputeValueRange, Evaluate>::getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange) 122{ 123 // \todo [2011-06-14 pyry] Void support? 124 if (!valueRange.getType().isFloatOrVec()) 125 return 0.0f; 126 127 int availableLevels = state.getShaderParameters().maxExpressionDepth - state.getExpressionDepth(); 128 129 if (availableLevels < getConservativeValueExprDepth(state, valueRange) + 1) 130 return 0.0f; 131 132 // Compute value range weight 133 float combinedWeight = 1.0f; 134 for (int elemNdx = 0; elemNdx < valueRange.getType().getNumElements(); elemNdx++) 135 { 136 float elemWeight = GetValueRangeWeight()(valueRange.component(elemNdx).getMin().asFloat(), valueRange.component(elemNdx).getMax().asFloat()); 137 combinedWeight *= elemWeight; 138 } 139 140 return combinedWeight; 141} 142 143// Proxy template. 144template <class C> 145struct GetUnaryBuiltinVecWeight 146{ 147 inline float operator() (float outMin, float outMax) const { return C::getCompWeight(outMin, outMax); } 148}; 149 150template <class C> 151struct ComputeUnaryBuiltinVecRange 152{ 153 inline void operator() (float outMin, float outMax, float& inMin, float& inMax) const { C::computeValueRange(outMin, outMax, inMin, inMax); } 154}; 155 156template <class C> 157struct EvaluateUnaryBuiltinVec 158{ 159 inline float operator() (float inVal) const { return C::evaluateComp(inVal); } 160}; 161 162template <class C> 163class UnaryBuiltinVecTemplateProxy : public UnaryBuiltinVecFunc<GetUnaryBuiltinVecWeight<C>, ComputeUnaryBuiltinVecRange<C>, EvaluateUnaryBuiltinVec<C> > 164{ 165public: 166 UnaryBuiltinVecTemplateProxy (GeneratorState& state, const char* function, ConstValueRangeAccess valueRange) 167 : UnaryBuiltinVecFunc<GetUnaryBuiltinVecWeight<C>, ComputeUnaryBuiltinVecRange<C>, EvaluateUnaryBuiltinVec<C> >(state, function, valueRange) 168 { 169 } 170}; 171 172// Template for trigonometric function group. 173template <class C> 174class UnaryTrigonometricFunc : public UnaryBuiltinVecTemplateProxy<C> 175{ 176public: 177 UnaryTrigonometricFunc (GeneratorState& state, const char* function, ConstValueRangeAccess valueRange) 178 : UnaryBuiltinVecTemplateProxy<C>(state, function, valueRange) 179 { 180 } 181 182 static inline float getCompWeight (float outMin, float outMax) 183 { 184 if (Scalar::min<float>() == outMin || Scalar::max<float>() == outMax) 185 return 1.0f; // Infinite value range, anything goes 186 187 // Transform range 188 float inMin, inMax; 189 if (!C::transformValueRange(outMin, outMax, inMin, inMax)) 190 return 0.0f; // Not possible to transform value range (out of range perhaps) 191 192 // Quantize 193 if (!quantizeFloatRange(inMin, inMax)) 194 return 0.0f; // Not possible to quantize - would cause accuracy issues 195 196 if (outMin == outMax) 197 return 1.0f; // Constant value and passed quantization 198 199 // Evaluate new intersection 200 float intersectionLen = C::evaluateComp(inMax) - C::evaluateComp(inMin); 201 float valRangeLen = outMax - outMin; 202 203 return deFloatMax(0.1f, intersectionLen/valRangeLen); 204 } 205 206 static inline void computeValueRange (float outMin, float outMax, float& inMin, float& inMax) 207 { 208 DE_VERIFY(C::transformValueRange(outMin, outMax, inMin, inMax)); 209 DE_VERIFY(quantizeFloatRange(inMin, inMax)); 210 DE_ASSERT(inMin <= inMax); 211 } 212 213 static float getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange) 214 { 215 if (state.getProgramParameters().trigonometricBaseWeight <= 0.0f) 216 return 0.0f; 217 218 return UnaryBuiltinVecTemplateProxy<C>::getWeight(state, valueRange) * state.getProgramParameters().trigonometricBaseWeight; 219 } 220}; 221 222class SinOp : public UnaryTrigonometricFunc<SinOp> 223{ 224public: 225 SinOp (GeneratorState& state, ConstValueRangeAccess valueRange) 226 : UnaryTrigonometricFunc<SinOp>(state, "sin", valueRange) 227 { 228 } 229 230 static inline bool transformValueRange (float outMin, float outMax, float& inMin, float& inMax) 231 { 232 if (outMax < -1.0f || outMin > 1.0f) 233 return false; 234 235 inMin = (outMin >= -1.0f) ? deFloatAsin(outMin) : -0.5f*DE_PI; 236 inMax = (outMax <= +1.0f) ? deFloatAsin(outMax) : +0.5f*DE_PI; 237 238 return true; 239 } 240 241 static inline float evaluateComp (float inVal) 242 { 243 return deFloatSin(inVal); 244 } 245}; 246 247class CosOp : public UnaryTrigonometricFunc<CosOp> 248{ 249public: 250 CosOp (GeneratorState& state, ConstValueRangeAccess valueRange) 251 : UnaryTrigonometricFunc<CosOp>(state, "cos", valueRange) 252 { 253 } 254 255 static inline bool transformValueRange (float outMin, float outMax, float& inMin, float& inMax) 256 { 257 if (outMax < -1.0f || outMin > 1.0f) 258 return false; 259 260 inMax = (outMin >= -1.0f) ? deFloatAcos(outMin) : +DE_PI; 261 inMin = (outMax <= +1.0f) ? deFloatAcos(outMax) : -DE_PI; 262 263 return true; 264 } 265 266 static inline float evaluateComp (float inVal) 267 { 268 return deFloatCos(inVal); 269 } 270}; 271 272class TanOp : public UnaryTrigonometricFunc<TanOp> 273{ 274public: 275 TanOp (GeneratorState& state, ConstValueRangeAccess valueRange) 276 : UnaryTrigonometricFunc<TanOp>(state, "tan", valueRange) 277 { 278 } 279 280 static inline bool transformValueRange (float outMin, float outMax, float& inMin, float& inMax) 281 { 282 // \note Currently tan() is limited to -4..4 range. Otherwise we will run into accuracy issues 283 const float rangeMin = -4.0f; 284 const float rangeMax = +4.0f; 285 286 if (outMax < rangeMin || outMin > rangeMax) 287 return false; 288 289 inMin = deFloatAtanOver(deFloatMax(outMin, rangeMin)); 290 inMax = deFloatAtanOver(deFloatMin(outMax, rangeMax)); 291 292 return true; 293 } 294 295 static inline float evaluateComp (float inVal) 296 { 297 return deFloatTan(inVal); 298 } 299}; 300 301class AsinOp : public UnaryTrigonometricFunc<AsinOp> 302{ 303public: 304 AsinOp (GeneratorState& state, ConstValueRangeAccess valueRange) 305 : UnaryTrigonometricFunc<AsinOp>(state, "asin", valueRange) 306 { 307 } 308 309 static inline bool transformValueRange (float outMin, float outMax, float& inMin, float& inMax) 310 { 311 const float rangeMin = -DE_PI/2.0f; 312 const float rangeMax = +DE_PI/2.0f; 313 314 if (outMax < rangeMin || outMin > rangeMax) 315 return false; // Out of range 316 317 inMin = deFloatSin(deFloatMax(outMin, rangeMin)); 318 inMax = deFloatSin(deFloatMin(outMax, rangeMax)); 319 320 return true; 321 } 322 323 static inline float evaluateComp (float inVal) 324 { 325 return deFloatAsin(inVal); 326 } 327}; 328 329class AcosOp : public UnaryTrigonometricFunc<AcosOp> 330{ 331public: 332 AcosOp (GeneratorState& state, ConstValueRangeAccess valueRange) 333 : UnaryTrigonometricFunc<AcosOp>(state, "acos", valueRange) 334 { 335 } 336 337 static inline bool transformValueRange (float outMin, float outMax, float& inMin, float& inMax) 338 { 339 const float rangeMin = 0.0f; 340 const float rangeMax = DE_PI; 341 342 if (outMax < rangeMin || outMin > rangeMax) 343 return false; // Out of range 344 345 inMax = deFloatCos(deFloatMax(outMin, rangeMin)); 346 inMin = deFloatCos(deFloatMin(outMax, rangeMax)); 347 348 return true; 349 } 350 351 static inline float evaluateComp (float inVal) 352 { 353 return deFloatAcos(inVal); 354 } 355}; 356 357class AtanOp : public UnaryTrigonometricFunc<AtanOp> 358{ 359public: 360 AtanOp (GeneratorState& state, ConstValueRangeAccess valueRange) 361 : UnaryTrigonometricFunc<AtanOp>(state, "atan", valueRange) 362 { 363 } 364 365 static inline bool transformValueRange (float outMin, float outMax, float& inMin, float& inMax) 366 { 367 // \note For accuracy reasons output range is limited to -1..1 368 const float rangeMin = -1.0f; 369 const float rangeMax = +1.0f; 370 371 if (outMax < rangeMin || outMin > rangeMax) 372 return false; // Out of range 373 374 inMin = deFloatTan(deFloatMax(outMin, rangeMin)); 375 inMax = deFloatTan(deFloatMin(outMax, rangeMax)); 376 377 return true; 378 } 379 380 static inline float evaluateComp (float inVal) 381 { 382 return deFloatAtanOver(inVal); 383 } 384}; 385 386// Template for exponential function group. 387// \todo [2011-07-07 pyry] Shares most of the code with Trigonometric variant.. 388template <class C> 389class UnaryExponentialFunc : public UnaryBuiltinVecTemplateProxy<C> 390{ 391public: 392 UnaryExponentialFunc (GeneratorState& state, const char* function, ConstValueRangeAccess valueRange) 393 : UnaryBuiltinVecTemplateProxy<C>(state, function, valueRange) 394 { 395 } 396 397 static inline float getCompWeight (float outMin, float outMax) 398 { 399 if (Scalar::min<float>() == outMin || Scalar::max<float>() == outMax) 400 return 1.0f; // Infinite value range, anything goes 401 402 // Transform range 403 float inMin, inMax; 404 if (!C::transformValueRange(outMin, outMax, inMin, inMax)) 405 return 0.0f; // Not possible to transform value range (out of range perhaps) 406 407 // Quantize 408 if (!quantizeFloatRange(inMin, inMax)) 409 return 0.0f; // Not possible to quantize - would cause accuracy issues 410 411 if (outMin == outMax) 412 return 1.0f; // Constant value and passed quantization 413 414 // Evaluate new intersection 415 float intersectionLen = C::evaluateComp(inMax) - C::evaluateComp(inMin); 416 float valRangeLen = outMax - outMin; 417 418 return deFloatMax(0.1f, intersectionLen/valRangeLen); 419 } 420 421 static inline void computeValueRange (float outMin, float outMax, float& inMin, float& inMax) 422 { 423 DE_VERIFY(C::transformValueRange(outMin, outMax, inMin, inMax)); 424 DE_VERIFY(quantizeFloatRange(inMin, inMax)); 425 DE_ASSERT(inMin <= inMax); 426 } 427 428 static float getWeight (const GeneratorState& state, ConstValueRangeAccess valueRange) 429 { 430 if (state.getProgramParameters().exponentialBaseWeight <= 0.0f) 431 return 0.0f; 432 433 return UnaryBuiltinVecTemplateProxy<C>::getWeight(state, valueRange) * state.getProgramParameters().exponentialBaseWeight; 434 } 435}; 436 437class ExpOp : public UnaryExponentialFunc<ExpOp> 438{ 439public: 440 ExpOp (GeneratorState& state, ConstValueRangeAccess valueRange) 441 : UnaryExponentialFunc<ExpOp>(state, "exp", valueRange) 442 { 443 } 444 445 static inline bool transformValueRange (float outMin, float outMax, float& inMin, float& inMax) 446 { 447 // Limited due to accuracy reasons, should be 0..+inf 448 const float rangeMin = 0.1f; 449 const float rangeMax = 10.0f; 450 451 if (outMax < rangeMin || outMin > rangeMax) 452 return false; // Out of range 453 454 inMin = deFloatLog(deFloatMax(outMin, rangeMin)); 455 inMax = deFloatLog(deFloatMin(outMax, rangeMax)); 456 457 return true; 458 } 459 460 static inline float evaluateComp (float inVal) 461 { 462 return deFloatExp(inVal); 463 } 464}; 465 466class LogOp : public UnaryExponentialFunc<LogOp> 467{ 468public: 469 LogOp (GeneratorState& state, ConstValueRangeAccess valueRange) 470 : UnaryExponentialFunc<LogOp>(state, "log", valueRange) 471 { 472 } 473 474 static inline bool transformValueRange (float outMin, float outMax, float& inMin, float& inMax) 475 { 476 // Limited due to accuracy reasons, should be -inf..+inf 477 const float rangeMin = 0.1f; 478 const float rangeMax = 6.0f; 479 480 if (outMax < rangeMin || outMin > rangeMax) 481 return false; // Out of range 482 483 inMin = deFloatExp(deFloatMax(outMin, rangeMin)); 484 inMax = deFloatExp(deFloatMin(outMax, rangeMax)); 485 486 return true; 487 } 488 489 static inline float evaluateComp (float inVal) 490 { 491 return deFloatLog(inVal); 492 } 493}; 494 495class Exp2Op : public UnaryExponentialFunc<Exp2Op> 496{ 497public: 498 Exp2Op (GeneratorState& state, ConstValueRangeAccess valueRange) 499 : UnaryExponentialFunc<Exp2Op>(state, "exp2", valueRange) 500 { 501 } 502 503 static inline bool transformValueRange (float outMin, float outMax, float& inMin, float& inMax) 504 { 505 // Limited due to accuracy reasons, should be 0..+inf 506 const float rangeMin = 0.1f; 507 const float rangeMax = 10.0f; 508 509 if (outMax < rangeMin || outMin > rangeMax) 510 return false; // Out of range 511 512 inMin = deFloatLog2(deFloatMax(outMin, rangeMin)); 513 inMax = deFloatLog2(deFloatMin(outMax, rangeMax)); 514 515 return true; 516 } 517 518 static inline float evaluateComp (float inVal) 519 { 520 return deFloatExp2(inVal); 521 } 522}; 523 524class Log2Op : public UnaryExponentialFunc<Log2Op> 525{ 526public: 527 Log2Op (GeneratorState& state, ConstValueRangeAccess valueRange) 528 : UnaryExponentialFunc<Log2Op>(state, "log2", valueRange) 529 { 530 } 531 532 static inline bool transformValueRange (float outMin, float outMax, float& inMin, float& inMax) 533 { 534 // Limited due to accuracy reasons, should be -inf..+inf 535 const float rangeMin = 0.1f; 536 const float rangeMax = 6.0f; 537 538 if (outMax < rangeMin || outMin > rangeMax) 539 return false; // Out of range 540 541 inMin = deFloatExp2(deFloatMax(outMin, rangeMin)); 542 inMax = deFloatExp2(deFloatMin(outMax, rangeMax)); 543 544 return true; 545 } 546 547 static inline float evaluateComp (float inVal) 548 { 549 return deFloatLog2(inVal); 550 } 551}; 552 553class SqrtOp : public UnaryExponentialFunc<SqrtOp> 554{ 555public: 556 SqrtOp (GeneratorState& state, ConstValueRangeAccess valueRange) 557 : UnaryExponentialFunc<SqrtOp>(state, "sqrt", valueRange) 558 { 559 } 560 561 static inline bool transformValueRange (float outMin, float outMax, float& inMin, float& inMax) 562 { 563 // Limited due to accuracy reasons, should be 0..+inf 564 const float rangeMin = 0.0f; 565 const float rangeMax = 4.0f; 566 567 if (outMax < rangeMin || outMin > rangeMax) 568 return false; // Out of range 569 570 inMin = deFloatMax(outMin, rangeMin); 571 inMax = deFloatMin(outMax, rangeMax); 572 573 inMin *= inMin; 574 inMax *= inMax; 575 576 return true; 577 } 578 579 static inline float evaluateComp (float inVal) 580 { 581 return deFloatSqrt(inVal); 582 } 583}; 584 585class InvSqrtOp : public UnaryExponentialFunc<InvSqrtOp> 586{ 587public: 588 InvSqrtOp (GeneratorState& state, ConstValueRangeAccess valueRange) 589 : UnaryExponentialFunc<InvSqrtOp>(state, "inversesqrt", valueRange) 590 { 591 } 592 593 static inline bool transformValueRange (float outMin, float outMax, float& inMin, float& inMax) 594 { 595 // Limited due to accuracy reasons 596 const float rangeMin = 0.4f; 597 const float rangeMax = 3.0f; 598 599 if (outMax < rangeMin || outMin > rangeMax) 600 return false; // Out of range 601 602 inMax = 1.0f/deFloatMax(outMin, rangeMin); 603 inMin = 1.0f/deFloatMin(outMax, rangeMax); 604 605 inMin *= inMin; 606 inMax *= inMax; 607 608 return true; 609 } 610 611 static inline float evaluateComp (float inVal) 612 { 613 return 1.0f/deFloatSqrt(inVal); 614 } 615}; 616 617} // rsg 618 619#endif // _RSGBUILTINFUNCTIONS_HPP 620