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