Merge "Remove broken record_variable_selection test from MR1 must-pass." into lollipo...
[platform/upstream/VK-GL-CTS.git] / framework / randomshaders / rsgBuiltinFunctions.hpp
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
31 namespace rsg
32 {
33
34 // Template for built-in functions with form "GenType func(GenType val)".
35 template <class GetValueRangeWeight, class ComputeValueRange, class Evaluate>
36 class UnaryBuiltinVecFunc : public Expression
37 {
38 public:
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
50 private:
51         std::string                                     m_function;
52         ValueRange                                      m_inValueRange;
53         ExecValueStorage                        m_value;
54         Expression*                                     m_child;
55 };
56
57 template <class GetValueRangeWeight, class ComputeValueRange, class Evaluate>
58 UnaryBuiltinVecFunc<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
78 template <class GetValueRangeWeight, class ComputeValueRange, class Evaluate>
79 UnaryBuiltinVecFunc<GetValueRangeWeight, ComputeValueRange, Evaluate>::~UnaryBuiltinVecFunc (void)
80 {
81         delete m_child;
82 }
83
84 template <class GetValueRangeWeight, class ComputeValueRange, class Evaluate>
85 Expression* 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
94 template <class GetValueRangeWeight, class ComputeValueRange, class Evaluate>
95 void 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
102 template <class GetValueRangeWeight, class ComputeValueRange, class Evaluate>
103 void 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
120 template <class GetValueRangeWeight, class ComputeValueRange, class Evaluate>
121 float 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.
144 template <class C>
145 struct GetUnaryBuiltinVecWeight
146 {
147         inline float operator() (float outMin, float outMax) const { return C::getCompWeight(outMin, outMax); }
148 };
149
150 template <class C>
151 struct ComputeUnaryBuiltinVecRange
152 {
153         inline void operator() (float outMin, float outMax, float& inMin, float& inMax) const { C::computeValueRange(outMin, outMax, inMin, inMax); }
154 };
155
156 template <class C>
157 struct EvaluateUnaryBuiltinVec
158 {
159         inline float operator() (float inVal) const { return C::evaluateComp(inVal); }
160 };
161
162 template <class C>
163 class UnaryBuiltinVecTemplateProxy : public UnaryBuiltinVecFunc<GetUnaryBuiltinVecWeight<C>, ComputeUnaryBuiltinVecRange<C>, EvaluateUnaryBuiltinVec<C> >
164 {
165 public:
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.
173 template <class C>
174 class UnaryTrigonometricFunc : public UnaryBuiltinVecTemplateProxy<C>
175 {
176 public:
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
222 class SinOp : public UnaryTrigonometricFunc<SinOp>
223 {
224 public:
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
247 class CosOp : public UnaryTrigonometricFunc<CosOp>
248 {
249 public:
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
272 class TanOp : public UnaryTrigonometricFunc<TanOp>
273 {
274 public:
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
301 class AsinOp : public UnaryTrigonometricFunc<AsinOp>
302 {
303 public:
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
329 class AcosOp : public UnaryTrigonometricFunc<AcosOp>
330 {
331 public:
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
357 class AtanOp : public UnaryTrigonometricFunc<AtanOp>
358 {
359 public:
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..
388 template <class C>
389 class UnaryExponentialFunc : public UnaryBuiltinVecTemplateProxy<C>
390 {
391 public:
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
437 class ExpOp : public UnaryExponentialFunc<ExpOp>
438 {
439 public:
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
466 class LogOp : public UnaryExponentialFunc<LogOp>
467 {
468 public:
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
495 class Exp2Op : public UnaryExponentialFunc<Exp2Op>
496 {
497 public:
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
524 class Log2Op : public UnaryExponentialFunc<Log2Op>
525 {
526 public:
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
553 class SqrtOp : public UnaryExponentialFunc<SqrtOp>
554 {
555 public:
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
585 class InvSqrtOp : public UnaryExponentialFunc<InvSqrtOp>
586 {
587 public:
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