xref: /aosp_15_r20/external/deqp/framework/randomshaders/rsgExpression.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program Random Shader Generator
3  * ----------------------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Expressions.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "rsgExpression.hpp"
25 #include "rsgVariableManager.hpp"
26 #include "rsgBinaryOps.hpp"
27 #include "rsgBuiltinFunctions.hpp"
28 #include "rsgUtils.hpp"
29 #include "deMath.h"
30 
31 using std::vector;
32 
33 namespace rsg
34 {
35 
36 namespace
37 {
38 
39 class IsReadableEntry
40 {
41 public:
42     typedef ValueEntryIterator<IsReadableEntry> Iterator;
43 
IsReadableEntry(uint32_t exprFlags)44     IsReadableEntry(uint32_t exprFlags) : m_exprFlags(exprFlags)
45     {
46     }
47 
operator ()(const ValueEntry * entry) const48     bool operator()(const ValueEntry *entry) const
49     {
50         if ((m_exprFlags & CONST_EXPR) && (entry->getVariable()->getStorage() != Variable::STORAGE_CONST))
51             return false;
52 
53         return true;
54     }
55 
56 private:
57     uint32_t m_exprFlags;
58 };
59 
60 class IsReadableIntersectingEntry : public IsReadableEntry
61 {
62 public:
63     typedef ValueEntryIterator<IsReadableIntersectingEntry> Iterator;
64 
IsReadableIntersectingEntry(ConstValueRangeAccess valueRange,uint32_t exprFlags)65     IsReadableIntersectingEntry(ConstValueRangeAccess valueRange, uint32_t exprFlags)
66         : IsReadableEntry(exprFlags)
67         , m_valueRange(valueRange)
68     {
69     }
70 
operator ()(const ValueEntry * entry) const71     bool operator()(const ValueEntry *entry) const
72     {
73         if (!IsReadableEntry::operator()(entry))
74             return false;
75 
76         if (entry->getValueRange().getType() != m_valueRange.getType())
77             return false;
78 
79         if (!entry->getValueRange().intersects(m_valueRange))
80             return false;
81 
82         return true;
83     }
84 
85 private:
86     ConstValueRangeAccess m_valueRange;
87 };
88 
89 class IsWritableIntersectingEntry : public IsWritableEntry
90 {
91 public:
92     typedef ValueEntryIterator<IsWritableIntersectingEntry> Iterator;
93 
IsWritableIntersectingEntry(ConstValueRangeAccess valueRange)94     IsWritableIntersectingEntry(ConstValueRangeAccess valueRange) : m_valueRange(valueRange)
95     {
96     }
97 
operator ()(const ValueEntry * entry) const98     bool operator()(const ValueEntry *entry) const
99     {
100         return IsWritableEntry::operator()(entry) && entry->getVariable()->getType() == m_valueRange.getType() &&
101                entry->getValueRange().intersects(m_valueRange);
102     }
103 
104 private:
105     ConstValueRangeAccess m_valueRange;
106 };
107 
108 class IsWritableSupersetEntry : public IsWritableEntry
109 {
110 public:
111     typedef ValueEntryIterator<IsWritableSupersetEntry> Iterator;
112 
IsWritableSupersetEntry(ConstValueRangeAccess valueRange)113     IsWritableSupersetEntry(ConstValueRangeAccess valueRange) : m_valueRange(valueRange)
114     {
115     }
116 
operator ()(const ValueEntry * entry) const117     bool operator()(const ValueEntry *entry) const
118     {
119         return IsWritableEntry()(entry) && entry->getVariable()->getType() == m_valueRange.getType() &&
120                entry->getValueRange().isSupersetOf(m_valueRange);
121     }
122 
123 private:
124     ConstValueRangeAccess m_valueRange;
125 };
126 
127 class IsSamplerEntry
128 {
129 public:
130     typedef ValueEntryIterator<IsSamplerEntry> Iterator;
131 
IsSamplerEntry(VariableType::Type type)132     IsSamplerEntry(VariableType::Type type) : m_type(type)
133     {
134         DE_ASSERT(m_type == VariableType::TYPE_SAMPLER_2D || m_type == VariableType::TYPE_SAMPLER_CUBE);
135     }
136 
operator ()(const ValueEntry * entry) const137     bool operator()(const ValueEntry *entry) const
138     {
139         if (entry->getVariable()->getType() == VariableType(m_type, 1))
140         {
141             DE_ASSERT(entry->getVariable()->getStorage() == Variable::STORAGE_UNIFORM);
142             return true;
143         }
144         else
145             return false;
146     }
147 
148 private:
149     VariableType::Type m_type;
150 };
151 
getWeightedBool(de::Random & random,float trueWeight)152 inline bool getWeightedBool(de::Random &random, float trueWeight)
153 {
154     DE_ASSERT(de::inRange<float>(trueWeight, 0.0f, 1.0f));
155     return (random.getFloat() < trueWeight);
156 }
157 
computeRandomValueRangeForInfElements(GeneratorState & state,ValueRangeAccess valueRange)158 void computeRandomValueRangeForInfElements(GeneratorState &state, ValueRangeAccess valueRange)
159 {
160     const VariableType &type = valueRange.getType();
161     de::Random &rnd          = state.getRandom();
162 
163     switch (type.getBaseType())
164     {
165     case VariableType::TYPE_BOOL:
166         // No need to handle bool as it will be false, true
167         break;
168 
169     case VariableType::TYPE_INT:
170         for (int ndx = 0; ndx < type.getNumElements(); ndx++)
171         {
172             if (valueRange.getMin().component(ndx).asScalar() != Scalar::min<int>() ||
173                 valueRange.getMax().component(ndx).asScalar() != Scalar::max<int>())
174                 continue;
175 
176             const int minIntVal   = -16;
177             const int maxIntVal   = 16;
178             const int maxRangeLen = maxIntVal - minIntVal;
179 
180             int rangeLen = rnd.getInt(0, maxRangeLen);
181             int minVal   = minIntVal + rnd.getInt(0, maxRangeLen - rangeLen);
182             int maxVal   = minVal + rangeLen;
183 
184             valueRange.getMin().component(ndx).asInt() = minVal;
185             valueRange.getMax().component(ndx).asInt() = maxVal;
186         }
187         break;
188 
189     case VariableType::TYPE_FLOAT:
190         for (int ndx = 0; ndx < type.getNumElements(); ndx++)
191         {
192             if (valueRange.getMin().component(ndx).asScalar() != Scalar::min<float>() ||
193                 valueRange.getMax().component(ndx).asScalar() != Scalar::max<float>())
194                 continue;
195 
196             const float step        = 0.1f;
197             const int maxSteps      = 320;
198             const float minFloatVal = -16.0f;
199 
200             int rangeLen = rnd.getInt(0, maxSteps);
201             int minStep  = rnd.getInt(0, maxSteps - rangeLen);
202 
203             float minVal = minFloatVal + step * (float)minStep;
204             float maxVal = minVal + step * (float)rangeLen;
205 
206             valueRange.getMin().component(ndx).asFloat() = minVal;
207             valueRange.getMax().component(ndx).asFloat() = maxVal;
208         }
209         break;
210 
211     default:
212         DE_ASSERT(false);
213         throw Exception("computeRandomValueRangeForInfElements(): unsupported type");
214     }
215 }
216 
setInfiniteRange(ValueRangeAccess valueRange)217 void setInfiniteRange(ValueRangeAccess valueRange)
218 {
219     const VariableType &type = valueRange.getType();
220 
221     switch (type.getBaseType())
222     {
223     case VariableType::TYPE_BOOL:
224         for (int ndx = 0; ndx < type.getNumElements(); ndx++)
225         {
226             valueRange.getMin().component(ndx) = Scalar::min<bool>();
227             valueRange.getMax().component(ndx) = Scalar::max<bool>();
228         }
229         break;
230 
231     case VariableType::TYPE_INT:
232         for (int ndx = 0; ndx < type.getNumElements(); ndx++)
233         {
234             valueRange.getMin().component(ndx) = Scalar::min<int>();
235             valueRange.getMax().component(ndx) = Scalar::max<int>();
236         }
237         break;
238 
239     case VariableType::TYPE_FLOAT:
240         for (int ndx = 0; ndx < type.getNumElements(); ndx++)
241         {
242             valueRange.getMin().component(ndx) = Scalar::min<float>();
243             valueRange.getMax().component(ndx) = Scalar::max<float>();
244         }
245         break;
246 
247     default:
248         DE_ASSERT(false);
249         throw Exception("setInfiniteRange(): unsupported type");
250     }
251 }
252 
canAllocateVariable(const GeneratorState & state,const VariableType & type)253 bool canAllocateVariable(const GeneratorState &state, const VariableType &type)
254 {
255     DE_ASSERT(!type.isVoid());
256 
257     if (state.getExpressionFlags() & NO_VAR_ALLOCATION)
258         return false;
259 
260     if (state.getVariableManager().getNumAllocatedScalars() + type.getScalarSize() >
261         state.getShaderParameters().maxCombinedVariableScalars)
262         return false;
263 
264     return true;
265 }
266 
267 template <class T>
getWeight(const GeneratorState & state,ConstValueRangeAccess valueRange)268 float getWeight(const GeneratorState &state, ConstValueRangeAccess valueRange)
269 {
270     return T::getWeight(state, valueRange);
271 }
272 template <class T>
create(GeneratorState & state,ConstValueRangeAccess valueRange)273 Expression *create(GeneratorState &state, ConstValueRangeAccess valueRange)
274 {
275     return new T(state, valueRange);
276 }
277 
278 struct ExpressionSpec
279 {
280     float (*getWeight)(const GeneratorState &state, ConstValueRangeAccess valueRange);
281     Expression *(*create)(GeneratorState &state, ConstValueRangeAccess valueRange);
282 };
283 
284 static const ExpressionSpec s_expressionSpecs[] = {{getWeight<FloatLiteral>, create<FloatLiteral>},
285                                                    {getWeight<IntLiteral>, create<IntLiteral>},
286                                                    {getWeight<BoolLiteral>, create<BoolLiteral>},
287                                                    {getWeight<ConstructorOp>, create<ConstructorOp>},
288                                                    {getWeight<AssignOp>, create<AssignOp>},
289                                                    {getWeight<VariableRead>, create<VariableRead>},
290                                                    {getWeight<MulOp>, create<MulOp>},
291                                                    {getWeight<AddOp>, create<AddOp>},
292                                                    {getWeight<SubOp>, create<SubOp>},
293                                                    {getWeight<LessThanOp>, create<LessThanOp>},
294                                                    {getWeight<LessOrEqualOp>, create<LessOrEqualOp>},
295                                                    {getWeight<GreaterThanOp>, create<GreaterThanOp>},
296                                                    {getWeight<GreaterOrEqualOp>, create<GreaterOrEqualOp>},
297                                                    {getWeight<EqualOp>, create<EqualOp>},
298                                                    {getWeight<NotEqualOp>, create<NotEqualOp>},
299                                                    {getWeight<SwizzleOp>, create<SwizzleOp>},
300                                                    {getWeight<SinOp>, create<SinOp>},
301                                                    {getWeight<CosOp>, create<CosOp>},
302                                                    {getWeight<TanOp>, create<TanOp>},
303                                                    {getWeight<AsinOp>, create<AsinOp>},
304                                                    {getWeight<AcosOp>, create<AcosOp>},
305                                                    {getWeight<AtanOp>, create<AtanOp>},
306                                                    {getWeight<ExpOp>, create<ExpOp>},
307                                                    {getWeight<LogOp>, create<LogOp>},
308                                                    {getWeight<Exp2Op>, create<Exp2Op>},
309                                                    {getWeight<Log2Op>, create<Log2Op>},
310                                                    {getWeight<SqrtOp>, create<SqrtOp>},
311                                                    {getWeight<InvSqrtOp>, create<InvSqrtOp>},
312                                                    {getWeight<ParenOp>, create<ParenOp>},
313                                                    {getWeight<TexLookup>, create<TexLookup>}};
314 
315 static const ExpressionSpec s_lvalueSpecs[] = {{getWeight<VariableWrite>, create<VariableWrite>}};
316 
317 #if !defined(DE_MAX)
318 #define DE_MAX(a, b) ((b) > (a) ? (b) : (a))
319 #endif
320 
321 enum
322 {
323     MAX_EXPRESSION_SPECS = (int)DE_MAX(DE_LENGTH_OF_ARRAY(s_expressionSpecs), DE_LENGTH_OF_ARRAY(s_lvalueSpecs))
324 };
325 
chooseExpression(GeneratorState & state,const ExpressionSpec * specs,int numSpecs,ConstValueRangeAccess valueRange)326 const ExpressionSpec *chooseExpression(GeneratorState &state, const ExpressionSpec *specs, int numSpecs,
327                                        ConstValueRangeAccess valueRange)
328 {
329     float weights[MAX_EXPRESSION_SPECS];
330 
331     DE_ASSERT(numSpecs <= (int)DE_LENGTH_OF_ARRAY(weights));
332 
333     // Compute weights
334     for (int ndx = 0; ndx < numSpecs; ndx++)
335         weights[ndx] = specs[ndx].getWeight(state, valueRange);
336 
337     // Choose
338     return &state.getRandom().chooseWeighted<const ExpressionSpec &>(specs, specs + numSpecs, weights);
339 }
340 
341 } // namespace
342 
~Expression(void)343 Expression::~Expression(void)
344 {
345 }
346 
createRandom(GeneratorState & state,ConstValueRangeAccess valueRange)347 Expression *Expression::createRandom(GeneratorState &state, ConstValueRangeAccess valueRange)
348 {
349     return chooseExpression(state, s_expressionSpecs, (int)DE_LENGTH_OF_ARRAY(s_expressionSpecs), valueRange)
350         ->create(state, valueRange);
351 }
352 
createRandomLValue(GeneratorState & state,ConstValueRangeAccess valueRange)353 Expression *Expression::createRandomLValue(GeneratorState &state, ConstValueRangeAccess valueRange)
354 {
355     return chooseExpression(state, s_lvalueSpecs, (int)DE_LENGTH_OF_ARRAY(s_lvalueSpecs), valueRange)
356         ->create(state, valueRange);
357 }
358 
FloatLiteral(GeneratorState & state,ConstValueRangeAccess valueRange)359 FloatLiteral::FloatLiteral(GeneratorState &state, ConstValueRangeAccess valueRange)
360     : m_value(VariableType::getScalarType(VariableType::TYPE_FLOAT))
361 {
362     float minVal = -10.0f;
363     float maxVal = +10.0f;
364     float step   = 0.25f;
365 
366     if (valueRange.getType() == VariableType(VariableType::TYPE_FLOAT, 1))
367     {
368         minVal = valueRange.getMin().component(0).asFloat();
369         maxVal = valueRange.getMax().component(0).asFloat();
370 
371         if (Scalar::min<float>() == minVal)
372             minVal = -10.0f;
373 
374         if (Scalar::max<float>() == maxVal)
375             maxVal = +10.0f;
376     }
377 
378     int numSteps = (int)((maxVal - minVal) / step) + 1;
379 
380     const float value      = deFloatClamp(minVal + step * (float)state.getRandom().getInt(0, numSteps), minVal, maxVal);
381     ExecValueAccess access = m_value.getValue(VariableType::getScalarType(VariableType::TYPE_FLOAT));
382 
383     for (int ndx = 0; ndx < EXEC_VEC_WIDTH; ndx++)
384         access.asFloat(ndx) = value;
385 }
386 
FloatLiteral(float customValue)387 FloatLiteral::FloatLiteral(float customValue) : m_value(VariableType::getScalarType(VariableType::TYPE_FLOAT))
388 {
389     // This constructor is required to handle corner case in which comparision
390     // of two same floats produced different results - this was resolved by
391     // adding FloatLiteral containing epsilon to one of values
392     ExecValueAccess access = m_value.getValue(VariableType::getScalarType(VariableType::TYPE_FLOAT));
393 
394     for (int ndx = 0; ndx < EXEC_VEC_WIDTH; ndx++)
395         access.asFloat(ndx) = customValue;
396 }
397 
getWeight(const GeneratorState & state,ConstValueRangeAccess valueRange)398 float FloatLiteral::getWeight(const GeneratorState &state, ConstValueRangeAccess valueRange)
399 {
400     DE_UNREF(state);
401     const VariableType &type = valueRange.getType();
402     if (type == VariableType(VariableType::TYPE_FLOAT, 1))
403     {
404         float minVal = valueRange.getMin().asFloat();
405         float maxVal = valueRange.getMax().asFloat();
406 
407         if (Scalar::min<float>() == minVal && Scalar::max<float>() == maxVal)
408             return 0.1f;
409 
410         // Weight based on value range length
411         float rangeLength = maxVal - minVal;
412 
413         DE_ASSERT(rangeLength >= 0.0f);
414         return deFloatMax(0.1f, 1.0f - rangeLength);
415     }
416     else if (type.isVoid())
417         return unusedValueWeight;
418     else
419         return 0.0f;
420 }
421 
tokenize(GeneratorState & state,TokenStream & str) const422 void FloatLiteral::tokenize(GeneratorState &state, TokenStream &str) const
423 {
424     DE_UNREF(state);
425     str << Token(m_value.getValue(VariableType::getScalarType(VariableType::TYPE_FLOAT)).asFloat(0));
426 }
427 
IntLiteral(GeneratorState & state,ConstValueRangeAccess valueRange)428 IntLiteral::IntLiteral(GeneratorState &state, ConstValueRangeAccess valueRange)
429     : m_value(VariableType::getScalarType(VariableType::TYPE_INT))
430 {
431     int minVal = -16;
432     int maxVal = +16;
433 
434     if (valueRange.getType() == VariableType(VariableType::TYPE_INT, 1))
435     {
436         minVal = valueRange.getMin().component(0).asInt();
437         maxVal = valueRange.getMax().component(0).asInt();
438 
439         if (Scalar::min<int>() == minVal)
440             minVal = -16;
441 
442         if (Scalar::max<int>() == maxVal)
443             maxVal = 16;
444     }
445 
446     int value              = state.getRandom().getInt(minVal, maxVal);
447     ExecValueAccess access = m_value.getValue(VariableType::getScalarType(VariableType::TYPE_INT));
448 
449     for (int ndx = 0; ndx < EXEC_VEC_WIDTH; ndx++)
450         access.asInt(ndx) = value;
451 }
452 
getWeight(const GeneratorState & state,ConstValueRangeAccess valueRange)453 float IntLiteral::getWeight(const GeneratorState &state, ConstValueRangeAccess valueRange)
454 {
455     DE_UNREF(state);
456     const VariableType &type = valueRange.getType();
457     if (type == VariableType(VariableType::TYPE_INT, 1))
458     {
459         int minVal = valueRange.getMin().asInt();
460         int maxVal = valueRange.getMax().asInt();
461 
462         if (Scalar::min<int>() == minVal && Scalar::max<int>() == maxVal)
463             return 0.1f;
464 
465         int rangeLength = maxVal - minVal;
466 
467         DE_ASSERT(rangeLength >= 0);
468         return deFloatMax(0.1f, 1.0f - (float)rangeLength / 4.0f);
469     }
470     else if (type.isVoid())
471         return unusedValueWeight;
472     else
473         return 0.0f;
474 }
475 
tokenize(GeneratorState & state,TokenStream & str) const476 void IntLiteral::tokenize(GeneratorState &state, TokenStream &str) const
477 {
478     DE_UNREF(state);
479     str << Token(m_value.getValue(VariableType::getScalarType(VariableType::TYPE_INT)).asInt(0));
480 }
481 
BoolLiteral(GeneratorState & state,ConstValueRangeAccess valueRange)482 BoolLiteral::BoolLiteral(GeneratorState &state, ConstValueRangeAccess valueRange)
483     : m_value(VariableType::getScalarType(VariableType::TYPE_BOOL))
484 {
485     int minVal = 0;
486     int maxVal = 1;
487 
488     if (valueRange.getType() == VariableType(VariableType::TYPE_BOOL, 1))
489     {
490         minVal = valueRange.getMin().component(0).asBool() ? 1 : 0;
491         maxVal = valueRange.getMax().component(0).asBool() ? 1 : 0;
492     }
493 
494     bool value             = state.getRandom().getInt(minVal, maxVal) == 1;
495     ExecValueAccess access = m_value.getValue(VariableType::getScalarType(VariableType::TYPE_BOOL));
496 
497     for (int ndx = 0; ndx < EXEC_VEC_WIDTH; ndx++)
498         access.asBool(ndx) = value;
499 }
500 
BoolLiteral(bool customValue)501 BoolLiteral::BoolLiteral(bool customValue) : m_value(VariableType::getScalarType(VariableType::TYPE_BOOL))
502 {
503     // This constructor is required to handle corner case in which comparision
504     // of two same floats produced different results - this was resolved by
505     // adding FloatLiteral containing epsilon to one of values
506     ExecValueAccess access = m_value.getValue(VariableType::getScalarType(VariableType::TYPE_BOOL));
507 
508     for (int ndx = 0; ndx < EXEC_VEC_WIDTH; ndx++)
509         access.asBool(ndx) = customValue;
510 }
511 
getWeight(const GeneratorState & state,ConstValueRangeAccess valueRange)512 float BoolLiteral::getWeight(const GeneratorState &state, ConstValueRangeAccess valueRange)
513 {
514     DE_UNREF(state);
515     const VariableType &type = valueRange.getType();
516     if (type == VariableType(VariableType::TYPE_BOOL, 1))
517         return 0.5f;
518     else if (type.isVoid())
519         return unusedValueWeight;
520     else
521         return 0.0f;
522 }
523 
tokenize(GeneratorState & state,TokenStream & str) const524 void BoolLiteral::tokenize(GeneratorState &state, TokenStream &str) const
525 {
526     DE_UNREF(state);
527     str << Token(m_value.getValue(VariableType::getScalarType(VariableType::TYPE_BOOL)).asBool(0));
528 }
529 
530 namespace
531 {
532 
533 // \note int-bool and float-bool conversions handled in a special way.
534 template <typename SrcType, typename DstType>
convert(SrcType src)535 inline DstType convert(SrcType src)
536 {
537     if (Scalar::min<SrcType>() == src)
538         return Scalar::min<DstType>().template as<DstType>();
539     else if (Scalar::max<SrcType>() == src)
540         return Scalar::max<DstType>().template as<DstType>();
541     else
542         return DstType(src);
543 }
544 
545 // According to GLSL ES spec.
546 template <>
convert(float src)547 inline bool convert<float, bool>(float src)
548 {
549     return src != 0.0f;
550 }
551 template <>
convert(int src)552 inline bool convert<int, bool>(int src)
553 {
554     return src != 0;
555 }
556 template <>
convert(bool src)557 inline bool convert<bool, bool>(bool src)
558 {
559     return src;
560 }
561 template <>
convert(bool src)562 inline float convert<bool, float>(bool src)
563 {
564     return src ? 1.0f : 0.0f;
565 }
566 template <>
convert(bool src)567 inline int convert<bool, int>(bool src)
568 {
569     return src ? 1 : 0;
570 }
571 
572 template <>
convert(float src)573 inline int convert<float, int>(float src)
574 {
575     if (Scalar::min<float>() == src)
576         return Scalar::min<int>().as<int>();
577     else if (Scalar::max<float>() == src)
578         return Scalar::max<int>().as<int>();
579     else if (src > 0.0f)
580         return (int)deFloatFloor(src);
581     else
582         return (int)deFloatCeil(src);
583 }
584 
585 template <typename SrcType, typename DstType>
convertValueRange(SrcType srcMin,SrcType srcMax,DstType & dstMin,DstType & dstMax)586 inline void convertValueRange(SrcType srcMin, SrcType srcMax, DstType &dstMin, DstType &dstMax)
587 {
588     dstMin = convert<SrcType, DstType>(srcMin);
589     dstMax = convert<SrcType, DstType>(srcMax);
590 }
591 
592 template <>
convertValueRange(float srcMin,float srcMax,int & dstMin,int & dstMax)593 inline void convertValueRange<float, int>(float srcMin, float srcMax, int &dstMin, int &dstMax)
594 {
595     if (Scalar::min<float>() == srcMin)
596         dstMin = Scalar::min<int>().as<int>();
597     else
598         dstMin = (int)deFloatCeil(srcMin);
599 
600     if (Scalar::max<float>() == srcMax)
601         dstMax = Scalar::max<int>().as<int>();
602     else
603         dstMax = (int)deFloatFloor(srcMax);
604 }
605 
606 template <>
convertValueRange(float srcMin,float srcMax,bool & dstMin,bool & dstMax)607 inline void convertValueRange<float, bool>(float srcMin, float srcMax, bool &dstMin, bool &dstMax)
608 {
609     dstMin = srcMin > 0.0f;
610     dstMax = srcMax > 0.0f;
611 }
612 
613 // \todo [pyry] More special cases?
614 
615 // Returns whether it is possible to convert some SrcType value range to given DstType valueRange
616 template <typename SrcType, typename DstType>
isConversionOk(DstType min,DstType max)617 bool isConversionOk(DstType min, DstType max)
618 {
619     SrcType sMin, sMax;
620     convertValueRange(min, max, sMin, sMax);
621     return sMin <= sMax && de::inRange(convert<SrcType, DstType>(sMin), min, max) &&
622            de::inRange(convert<SrcType, DstType>(sMax), min, max);
623 }
624 
625 // Work-around for non-deterministic float behavior
626 template <>
isConversionOk(float,float)627 bool isConversionOk<float, float>(float, float)
628 {
629     return true;
630 }
631 
632 // \todo [2011-03-26 pyry] Provide this in ValueAccess?
633 template <typename T>
634 T getValueAccessValue(ConstValueAccess access);
635 template <>
getValueAccessValue(ConstValueAccess access)636 inline float getValueAccessValue<float>(ConstValueAccess access)
637 {
638     return access.asFloat();
639 }
640 template <>
getValueAccessValue(ConstValueAccess access)641 inline int getValueAccessValue<int>(ConstValueAccess access)
642 {
643     return access.asInt();
644 }
645 template <>
getValueAccessValue(ConstValueAccess access)646 inline bool getValueAccessValue<bool>(ConstValueAccess access)
647 {
648     return access.asBool();
649 }
650 
651 template <typename T>
652 T &getValueAccessValue(ValueAccess access);
653 template <>
getValueAccessValue(ValueAccess access)654 inline float &getValueAccessValue<float>(ValueAccess access)
655 {
656     return access.asFloat();
657 }
658 template <>
getValueAccessValue(ValueAccess access)659 inline int &getValueAccessValue<int>(ValueAccess access)
660 {
661     return access.asInt();
662 }
663 template <>
getValueAccessValue(ValueAccess access)664 inline bool &getValueAccessValue<bool>(ValueAccess access)
665 {
666     return access.asBool();
667 }
668 
669 template <typename SrcType, typename DstType>
isConversionOk(ConstValueRangeAccess valueRange)670 bool isConversionOk(ConstValueRangeAccess valueRange)
671 {
672     return isConversionOk<SrcType>(getValueAccessValue<DstType>(valueRange.getMin()),
673                                    getValueAccessValue<DstType>(valueRange.getMax()));
674 }
675 
676 template <typename SrcType, typename DstType>
convertValueRangeTempl(ConstValueRangeAccess src,ValueRangeAccess dst)677 void convertValueRangeTempl(ConstValueRangeAccess src, ValueRangeAccess dst)
678 {
679     DstType dMin, dMax;
680     convertValueRange(getValueAccessValue<SrcType>(src.getMin()), getValueAccessValue<SrcType>(src.getMax()), dMin,
681                       dMax);
682     getValueAccessValue<DstType>(dst.getMin()) = dMin;
683     getValueAccessValue<DstType>(dst.getMax()) = dMax;
684 }
685 
686 template <typename SrcType, typename DstType>
convertExecValueTempl(ExecConstValueAccess src,ExecValueAccess dst)687 void convertExecValueTempl(ExecConstValueAccess src, ExecValueAccess dst)
688 {
689     for (int ndx = 0; ndx < EXEC_VEC_WIDTH; ndx++)
690         dst.as<DstType>(ndx) = convert<SrcType, DstType>(src.as<SrcType>(ndx));
691 }
692 
693 typedef bool (*IsConversionOkFunc)(ConstValueRangeAccess);
694 typedef void (*ConvertValueRangeFunc)(ConstValueRangeAccess, ValueRangeAccess);
695 typedef void (*ConvertExecValueFunc)(ExecConstValueAccess, ExecValueAccess);
696 
getBaseTypeConvNdx(VariableType::Type type)697 inline int getBaseTypeConvNdx(VariableType::Type type)
698 {
699     switch (type)
700     {
701     case VariableType::TYPE_FLOAT:
702         return 0;
703     case VariableType::TYPE_INT:
704         return 1;
705     case VariableType::TYPE_BOOL:
706         return 2;
707     default:
708         return -1;
709     }
710 }
711 
isConversionOk(VariableType::Type srcType,VariableType::Type dstType,ConstValueRangeAccess valueRange)712 bool isConversionOk(VariableType::Type srcType, VariableType::Type dstType, ConstValueRangeAccess valueRange)
713 {
714     // [src][dst]
715     static const IsConversionOkFunc convTable[3][3] = {
716         {isConversionOk<float, float>, isConversionOk<float, int>, isConversionOk<float, bool>},
717         {isConversionOk<int, float>, isConversionOk<int, int>, isConversionOk<int, bool>},
718         {isConversionOk<bool, float>, isConversionOk<bool, int>, isConversionOk<bool, bool>}};
719     return convTable[getBaseTypeConvNdx(srcType)][getBaseTypeConvNdx(dstType)](valueRange);
720 }
721 
convertValueRange(ConstValueRangeAccess src,ValueRangeAccess dst)722 void convertValueRange(ConstValueRangeAccess src, ValueRangeAccess dst)
723 {
724     // [src][dst]
725     static const ConvertValueRangeFunc convTable[3][3] = {
726         {convertValueRangeTempl<float, float>, convertValueRangeTempl<float, int>, convertValueRangeTempl<float, bool>},
727         {convertValueRangeTempl<int, float>, convertValueRangeTempl<int, int>, convertValueRangeTempl<int, bool>},
728         {convertValueRangeTempl<bool, float>, convertValueRangeTempl<bool, int>, convertValueRangeTempl<bool, bool>}};
729 
730     convTable[getBaseTypeConvNdx(src.getType().getBaseType())][getBaseTypeConvNdx(dst.getType().getBaseType())](src,
731                                                                                                                 dst);
732 }
733 
convertExecValue(ExecConstValueAccess src,ExecValueAccess dst)734 void convertExecValue(ExecConstValueAccess src, ExecValueAccess dst)
735 {
736     // [src][dst]
737     static const ConvertExecValueFunc convTable[3][3] = {
738         {convertExecValueTempl<float, float>, convertExecValueTempl<float, int>, convertExecValueTempl<float, bool>},
739         {convertExecValueTempl<int, float>, convertExecValueTempl<int, int>, convertExecValueTempl<int, bool>},
740         {convertExecValueTempl<bool, float>, convertExecValueTempl<bool, int>, convertExecValueTempl<bool, bool>}};
741 
742     convTable[getBaseTypeConvNdx(src.getType().getBaseType())][getBaseTypeConvNdx(dst.getType().getBaseType())](src,
743                                                                                                                 dst);
744 }
745 
746 } // namespace
747 
ConstructorOp(GeneratorState & state,ConstValueRangeAccess valueRange)748 ConstructorOp::ConstructorOp(GeneratorState &state, ConstValueRangeAccess valueRange) : m_valueRange(valueRange)
749 {
750     if (valueRange.getType().isVoid())
751     {
752         // Use random range
753         const int maxScalars = 4; // We don't have to be able to assign this value to anywhere
754         m_valueRange         = ValueRange(computeRandomType(state, maxScalars));
755         computeRandomValueRange(state, m_valueRange.asAccess());
756     }
757 
758     // \todo [2011-03-26 pyry] Vector conversions
759     // int remainingDepth = state.getShaderParameters().maxExpressionDepth - state.getExpressionDepth();
760 
761     const VariableType &type    = m_valueRange.getType();
762     VariableType::Type baseType = type.getBaseType();
763     int numScalars              = type.getNumElements();
764     int curScalarNdx            = 0;
765 
766     // \todo [2011-03-26 pyry] Separate op for struct constructors!
767     DE_ASSERT(type.isFloatOrVec() || type.isIntOrVec() || type.isBoolOrVec());
768 
769     bool scalarConversions = state.getProgramParameters().useScalarConversions;
770 
771     while (curScalarNdx < numScalars)
772     {
773         ConstValueRangeAccess comp = m_valueRange.asAccess().component(curScalarNdx);
774 
775         if (scalarConversions)
776         {
777             int numInTypes = 0;
778             VariableType::Type inTypes[3];
779 
780             if (isConversionOk(VariableType::TYPE_FLOAT, baseType, comp))
781                 inTypes[numInTypes++] = VariableType::TYPE_FLOAT;
782             if (isConversionOk(VariableType::TYPE_INT, baseType, comp))
783                 inTypes[numInTypes++] = VariableType::TYPE_INT;
784             if (isConversionOk(VariableType::TYPE_BOOL, baseType, comp))
785                 inTypes[numInTypes++] = VariableType::TYPE_BOOL;
786 
787             DE_ASSERT(numInTypes > 0); // At least nop conversion should be ok
788 
789             // Choose random
790             VariableType::Type inType =
791                 state.getRandom().choose<VariableType::Type>(&inTypes[0], &inTypes[0] + numInTypes);
792 
793             // Compute converted value range
794             ValueRange inValueRange(VariableType(inType, 1));
795             convertValueRange(comp, inValueRange);
796             m_inputValueRanges.push_back(inValueRange);
797 
798             curScalarNdx += 1;
799         }
800         else
801         {
802             m_inputValueRanges.push_back(ValueRange(comp));
803             curScalarNdx += 1;
804         }
805     }
806 }
807 
~ConstructorOp(void)808 ConstructorOp::~ConstructorOp(void)
809 {
810     for (vector<Expression *>::iterator i = m_inputExpressions.begin(); i != m_inputExpressions.end(); i++)
811         delete *i;
812 }
813 
createNextChild(GeneratorState & state)814 Expression *ConstructorOp::createNextChild(GeneratorState &state)
815 {
816     int numChildren   = (int)m_inputExpressions.size();
817     Expression *child = DE_NULL;
818 
819     // \note Created in reverse order!
820     if (numChildren < (int)m_inputValueRanges.size())
821     {
822         const ValueRange &inValueRange = m_inputValueRanges[m_inputValueRanges.size() - 1 - numChildren];
823         child                          = Expression::createRandom(state, inValueRange);
824         try
825         {
826             m_inputExpressions.push_back(child);
827         }
828         catch (const std::exception &)
829         {
830             delete child;
831             throw;
832         }
833     }
834 
835     return child;
836 }
837 
getWeight(const GeneratorState & state,ConstValueRangeAccess valueRange)838 float ConstructorOp::getWeight(const GeneratorState &state, ConstValueRangeAccess valueRange)
839 {
840     if (valueRange.getType().isVoid())
841         return unusedValueWeight;
842 
843     if (!valueRange.getType().isFloatOrVec() && !valueRange.getType().isIntOrVec() &&
844         !valueRange.getType().isBoolOrVec())
845         return 0.0f;
846 
847     if (state.getExpressionDepth() + getTypeConstructorDepth(valueRange.getType()) >
848         state.getShaderParameters().maxExpressionDepth)
849         return 0.0f;
850 
851     return 1.0f;
852 }
853 
tokenize(GeneratorState & state,TokenStream & str) const854 void ConstructorOp::tokenize(GeneratorState &state, TokenStream &str) const
855 {
856     const VariableType &type = m_valueRange.getType();
857     DE_ASSERT(type.getPrecision() == VariableType::PRECISION_NONE);
858     type.tokenizeShortType(str);
859 
860     str << Token::LEFT_PAREN;
861 
862     for (vector<Expression *>::const_reverse_iterator i = m_inputExpressions.rbegin(); i != m_inputExpressions.rend();
863          i++)
864     {
865         if (i != m_inputExpressions.rbegin())
866             str << Token::COMMA;
867         (*i)->tokenize(state, str);
868     }
869 
870     str << Token::RIGHT_PAREN;
871 }
872 
evaluate(ExecutionContext & evalCtx)873 void ConstructorOp::evaluate(ExecutionContext &evalCtx)
874 {
875     // Evaluate children
876     for (vector<Expression *>::reverse_iterator i = m_inputExpressions.rbegin(); i != m_inputExpressions.rend(); i++)
877         (*i)->evaluate(evalCtx);
878 
879     // Compute value
880     const VariableType &type = m_valueRange.getType();
881     m_value.setStorage(type);
882 
883     ExecValueAccess dst = m_value.getValue(type);
884     int curScalarNdx    = 0;
885 
886     for (vector<Expression *>::reverse_iterator i = m_inputExpressions.rbegin(); i != m_inputExpressions.rend(); i++)
887     {
888         ExecConstValueAccess src = (*i)->getValue();
889 
890         for (int elemNdx = 0; elemNdx < src.getType().getNumElements(); elemNdx++)
891             convertExecValue(src.component(elemNdx), dst.component(curScalarNdx++));
892     }
893 }
894 
AssignOp(GeneratorState & state,ConstValueRangeAccess valueRange)895 AssignOp::AssignOp(GeneratorState &state, ConstValueRangeAccess valueRange)
896     : m_valueRange(valueRange)
897     , m_lvalueExpr(DE_NULL)
898     , m_rvalueExpr(DE_NULL)
899 {
900     if (m_valueRange.getType().isVoid())
901     {
902         // Compute random value range
903         int maxScalars = state.getShaderParameters().maxCombinedVariableScalars -
904                          state.getVariableManager().getNumAllocatedScalars();
905         bool useRandomRange = !state.getVariableManager().hasEntry<IsWritableEntry>() ||
906                               ((maxScalars > 0) && getWeightedBool(state.getRandom(), 0.1f));
907 
908         if (useRandomRange)
909         {
910             DE_ASSERT(maxScalars > 0);
911             m_valueRange = ValueRange(computeRandomType(state, maxScalars));
912             computeRandomValueRange(state, m_valueRange.asAccess());
913         }
914         else
915         {
916             // Use value range from random entry
917             // \todo [2011-02-28 pyry] Give lower weight to entries without range? Choose subtype range?
918             const ValueEntry *entry =
919                 state.getRandom().choose<const ValueEntry *>(state.getVariableManager().getBegin<IsWritableEntry>(),
920                                                              state.getVariableManager().getEnd<IsWritableEntry>());
921             m_valueRange = ValueRange(entry->getValueRange());
922 
923             computeRandomValueRangeForInfElements(state, m_valueRange.asAccess());
924 
925             DE_ASSERT(state.getVariableManager().hasEntry(IsWritableIntersectingEntry(m_valueRange.asAccess())));
926         }
927     }
928 
929     IsWritableIntersectingEntry::Iterator first =
930         state.getVariableManager().getBegin(IsWritableIntersectingEntry(m_valueRange.asAccess()));
931     IsWritableIntersectingEntry::Iterator end =
932         state.getVariableManager().getEnd(IsWritableIntersectingEntry(m_valueRange.asAccess()));
933 
934     bool possiblyCreateVar = canAllocateVariable(state, m_valueRange.getType()) &&
935                              (first == end || getWeightedBool(state.getRandom(), 0.5f));
936 
937     if (!possiblyCreateVar)
938     {
939         // Find all possible valueranges matching given type and intersecting with valuerange
940         // \todo [pyry] Actually collect all ValueRanges, currently operates only on whole variables
941         DE_ASSERT(first != end);
942 
943         // Try to select one closest to given range but bigger (eg. superset)
944         bool supersetExists = false;
945         for (IsWritableIntersectingEntry::Iterator i = first; i != end; i++)
946         {
947             if ((*i)->getValueRange().isSupersetOf(m_valueRange.asAccess()))
948             {
949                 supersetExists = true;
950                 break;
951             }
952         }
953 
954         if (!supersetExists)
955         {
956             // Select some other range and compute intersection
957             // \todo [2011-02-03 pyry] Use some heuristics to select the range?
958             ConstValueRangeAccess selectedRange =
959                 state.getRandom().choose<const ValueEntry *>(first, end)->getValueRange();
960 
961             ValueRange::computeIntersection(m_valueRange.asAccess(), m_valueRange.asAccess(), selectedRange);
962         }
963     }
964 }
965 
~AssignOp(void)966 AssignOp::~AssignOp(void)
967 {
968     delete m_lvalueExpr;
969     delete m_rvalueExpr;
970 }
971 
getWeight(const GeneratorState & state,ConstValueRangeAccess valueRange)972 float AssignOp::getWeight(const GeneratorState &state, ConstValueRangeAccess valueRange)
973 {
974     if (!valueRange.getType().isVoid() && !canAllocateVariable(state, valueRange.getType()) &&
975         !state.getVariableManager().hasEntry(IsWritableIntersectingEntry(valueRange)))
976         return 0.0f; // Would require creating a new variable
977 
978     if (!valueRange.getType().isVoid() &&
979         state.getExpressionDepth() + getTypeConstructorDepth(valueRange.getType()) + 1 >=
980             state.getShaderParameters().maxExpressionDepth)
981         return 0.0f;
982 
983     if (valueRange.getType().isVoid() && !state.getVariableManager().hasEntry<IsWritableEntry>() &&
984         state.getVariableManager().getNumAllocatedScalars() >= state.getShaderParameters().maxCombinedVariableScalars)
985         return 0.0f; // Can not allocate a new entry
986 
987     if (state.getExpressionDepth() == 0)
988         return 4.0f;
989     else
990         return 0.0f; // \todo [pyry] Fix assign ops
991 }
992 
createNextChild(GeneratorState & state)993 Expression *AssignOp::createNextChild(GeneratorState &state)
994 {
995     if (m_lvalueExpr == DE_NULL)
996     {
997         // Construct lvalue
998         // \todo [2011-03-14 pyry] Proper l-value generation:
999         //  - pure L-value part is generated first
1000         //  - variable valuerange is made unbound
1001         //  - R-value is generated
1002         //  - R-values in L-value are generated
1003         m_lvalueExpr = Expression::createRandomLValue(state, m_valueRange.asAccess());
1004         return m_lvalueExpr;
1005     }
1006     else if (m_rvalueExpr == DE_NULL)
1007     {
1008         // Construct value expr
1009         m_rvalueExpr = Expression::createRandom(state, m_valueRange.asAccess());
1010         return m_rvalueExpr;
1011     }
1012     else
1013         return DE_NULL;
1014 }
1015 
tokenize(GeneratorState & state,TokenStream & str) const1016 void AssignOp::tokenize(GeneratorState &state, TokenStream &str) const
1017 {
1018     m_lvalueExpr->tokenize(state, str);
1019     str << Token::EQUAL;
1020     m_rvalueExpr->tokenize(state, str);
1021 }
1022 
evaluate(ExecutionContext & evalCtx)1023 void AssignOp::evaluate(ExecutionContext &evalCtx)
1024 {
1025     // Evaluate l-value
1026     m_lvalueExpr->evaluate(evalCtx);
1027 
1028     // Evaluate value
1029     m_rvalueExpr->evaluate(evalCtx);
1030     m_value.setStorage(m_valueRange.getType());
1031     m_value.getValue(m_valueRange.getType()) = m_rvalueExpr->getValue().value();
1032 
1033     // Assign
1034     assignMasked(m_lvalueExpr->getLValue(), m_value.getValue(m_valueRange.getType()), evalCtx.getExecutionMask());
1035 }
1036 
1037 namespace
1038 {
1039 
isShaderInOutSupportedType(const VariableType & type)1040 inline bool isShaderInOutSupportedType(const VariableType &type)
1041 {
1042     // \todo [2011-03-11 pyry] Float arrays, structs?
1043     return type.getBaseType() == VariableType::TYPE_FLOAT;
1044 }
1045 
allocateNewVariable(GeneratorState & state,ConstValueRangeAccess valueRange)1046 Variable *allocateNewVariable(GeneratorState &state, ConstValueRangeAccess valueRange)
1047 {
1048     Variable *variable = state.getVariableManager().allocate(valueRange.getType());
1049 
1050     // Update value range
1051     state.getVariableManager().setValue(variable, valueRange);
1052 
1053     // Random storage \todo [pyry] Check that scalar count in uniform/input classes is not exceeded
1054     static const Variable::Storage storages[] = {Variable::STORAGE_CONST, Variable::STORAGE_UNIFORM,
1055                                                  Variable::STORAGE_LOCAL, Variable::STORAGE_SHADER_IN};
1056     float weights[DE_LENGTH_OF_ARRAY(storages)];
1057 
1058     // Dynamic vs. constant weight.
1059     float dynWeight = computeDynamicRangeWeight(valueRange);
1060     int numScalars  = valueRange.getType().getScalarSize();
1061     bool uniformOk  = state.getVariableManager().getNumAllocatedUniformScalars() + numScalars <=
1062                      state.getShaderParameters().maxUniformScalars;
1063     bool shaderInOk = isShaderInOutSupportedType(valueRange.getType()) &&
1064                       (state.getVariableManager().getNumAllocatedShaderInVariables() + NUM_RESERVED_SHADER_INPUTS <
1065                        state.getShaderParameters().maxInputVariables);
1066 
1067     weights[0] = de::max(1.0f - dynWeight, 0.1f);
1068     weights[1] = uniformOk ? dynWeight * 0.5f : 0.0f;
1069     weights[2] = dynWeight;
1070     weights[3] = shaderInOk ? dynWeight * 2.0f : 0.0f;
1071 
1072     state.getVariableManager().setStorage(variable,
1073                                           state.getRandom().chooseWeighted<Variable::Storage>(
1074                                               &storages[0], &storages[DE_LENGTH_OF_ARRAY(storages)], &weights[0]));
1075 
1076     return variable;
1077 }
1078 
combineWeight(float curCombinedWeight,float partialWeight)1079 inline float combineWeight(float curCombinedWeight, float partialWeight)
1080 {
1081     return curCombinedWeight * partialWeight;
1082 }
1083 
computeEntryReadWeight(ConstValueRangeAccess entryValueRange,ConstValueRangeAccess readValueRange)1084 float computeEntryReadWeight(ConstValueRangeAccess entryValueRange, ConstValueRangeAccess readValueRange)
1085 {
1086     const VariableType &type = entryValueRange.getType();
1087     DE_ASSERT(type == readValueRange.getType());
1088 
1089     float weight = 1.0f;
1090 
1091     switch (type.getBaseType())
1092     {
1093     case VariableType::TYPE_FLOAT:
1094     {
1095         for (int elemNdx = 0; elemNdx < type.getNumElements(); elemNdx++)
1096         {
1097             float entryMin = entryValueRange.component(elemNdx).getMin().asFloat();
1098             float entryMax = entryValueRange.component(elemNdx).getMax().asFloat();
1099             float readMin  = readValueRange.component(elemNdx).getMin().asFloat();
1100             float readMax  = readValueRange.component(elemNdx).getMax().asFloat();
1101 
1102             // Check for -inf..inf ranges - they don't bring down the weight.
1103             if (Scalar::min<float>() == entryMin && Scalar::max<float>() == entryMax)
1104                 continue;
1105 
1106             // Intersection to entry value range length ratio.
1107             float intersectionMin = deFloatMax(entryMin, readMin);
1108             float intersectionMax = deFloatMin(entryMax, readMax);
1109             float entryRangeLen   = entryMax - entryMin;
1110             float readRangeLen    = readMax - readMin;
1111             float intersectionLen = intersectionMax - intersectionMin;
1112             float entryRatio      = (entryRangeLen > 0.0f) ? (intersectionLen / entryRangeLen) : 1.0f;
1113             float readRatio       = (readRangeLen > 0.0f) ? (intersectionLen / readRangeLen) : 1.0f;
1114             float elementWeight   = 0.5f * readRatio + 0.5f * entryRatio;
1115 
1116             weight = combineWeight(weight, elementWeight);
1117         }
1118         break;
1119     }
1120 
1121     case VariableType::TYPE_INT:
1122     {
1123         for (int elemNdx = 0; elemNdx < type.getNumElements(); elemNdx++)
1124         {
1125             int entryMin = entryValueRange.component(elemNdx).getMin().asInt();
1126             int entryMax = entryValueRange.component(elemNdx).getMax().asInt();
1127             int readMin  = readValueRange.component(elemNdx).getMin().asInt();
1128             int readMax  = readValueRange.component(elemNdx).getMax().asInt();
1129 
1130             // Check for -inf..inf ranges - they don't bring down the weight.
1131             if (Scalar::min<int>() == entryMin && Scalar::max<int>() == entryMax)
1132                 continue;
1133 
1134             // Intersection to entry value range length ratio.
1135             int intersectionMin     = deMax32(entryMin, readMin);
1136             int intersectionMax     = deMin32(entryMax, readMax);
1137             int64_t entryRangeLen   = (int64_t)entryMax - (int64_t)entryMin;
1138             int64_t readRangeLen    = (int64_t)readMax - (int64_t)readMin;
1139             int64_t intersectionLen = (int64_t)intersectionMax - (int64_t)intersectionMin;
1140             float entryRatio        = (entryRangeLen > 0) ? ((float)intersectionLen / (float)entryRangeLen) : 1.0f;
1141             float readRatio         = (readRangeLen > 0) ? ((float)intersectionLen / (float)readRangeLen) : 1.0f;
1142             float elementWeight     = 0.5f * readRatio + 0.5f * entryRatio;
1143 
1144             weight = combineWeight(weight, elementWeight);
1145         }
1146         break;
1147     }
1148 
1149     case VariableType::TYPE_BOOL:
1150     {
1151         // \todo
1152         break;
1153     }
1154 
1155     case VariableType::TYPE_ARRAY:
1156     case VariableType::TYPE_STRUCT:
1157 
1158     default:
1159         TCU_FAIL("Unsupported type");
1160     }
1161 
1162     return deFloatMax(weight, 0.01f);
1163 }
1164 
1165 } // namespace
1166 
VariableRead(GeneratorState & state,ConstValueRangeAccess valueRange)1167 VariableRead::VariableRead(GeneratorState &state, ConstValueRangeAccess valueRange)
1168 {
1169     if (valueRange.getType().isVoid())
1170     {
1171         IsReadableEntry filter = IsReadableEntry(state.getExpressionFlags());
1172         int maxScalars         = state.getShaderParameters().maxCombinedVariableScalars -
1173                          state.getVariableManager().getNumAllocatedScalars();
1174         bool useRandomRange = !state.getVariableManager().hasEntry(filter) ||
1175                               ((maxScalars > 0) && getWeightedBool(state.getRandom(), 0.5f));
1176 
1177         if (useRandomRange)
1178         {
1179             // Allocate a new variable
1180             DE_ASSERT(maxScalars > 0);
1181             ValueRange newVarRange(computeRandomType(state, maxScalars));
1182             computeRandomValueRange(state, newVarRange.asAccess());
1183 
1184             m_variable = allocateNewVariable(state, newVarRange.asAccess());
1185         }
1186         else
1187         {
1188             // Use random entry \todo [pyry] Handle -inf..inf ranges?
1189             m_variable = state.getRandom()
1190                              .choose<const ValueEntry *>(state.getVariableManager().getBegin(filter),
1191                                                          state.getVariableManager().getEnd(filter))
1192                              ->getVariable();
1193         }
1194     }
1195     else
1196     {
1197         // Find variable that has value range that intersects with given range
1198         IsReadableIntersectingEntry::Iterator first =
1199             state.getVariableManager().getBegin(IsReadableIntersectingEntry(valueRange, state.getExpressionFlags()));
1200         IsReadableIntersectingEntry::Iterator end =
1201             state.getVariableManager().getEnd(IsReadableIntersectingEntry(valueRange, state.getExpressionFlags()));
1202 
1203         const float createOnReadWeight = 0.5f;
1204         bool createVar                 = canAllocateVariable(state, valueRange.getType()) &&
1205                          (first == end || getWeightedBool(state.getRandom(), createOnReadWeight));
1206 
1207         if (createVar)
1208         {
1209             m_variable = allocateNewVariable(state, valueRange);
1210         }
1211         else
1212         {
1213             // Copy value entries for computing weights.
1214             std::vector<const ValueEntry *> availableVars;
1215             std::vector<float> weights;
1216 
1217             std::copy(first, end, std::inserter(availableVars, availableVars.begin()));
1218 
1219             // Compute weights.
1220             weights.resize(availableVars.size());
1221             for (int ndx = 0; ndx < (int)availableVars.size(); ndx++)
1222                 weights[ndx] = computeEntryReadWeight(availableVars[ndx]->getValueRange(), valueRange);
1223 
1224             // Select.
1225             const ValueEntry *entry = state.getRandom().chooseWeighted<const ValueEntry *>(
1226                 availableVars.begin(), availableVars.end(), weights.begin());
1227             m_variable = entry->getVariable();
1228 
1229             // Compute intersection
1230             ValueRange intersection(m_variable->getType());
1231             ValueRange::computeIntersection(intersection, entry->getValueRange(), valueRange);
1232             state.getVariableManager().setValue(m_variable, intersection.asAccess());
1233         }
1234     }
1235 }
1236 
VariableRead(const Variable * variable)1237 VariableRead::VariableRead(const Variable *variable)
1238 {
1239     m_variable = variable;
1240 }
1241 
getWeight(const GeneratorState & state,ConstValueRangeAccess valueRange)1242 float VariableRead::getWeight(const GeneratorState &state, ConstValueRangeAccess valueRange)
1243 {
1244     if (valueRange.getType().isVoid())
1245     {
1246         if (state.getVariableManager().hasEntry(IsReadableEntry(state.getExpressionFlags())) ||
1247             state.getVariableManager().getNumAllocatedScalars() <
1248                 state.getShaderParameters().maxCombinedVariableScalars)
1249             return unusedValueWeight;
1250         else
1251             return 0.0f;
1252     }
1253 
1254     if (!canAllocateVariable(state, valueRange.getType()) &&
1255         !state.getVariableManager().hasEntry(IsReadableIntersectingEntry(valueRange, state.getExpressionFlags())))
1256         return 0.0f;
1257     else
1258         return 1.0f;
1259 }
1260 
VariableWrite(GeneratorState & state,ConstValueRangeAccess valueRange)1261 VariableWrite::VariableWrite(GeneratorState &state, ConstValueRangeAccess valueRange)
1262 {
1263     DE_ASSERT(!valueRange.getType().isVoid());
1264 
1265     // Find variable with range that is superset of given range
1266     IsWritableSupersetEntry::Iterator first = state.getVariableManager().getBegin(IsWritableSupersetEntry(valueRange));
1267     IsWritableSupersetEntry::Iterator end   = state.getVariableManager().getEnd(IsWritableSupersetEntry(valueRange));
1268 
1269     const float createOnAssignWeight = 0.1f; // Will essentially create an unused variable
1270     bool createVar                   = canAllocateVariable(state, valueRange.getType()) &&
1271                      (first == end || getWeightedBool(state.getRandom(), createOnAssignWeight));
1272 
1273     if (createVar)
1274     {
1275         m_variable = state.getVariableManager().allocate(valueRange.getType());
1276         // \note Storage will be LOCAL
1277     }
1278     else
1279     {
1280         // Choose random
1281         DE_ASSERT(first != end);
1282         const ValueEntry *entry = state.getRandom().choose<const ValueEntry *>(first, end);
1283         m_variable              = entry->getVariable();
1284     }
1285 
1286     DE_ASSERT(m_variable);
1287 
1288     // Reset value range.
1289     const ValueEntry *parentEntry = state.getVariableManager().getParentValue(m_variable);
1290     if (parentEntry)
1291     {
1292         // Use parent value range.
1293         state.getVariableManager().setValue(m_variable, parentEntry->getValueRange());
1294     }
1295     else
1296     {
1297         // Use infinite range.
1298         ValueRange infRange(m_variable->getType());
1299         setInfiniteRange(infRange);
1300 
1301         state.getVariableManager().setValue(m_variable, infRange.asAccess());
1302     }
1303 }
1304 
getWeight(const GeneratorState & state,ConstValueRangeAccess valueRange)1305 float VariableWrite::getWeight(const GeneratorState &state, ConstValueRangeAccess valueRange)
1306 {
1307     if (!canAllocateVariable(state, valueRange.getType()) &&
1308         !state.getVariableManager().hasEntry(IsWritableSupersetEntry(valueRange)))
1309         return 0.0f;
1310     else
1311         return 1.0f;
1312 }
1313 
evaluate(ExecutionContext & evalCtx)1314 void VariableAccess::evaluate(ExecutionContext &evalCtx)
1315 {
1316     m_valueAccess = evalCtx.getValue(m_variable);
1317 }
1318 
ParenOp(GeneratorState & state,ConstValueRangeAccess valueRange)1319 ParenOp::ParenOp(GeneratorState &state, ConstValueRangeAccess valueRange) : m_valueRange(valueRange), m_child(DE_NULL)
1320 {
1321     DE_UNREF(state);
1322 }
1323 
~ParenOp(void)1324 ParenOp::~ParenOp(void)
1325 {
1326     delete m_child;
1327 }
1328 
createNextChild(GeneratorState & state)1329 Expression *ParenOp::createNextChild(GeneratorState &state)
1330 {
1331     if (m_child == DE_NULL)
1332     {
1333         m_child = Expression::createRandom(state, m_valueRange.asAccess());
1334         return m_child;
1335     }
1336     else
1337         return DE_NULL;
1338 }
1339 
tokenize(GeneratorState & state,TokenStream & str) const1340 void ParenOp::tokenize(GeneratorState &state, TokenStream &str) const
1341 {
1342     str << Token::LEFT_PAREN;
1343     m_child->tokenize(state, str);
1344     str << Token::RIGHT_PAREN;
1345 }
1346 
setChild(Expression * expression)1347 void ParenOp::setChild(Expression *expression)
1348 {
1349     m_child = expression;
1350 }
1351 
getWeight(const GeneratorState & state,ConstValueRangeAccess valueRange)1352 float ParenOp::getWeight(const GeneratorState &state, ConstValueRangeAccess valueRange)
1353 {
1354     if (valueRange.getType().isVoid())
1355         return state.getExpressionDepth() + 2 <= state.getShaderParameters().maxExpressionDepth ? unusedValueWeight :
1356                                                                                                   0.0f;
1357     else
1358     {
1359         int requiredDepth = 1 + getConservativeValueExprDepth(state, valueRange);
1360         return state.getExpressionDepth() + requiredDepth <= state.getShaderParameters().maxExpressionDepth ? 1.0f :
1361                                                                                                               0.0f;
1362     }
1363 }
1364 
1365 const int swizzlePrecedence = 2;
1366 
SwizzleOp(GeneratorState & state,ConstValueRangeAccess valueRange)1367 SwizzleOp::SwizzleOp(GeneratorState &state, ConstValueRangeAccess valueRange)
1368     : m_outValueRange(valueRange)
1369     , m_numInputElements(0)
1370     , m_child(DE_NULL)
1371 {
1372     DE_ASSERT(!m_outValueRange.getType().isVoid()); // \todo [2011-06-13 pyry] Void support
1373     DE_ASSERT(m_outValueRange.getType().isFloatOrVec() || m_outValueRange.getType().isIntOrVec() ||
1374               m_outValueRange.getType().isBoolOrVec());
1375 
1376     m_value.setStorage(m_outValueRange.getType());
1377 
1378     int numOutputElements = m_outValueRange.getType().getNumElements();
1379 
1380     // \note Swizzle works for vector types only.
1381     // \todo [2011-06-13 pyry] Use components multiple times.
1382     m_numInputElements = state.getRandom().getInt(deMax32(numOutputElements, 2), 4);
1383 
1384     std::set<int> availableElements;
1385     for (int ndx = 0; ndx < m_numInputElements; ndx++)
1386         availableElements.insert(ndx);
1387 
1388     // Randomize swizzle.
1389     for (int elemNdx = 0; elemNdx < (int)DE_LENGTH_OF_ARRAY(m_swizzle); elemNdx++)
1390     {
1391         if (elemNdx < numOutputElements)
1392         {
1393             int inElemNdx = state.getRandom().choose<int>(availableElements.begin(), availableElements.end());
1394             availableElements.erase(inElemNdx);
1395             m_swizzle[elemNdx] = (uint8_t)inElemNdx;
1396         }
1397         else
1398             m_swizzle[elemNdx] = 0;
1399     }
1400 }
1401 
~SwizzleOp(void)1402 SwizzleOp::~SwizzleOp(void)
1403 {
1404     delete m_child;
1405 }
1406 
createNextChild(GeneratorState & state)1407 Expression *SwizzleOp::createNextChild(GeneratorState &state)
1408 {
1409     if (m_child)
1410         return DE_NULL;
1411 
1412     // Compute input value range.
1413     VariableType inVarType  = VariableType(m_outValueRange.getType().getBaseType(), m_numInputElements);
1414     ValueRange inValueRange = ValueRange(inVarType);
1415 
1416     // Initialize all inputs to -inf..inf
1417     setInfiniteRange(inValueRange);
1418 
1419     // Compute intersections.
1420     int numOutputElements = m_outValueRange.getType().getNumElements();
1421     for (int outElemNdx = 0; outElemNdx < numOutputElements; outElemNdx++)
1422     {
1423         int inElemNdx = m_swizzle[outElemNdx];
1424         ValueRange::computeIntersection(inValueRange.asAccess().component(inElemNdx),
1425                                         inValueRange.asAccess().component(inElemNdx),
1426                                         m_outValueRange.asAccess().component(outElemNdx));
1427     }
1428 
1429     // Create child.
1430     state.pushPrecedence(swizzlePrecedence);
1431     m_child = Expression::createRandom(state, inValueRange.asAccess());
1432     state.popPrecedence();
1433 
1434     return m_child;
1435 }
1436 
tokenize(GeneratorState & state,TokenStream & str) const1437 void SwizzleOp::tokenize(GeneratorState &state, TokenStream &str) const
1438 {
1439     const char *rgbaSet[]   = {"r", "g", "b", "a"};
1440     const char *xyzwSet[]   = {"x", "y", "z", "w"};
1441     const char *stpqSet[]   = {"s", "t", "p", "q"};
1442     const char **swizzleSet = DE_NULL;
1443 
1444     switch (state.getRandom().getInt(0, 2))
1445     {
1446     case 0:
1447         swizzleSet = rgbaSet;
1448         break;
1449     case 1:
1450         swizzleSet = xyzwSet;
1451         break;
1452     case 2:
1453         swizzleSet = stpqSet;
1454         break;
1455     default:
1456         DE_ASSERT(false);
1457     }
1458 
1459     std::string swizzleStr;
1460     for (int elemNdx = 0; elemNdx < m_outValueRange.getType().getNumElements(); elemNdx++)
1461         swizzleStr += swizzleSet[m_swizzle[elemNdx]];
1462 
1463     m_child->tokenize(state, str);
1464     str << Token::DOT << Token(swizzleStr.c_str());
1465 }
1466 
getWeight(const GeneratorState & state,ConstValueRangeAccess valueRange)1467 float SwizzleOp::getWeight(const GeneratorState &state, ConstValueRangeAccess valueRange)
1468 {
1469     if (!state.getProgramParameters().useSwizzle)
1470         return 0.0f;
1471 
1472     if (state.getPrecedence() < swizzlePrecedence)
1473         return 0.0f;
1474 
1475     if (!valueRange.getType().isFloatOrVec() && !valueRange.getType().isIntOrVec() &&
1476         !valueRange.getType().isBoolOrVec())
1477         return 0.0f;
1478 
1479     int availableLevels = state.getShaderParameters().maxExpressionDepth - state.getExpressionDepth();
1480 
1481     // Swizzle + Constructor + Values
1482     if (availableLevels < 3)
1483         return 0.0f;
1484 
1485     return 1.0f;
1486 }
1487 
evaluate(ExecutionContext & execCtx)1488 void SwizzleOp::evaluate(ExecutionContext &execCtx)
1489 {
1490     m_child->evaluate(execCtx);
1491 
1492     ExecConstValueAccess inValue = m_child->getValue();
1493     ExecValueAccess outValue     = m_value.getValue(m_outValueRange.getType());
1494 
1495     for (int outElemNdx = 0; outElemNdx < outValue.getType().getNumElements(); outElemNdx++)
1496     {
1497         int inElemNdx                  = m_swizzle[outElemNdx];
1498         outValue.component(outElemNdx) = inValue.component(inElemNdx).value();
1499     }
1500 }
1501 
countSamplers(const VariableManager & varManager,VariableType::Type samplerType)1502 static int countSamplers(const VariableManager &varManager, VariableType::Type samplerType)
1503 {
1504     int numSamplers = 0;
1505 
1506     IsSamplerEntry::Iterator i   = varManager.getBegin(IsSamplerEntry(samplerType));
1507     IsSamplerEntry::Iterator end = varManager.getEnd(IsSamplerEntry(samplerType));
1508 
1509     for (; i != end; i++)
1510         numSamplers += 1;
1511 
1512     return numSamplers;
1513 }
1514 
TexLookup(GeneratorState & state,ConstValueRangeAccess valueRange)1515 TexLookup::TexLookup(GeneratorState &state, ConstValueRangeAccess valueRange)
1516     : m_type(TYPE_LAST)
1517     , m_coordExpr(DE_NULL)
1518     , m_lodBiasExpr(DE_NULL)
1519     , m_valueType(VariableType::TYPE_FLOAT, 4)
1520     , m_value(m_valueType)
1521 {
1522     DE_ASSERT(valueRange.getType() == VariableType(VariableType::TYPE_FLOAT, 4));
1523     DE_UNREF(valueRange); // Texture output value range is constant.
1524 
1525     // Select type.
1526     vector<Type> typeCandidates;
1527     if (state.getShaderParameters().useTexture2D)
1528     {
1529         typeCandidates.push_back(TYPE_TEXTURE2D);
1530         typeCandidates.push_back(TYPE_TEXTURE2D_LOD);
1531         typeCandidates.push_back(TYPE_TEXTURE2D_PROJ);
1532         typeCandidates.push_back(TYPE_TEXTURE2D_PROJ_LOD);
1533     }
1534 
1535     if (state.getShaderParameters().useTextureCube)
1536     {
1537         typeCandidates.push_back(TYPE_TEXTURECUBE);
1538         typeCandidates.push_back(TYPE_TEXTURECUBE_LOD);
1539     }
1540 
1541     m_type = state.getRandom().choose<Type>(typeCandidates.begin(), typeCandidates.end());
1542 
1543     // Select or allocate sampler.
1544     VariableType::Type samplerType = VariableType::TYPE_LAST;
1545     switch (m_type)
1546     {
1547     case TYPE_TEXTURE2D:
1548     case TYPE_TEXTURE2D_LOD:
1549     case TYPE_TEXTURE2D_PROJ:
1550     case TYPE_TEXTURE2D_PROJ_LOD:
1551         samplerType = VariableType::TYPE_SAMPLER_2D;
1552         break;
1553 
1554     case TYPE_TEXTURECUBE:
1555     case TYPE_TEXTURECUBE_LOD:
1556         samplerType = VariableType::TYPE_SAMPLER_CUBE;
1557         break;
1558 
1559     default:
1560         DE_ASSERT(false);
1561     }
1562 
1563     int sampler2DCount   = countSamplers(state.getVariableManager(), VariableType::TYPE_SAMPLER_2D);
1564     int samplerCubeCount = countSamplers(state.getVariableManager(), VariableType::TYPE_SAMPLER_CUBE);
1565     bool canAllocSampler = sampler2DCount + samplerCubeCount < state.getShaderParameters().maxSamplers;
1566     bool hasSampler      = samplerType == VariableType::TYPE_SAMPLER_2D ? (sampler2DCount > 0) : (samplerCubeCount > 0);
1567     bool allocSampler    = !hasSampler || (canAllocSampler && state.getRandom().getBool());
1568 
1569     if (allocSampler)
1570     {
1571         Variable *sampler = state.getVariableManager().allocate(VariableType(samplerType, 1));
1572         state.getVariableManager().setStorage(sampler, Variable::STORAGE_UNIFORM); // Samplers are always uniforms.
1573         m_sampler = sampler;
1574     }
1575     else
1576         m_sampler = state.getRandom()
1577                         .choose<const ValueEntry *>(state.getVariableManager().getBegin(IsSamplerEntry(samplerType)),
1578                                                     state.getVariableManager().getEnd(IsSamplerEntry(samplerType)))
1579                         ->getVariable();
1580 }
1581 
~TexLookup(void)1582 TexLookup::~TexLookup(void)
1583 {
1584     delete m_coordExpr;
1585     delete m_lodBiasExpr;
1586 }
1587 
createNextChild(GeneratorState & state)1588 Expression *TexLookup::createNextChild(GeneratorState &state)
1589 {
1590     bool hasLodBias =
1591         m_type == TYPE_TEXTURE2D_LOD || m_type == TYPE_TEXTURE2D_PROJ_LOD || m_type == TYPE_TEXTURECUBE_LOD;
1592 
1593     if (hasLodBias && !m_lodBiasExpr)
1594     {
1595         ValueRange lodRange(VariableType(VariableType::TYPE_FLOAT, 1));
1596         setInfiniteRange(lodRange); // Any value is valid.
1597 
1598         m_lodBiasExpr = Expression::createRandom(state, lodRange.asAccess());
1599         return m_lodBiasExpr;
1600     }
1601 
1602     if (!m_coordExpr)
1603     {
1604         if (m_type == TYPE_TEXTURECUBE || m_type == TYPE_TEXTURECUBE_LOD)
1605         {
1606             // Make sure major axis selection can be done.
1607             int majorAxisNdx = state.getRandom().getInt(0, 2);
1608 
1609             ValueRange coordRange(VariableType(VariableType::TYPE_FLOAT, 3));
1610 
1611             for (int ndx = 0; ndx < 3; ndx++)
1612             {
1613                 if (ndx == majorAxisNdx)
1614                 {
1615                     bool neg                           = state.getRandom().getBool();
1616                     coordRange.getMin().component(ndx) = neg ? -4.0f : 2.25f;
1617                     coordRange.getMax().component(ndx) = neg ? -2.25f : 4.0f;
1618                 }
1619                 else
1620                 {
1621                     coordRange.getMin().component(ndx) = -2.0f;
1622                     coordRange.getMax().component(ndx) = 2.0f;
1623                 }
1624             }
1625 
1626             m_coordExpr = Expression::createRandom(state, coordRange.asAccess());
1627         }
1628         else
1629         {
1630             bool isProj         = m_type == TYPE_TEXTURE2D_PROJ || m_type == TYPE_TEXTURE2D_PROJ_LOD;
1631             int coordScalarSize = isProj ? 3 : 2;
1632 
1633             ValueRange coordRange(VariableType(VariableType::TYPE_FLOAT, coordScalarSize));
1634             setInfiniteRange(coordRange); // Initialize base range with -inf..inf
1635 
1636             if (isProj)
1637             {
1638                 // w coordinate must be something sane, and not 0.
1639                 bool neg                         = state.getRandom().getBool();
1640                 coordRange.getMin().component(2) = neg ? -4.0f : 0.25f;
1641                 coordRange.getMax().component(2) = neg ? -0.25f : 4.0f;
1642             }
1643 
1644             m_coordExpr = Expression::createRandom(state, coordRange.asAccess());
1645         }
1646 
1647         DE_ASSERT(m_coordExpr);
1648         return m_coordExpr;
1649     }
1650 
1651     return DE_NULL; // Done.
1652 }
1653 
tokenize(GeneratorState & state,TokenStream & str) const1654 void TexLookup::tokenize(GeneratorState &state, TokenStream &str) const
1655 {
1656     bool isVertex = state.getShader().getType() == Shader::TYPE_VERTEX;
1657 
1658     if (state.getProgramParameters().version == VERSION_300)
1659     {
1660         switch (m_type)
1661         {
1662         case TYPE_TEXTURE2D:
1663             str << "texture";
1664             break;
1665         case TYPE_TEXTURE2D_LOD:
1666             str << (isVertex ? "textureLod" : "texture");
1667             break;
1668         case TYPE_TEXTURE2D_PROJ:
1669             str << "textureProj";
1670             break;
1671         case TYPE_TEXTURE2D_PROJ_LOD:
1672             str << (isVertex ? "textureProjLod" : "textureProj");
1673             break;
1674         case TYPE_TEXTURECUBE:
1675             str << "texture";
1676             break;
1677         case TYPE_TEXTURECUBE_LOD:
1678             str << (isVertex ? "textureLod" : "texture");
1679             break;
1680         default:
1681             DE_ASSERT(false);
1682         }
1683     }
1684     else
1685     {
1686         switch (m_type)
1687         {
1688         case TYPE_TEXTURE2D:
1689             str << "texture2D";
1690             break;
1691         case TYPE_TEXTURE2D_LOD:
1692             str << (isVertex ? "texture2DLod" : "texture2D");
1693             break;
1694         case TYPE_TEXTURE2D_PROJ:
1695             str << "texture2DProj";
1696             break;
1697         case TYPE_TEXTURE2D_PROJ_LOD:
1698             str << (isVertex ? "texture2DProjLod" : "texture2DProj");
1699             break;
1700         case TYPE_TEXTURECUBE:
1701             str << "textureCube";
1702             break;
1703         case TYPE_TEXTURECUBE_LOD:
1704             str << (isVertex ? "textureCubeLod" : "textureCube");
1705             break;
1706         default:
1707             DE_ASSERT(false);
1708         }
1709     }
1710 
1711     str << Token::LEFT_PAREN;
1712     str << m_sampler->getName();
1713     str << Token::COMMA;
1714     m_coordExpr->tokenize(state, str);
1715 
1716     if (m_lodBiasExpr)
1717     {
1718         str << Token::COMMA;
1719         m_lodBiasExpr->tokenize(state, str);
1720     }
1721 
1722     str << Token::RIGHT_PAREN;
1723 }
1724 
getWeight(const GeneratorState & state,ConstValueRangeAccess valueRange)1725 float TexLookup::getWeight(const GeneratorState &state, ConstValueRangeAccess valueRange)
1726 {
1727     if (state.getShaderParameters().texLookupBaseWeight <= 0.0f)
1728         return 0.0f;
1729 
1730     int availableLevels = state.getShaderParameters().maxExpressionDepth - state.getExpressionDepth();
1731 
1732     // Lookup + Constructor + Values
1733     if (availableLevels < 3)
1734         return 0.0f;
1735 
1736     if (state.getExpressionFlags() & (CONST_EXPR | NO_VAR_ALLOCATION))
1737         return 0.0f;
1738 
1739     if (valueRange.getType() != VariableType(VariableType::TYPE_FLOAT, 4))
1740         return 0.0f;
1741 
1742     ValueRange texOutputRange(VariableType(VariableType::TYPE_FLOAT, 4));
1743     for (int ndx = 0; ndx < 4; ndx++)
1744     {
1745         texOutputRange.getMin().component(ndx) = 0.0f;
1746         texOutputRange.getMax().component(ndx) = 1.0f;
1747     }
1748 
1749     if (!valueRange.isSupersetOf(texOutputRange.asAccess()))
1750         return 0.0f;
1751 
1752     return state.getShaderParameters().texLookupBaseWeight;
1753 }
1754 
evaluate(ExecutionContext & execCtx)1755 void TexLookup::evaluate(ExecutionContext &execCtx)
1756 {
1757     // Evaluate coord and bias.
1758     m_coordExpr->evaluate(execCtx);
1759     if (m_lodBiasExpr)
1760         m_lodBiasExpr->evaluate(execCtx);
1761 
1762     ExecConstValueAccess coords = m_coordExpr->getValue();
1763     ExecValueAccess dst         = m_value.getValue(m_valueType);
1764 
1765     switch (m_type)
1766     {
1767     case TYPE_TEXTURE2D:
1768     {
1769         const Sampler2D &tex = execCtx.getSampler2D(m_sampler);
1770         for (int i = 0; i < EXEC_VEC_WIDTH; i++)
1771         {
1772             float s     = coords.component(0).asFloat(i);
1773             float t     = coords.component(1).asFloat(i);
1774             tcu::Vec4 p = tex.sample(s, t, 0.0f);
1775 
1776             for (int comp = 0; comp < 4; comp++)
1777                 dst.component(comp).asFloat(i) = p[comp];
1778         }
1779         break;
1780     }
1781 
1782     case TYPE_TEXTURE2D_LOD:
1783     {
1784         ExecConstValueAccess lod = m_lodBiasExpr->getValue();
1785         const Sampler2D &tex     = execCtx.getSampler2D(m_sampler);
1786         for (int i = 0; i < EXEC_VEC_WIDTH; i++)
1787         {
1788             float s     = coords.component(0).asFloat(i);
1789             float t     = coords.component(1).asFloat(i);
1790             float l     = lod.component(0).asFloat(i);
1791             tcu::Vec4 p = tex.sample(s, t, l);
1792 
1793             for (int comp = 0; comp < 4; comp++)
1794                 dst.component(comp).asFloat(i) = p[comp];
1795         }
1796         break;
1797     }
1798 
1799     case TYPE_TEXTURE2D_PROJ:
1800     {
1801         const Sampler2D &tex = execCtx.getSampler2D(m_sampler);
1802         for (int i = 0; i < EXEC_VEC_WIDTH; i++)
1803         {
1804             float s     = coords.component(0).asFloat(i);
1805             float t     = coords.component(1).asFloat(i);
1806             float w     = coords.component(2).asFloat(i);
1807             tcu::Vec4 p = tex.sample(s / w, t / w, 0.0f);
1808 
1809             for (int comp = 0; comp < 4; comp++)
1810                 dst.component(comp).asFloat(i) = p[comp];
1811         }
1812         break;
1813     }
1814 
1815     case TYPE_TEXTURE2D_PROJ_LOD:
1816     {
1817         ExecConstValueAccess lod = m_lodBiasExpr->getValue();
1818         const Sampler2D &tex     = execCtx.getSampler2D(m_sampler);
1819         for (int i = 0; i < EXEC_VEC_WIDTH; i++)
1820         {
1821             float s     = coords.component(0).asFloat(i);
1822             float t     = coords.component(1).asFloat(i);
1823             float w     = coords.component(2).asFloat(i);
1824             float l     = lod.component(0).asFloat(i);
1825             tcu::Vec4 p = tex.sample(s / w, t / w, l);
1826 
1827             for (int comp = 0; comp < 4; comp++)
1828                 dst.component(comp).asFloat(i) = p[comp];
1829         }
1830         break;
1831     }
1832 
1833     case TYPE_TEXTURECUBE:
1834     {
1835         const SamplerCube &tex = execCtx.getSamplerCube(m_sampler);
1836         for (int i = 0; i < EXEC_VEC_WIDTH; i++)
1837         {
1838             float s     = coords.component(0).asFloat(i);
1839             float t     = coords.component(1).asFloat(i);
1840             float r     = coords.component(2).asFloat(i);
1841             tcu::Vec4 p = tex.sample(s, t, r, 0.0f);
1842 
1843             for (int comp = 0; comp < 4; comp++)
1844                 dst.component(comp).asFloat(i) = p[comp];
1845         }
1846         break;
1847     }
1848 
1849     case TYPE_TEXTURECUBE_LOD:
1850     {
1851         ExecConstValueAccess lod = m_lodBiasExpr->getValue();
1852         const SamplerCube &tex   = execCtx.getSamplerCube(m_sampler);
1853         for (int i = 0; i < EXEC_VEC_WIDTH; i++)
1854         {
1855             float s     = coords.component(0).asFloat(i);
1856             float t     = coords.component(1).asFloat(i);
1857             float r     = coords.component(2).asFloat(i);
1858             float l     = lod.component(0).asFloat(i);
1859             tcu::Vec4 p = tex.sample(s, t, r, l);
1860 
1861             for (int comp = 0; comp < 4; comp++)
1862                 dst.component(comp).asFloat(i) = p[comp];
1863         }
1864         break;
1865     }
1866 
1867     default:
1868         DE_ASSERT(false);
1869     }
1870 }
1871 
1872 } // namespace rsg
1873