1/*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 2.0 Module
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 Algorithm implementation tests.
22 *//*--------------------------------------------------------------------*/
23
24#include "es2fShaderAlgorithmTests.hpp"
25#include "glsShaderRenderCase.hpp"
26#include "gluShaderUtil.hpp"
27#include "tcuStringTemplate.hpp"
28
29#include "deInt32.h"
30#include "deMemory.h"
31
32#include <map>
33#include <algorithm>
34
35using namespace std;
36using namespace tcu;
37using namespace glu;
38using namespace deqp::gls;
39
40namespace deqp
41{
42namespace gles2
43{
44namespace Functional
45{
46
47// ShaderAlgorithmCase
48
49class ShaderAlgorithmCase : public ShaderRenderCase
50{
51public:
52								ShaderAlgorithmCase			(Context& context, const char* name, const char* description, bool isVertexCase, ShaderEvalFunc evalFunc, const char* vertShaderSource, const char* fragShaderSource);
53	virtual						~ShaderAlgorithmCase		(void);
54
55private:
56								ShaderAlgorithmCase			(const ShaderAlgorithmCase&);	// not allowed!
57	ShaderAlgorithmCase&		operator=					(const ShaderAlgorithmCase&);	// not allowed!
58};
59
60ShaderAlgorithmCase::ShaderAlgorithmCase (Context& context, const char* name, const char* description, bool isVertexCase, ShaderEvalFunc evalFunc, const char* vertShaderSource, const char* fragShaderSource)
61	: ShaderRenderCase(context.getTestContext(), context.getRenderContext(), context.getContextInfo(), name, description, isVertexCase, evalFunc)
62{
63	m_vertShaderSource	= vertShaderSource;
64	m_fragShaderSource	= fragShaderSource;
65}
66
67ShaderAlgorithmCase::~ShaderAlgorithmCase (void)
68{
69}
70
71// Helpers.
72
73static ShaderAlgorithmCase* createExpressionCase (Context& context, const char* caseName, const char* description, bool isVertexCase, ShaderEvalFunc evalFunc, LineStream& shaderBody)
74{
75	std::ostringstream vtx;
76	std::ostringstream frag;
77	std::ostringstream& op = isVertexCase ? vtx : frag;
78
79	vtx << "attribute highp vec4 a_position;\n";
80	vtx << "attribute highp vec4 a_unitCoords;\n";
81
82	if (isVertexCase)
83	{
84		vtx << "varying mediump vec3 v_color;\n";
85		frag << "varying mediump vec3 v_color;\n";
86	}
87	else
88	{
89		vtx << "varying mediump vec4 v_coords;\n";
90		frag << "varying mediump vec4 v_coords;\n";
91	}
92
93//	op << "uniform mediump sampler2D ut_brick;\n";
94
95	vtx << "\n";
96	vtx << "void main()\n";
97	vtx << "{\n";
98	vtx << "	gl_Position = a_position;\n";
99
100	frag << "\n";
101	frag << "void main()\n";
102	frag << "{\n";
103
104	// Write matrix.
105	if (isVertexCase)
106		op << "	${PRECISION} vec4 coords = a_unitCoords;\n";
107	else
108		op << "	${PRECISION} vec4 coords = v_coords;\n";
109
110	op << "	${PRECISION} vec3 res = vec3(0.0);\n";
111	op << shaderBody.str();
112
113	if (isVertexCase)
114	{
115		vtx << "	v_color = res;\n";
116		frag << "	gl_FragColor = vec4(v_color, 1.0);\n";
117	}
118	else
119	{
120		vtx << "	v_coords = a_unitCoords;\n";
121		frag << "	gl_FragColor = vec4(res, 1.0);\n";
122	}
123
124	vtx << "}\n";
125	frag << "}\n";
126
127	// Fill in shader templates.
128	map<string, string> params;
129	params.insert(pair<string, string>("PRECISION", "mediump"));
130
131	StringTemplate vertTemplate(vtx.str().c_str());
132	StringTemplate fragTemplate(frag.str().c_str());
133	string vertexShaderSource = vertTemplate.specialize(params);
134	string fragmentShaderSource = fragTemplate.specialize(params);
135
136	return new ShaderAlgorithmCase(context, caseName, description, isVertexCase, evalFunc, vertexShaderSource.c_str(), fragmentShaderSource.c_str());
137}
138
139// ShaderAlgorithmTests.
140
141ShaderAlgorithmTests::ShaderAlgorithmTests(Context& context)
142	: TestCaseGroup(context, "algorithm", "Miscellaneous algorithm implementations using shaders.")
143{
144}
145
146ShaderAlgorithmTests::~ShaderAlgorithmTests (void)
147{
148}
149
150void ShaderAlgorithmTests::init (void)
151{
152//	TestCaseGroup* colorGroup = new TestCaseGroup(m_testCtx, "color", "Miscellaneous color related algorithm tests.");
153//	addChild(colorGroup);
154
155	#define SHADER_OP_CASE(NAME, DESCRIPTION, SHADER_OP, EVAL_FUNC_BODY)														\
156		do {																													\
157			struct Eval_##NAME { static void eval (ShaderEvalContext& c) EVAL_FUNC_BODY };										\
158			addChild(createExpressionCase(m_context, #NAME "_vertex", DESCRIPTION, true, &Eval_##NAME::eval, SHADER_OP));		\
159			addChild(createExpressionCase(m_context, #NAME "_fragment", DESCRIPTION, false, &Eval_##NAME::eval, SHADER_OP));	\
160		} while (deGetFalse())
161
162	SHADER_OP_CASE(hsl_to_rgb, "Conversion from HSL color space into RGB.",
163		LineStream(1)
164		<< "mediump float H = coords.x, S = coords.y, L = coords.z;"
165		<< "mediump float v = (L <= 0.5) ? (L * (1.0 + S)) : (L + S - L * S);"
166		<< "res = vec3(L); // default to gray"
167		<< "if (v > 0.0)"
168		<< "{"
169		<< "	mediump float m = L + L - v;"
170		<< "	mediump float sv = (v - m) / v;"
171		<< "	H *= 6.0;"
172		<< "	mediump int sextant = int(H);"
173		<< "	mediump float fract = H - float(sextant);"
174		<< "	mediump float vsf = v * sv * fract;"
175		<< "	mediump float mid1 = m + vsf;"
176		<< "	mediump float mid2 = m - vsf;"
177		<< "	if (sextant == 0)      res = vec3(v, mid1, m);"
178		<< "	else if (sextant == 1) res = vec3(mid2, v, m);"
179		<< "	else if (sextant == 2) res = vec3(m, v, mid1);"
180		<< "	else if (sextant == 3) res = vec3(m, mid2, v);"
181		<< "	else if (sextant == 4) res = vec3(mid1, m, v);"
182		<< "	else                   res = vec3(v, m, mid2);"
183		<< "}",
184		{
185			float H = c.unitCoords.x();
186			float S = c.unitCoords.y();
187			float L = c.unitCoords.z();
188			Vec3 rgb = Vec3(L);
189			float v = (L <= 0.5f) ? (L * (1.0f + S)) : (L + S - L * S);
190			if (v > 0.0f)
191			{
192				float m = L + L - v;
193				float sv = (v - m) / v;
194				H *= 6.0f;
195				int sextant = int(H);
196				float fract = H - float(sextant);
197				float vsf = v * sv * fract;
198				float mid1 = m + vsf;
199				float mid2 = m - vsf;
200				if (sextant == 0)		rgb = Vec3(v, mid1, m);
201				else if (sextant == 1)	rgb = Vec3(mid2, v, m);
202				else if (sextant == 2)	rgb = Vec3(m, v, mid1);
203				else if (sextant == 3)	rgb = Vec3(m, mid2, v);
204				else if (sextant == 4)	rgb = Vec3(mid1, m, v);
205				else					rgb = Vec3(v, m, mid2);
206			}
207			c.color.xyz() = rgb;
208		});
209
210	SHADER_OP_CASE(rgb_to_hsl, "Conversion from RGB color space into HSL.",
211		LineStream(1)
212		<< "mediump float r = coords.x, g = coords.y, b = coords.z;"
213		<< "mediump float minVal = min(min(r, g), b);"
214		<< "mediump float maxVal = max(max(r, g), b);"
215		<< "mediump float L = (minVal + maxVal) * 0.5;"
216		<< "if (minVal == maxVal)"
217		<< "	res = vec3(0.0, 0.0, L);"
218		<< "else"
219		<< "{"
220		<< "	mediump float H;"
221		<< "	mediump float S;"
222		<< "	if (L < 0.5)"
223		<< "		S = (maxVal - minVal) / (maxVal + minVal);"
224		<< "	else"
225		<< "		S = (maxVal - minVal) / (2.0 - maxVal - minVal);"
226		<< ""
227		<< "	mediump float ooDiff = 1.0 / (maxVal - minVal);"
228		<< "	if (r == maxVal)      H = (g - b) * ooDiff;"
229		<< "	else if (g == maxVal) H = 2.0 + (b - r) * ooDiff;"
230		<< "	else                  H = 4.0 + (r - g) * ooDiff;"
231		<< "	H /= 6.0;"
232		<< ""
233		<< "	res = vec3(H, S, L);"
234		<< "}",
235		{
236			float r = c.unitCoords.x();
237			float g = c.unitCoords.y();
238			float b = c.unitCoords.z();
239			float minVal = min(min(r, g), b);
240			float maxVal = max(max(r, g), b);
241			float L = (minVal + maxVal) * 0.5f;
242			Vec3 hsl;
243
244			if (minVal == maxVal)
245				hsl = Vec3(0.0f, 0.0f, L);
246			else
247			{
248				float H;
249				float S;
250				if (L < 0.5f)
251					S = (maxVal - minVal) / (maxVal + minVal);
252				else
253					S = (maxVal - minVal) / (2.0f - maxVal - minVal);
254
255				float ooDiff = 1.0f / (maxVal - minVal);
256				if (r == maxVal)		H = (g - b) * ooDiff;
257				else if (g == maxVal)	H = 2.0f + (b - r) * ooDiff;
258				else					H = 4.0f + (r - g) * ooDiff;
259				H /= 6.0f;
260
261				hsl = Vec3(H, S, L);
262			}
263			c.color.xyz() = hsl;
264		});
265
266/*	SHADER_OP_CASE(image_to_grayscale, "Convert image to grayscale.",
267		LineStream(1)
268		<< "res = texture2D(ut_brick, coords.xy).rgb;",
269		{
270			c.color.xyz() = Vec3(0.5f);
271		});*/
272}
273
274} // Functional
275} // gles2
276} // deqp
277