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