• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 3.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 Shader switch statement tests.
22  *
23  * Variables:
24  *  + Selection expression type: static, uniform, dynamic
25  *  + Switch layout - fall-through or use of default label
26  *  + Switch nested in loop/conditional statement
27  *  + Loop/conditional statement nested in switch
28  *//*--------------------------------------------------------------------*/
29 
30 #include "es3fShaderSwitchTests.hpp"
31 #include "glsShaderRenderCase.hpp"
32 #include "glsShaderLibrary.hpp"
33 #include "tcuStringTemplate.hpp"
34 #include "deMath.h"
35 
36 namespace deqp
37 {
38 namespace gles3
39 {
40 namespace Functional
41 {
42 
43 using namespace deqp::gls;
44 using std::string;
45 using std::map;
46 using std::vector;
47 
48 class ShaderSwitchCase : public ShaderRenderCase
49 {
50 public:
51 						ShaderSwitchCase			(Context& context, const char* name, const char* description, bool isVertexCase, const char* vtxSource, const char* fragSource, ShaderEvalFunc evalFunc);
52 	virtual				~ShaderSwitchCase			(void);
53 };
54 
ShaderSwitchCase(Context & context,const char * name,const char * description,bool isVertexCase,const char * vtxSource,const char * fragSource,ShaderEvalFunc evalFunc)55 ShaderSwitchCase::ShaderSwitchCase (Context& context, const char* name, const char* description, bool isVertexCase, const char* vtxSource, const char* fragSource, ShaderEvalFunc evalFunc)
56 	: ShaderRenderCase(context.getTestContext(), context.getRenderContext(), context.getContextInfo(), name, description, isVertexCase, evalFunc)
57 {
58 	m_vertShaderSource	= vtxSource;
59 	m_fragShaderSource	= fragSource;
60 }
61 
~ShaderSwitchCase(void)62 ShaderSwitchCase::~ShaderSwitchCase (void)
63 {
64 }
65 
66 enum SwitchType
67 {
68 	SWITCHTYPE_STATIC = 0,
69 	SWITCHTYPE_UNIFORM,
70 	SWITCHTYPE_DYNAMIC,
71 
72 	SWITCHTYPE_LAST
73 };
74 
evalSwitchStatic(ShaderEvalContext & evalCtx)75 static void evalSwitchStatic	(ShaderEvalContext& evalCtx)	{ evalCtx.color.xyz() = evalCtx.coords.swizzle(1,2,3);	}
evalSwitchUniform(ShaderEvalContext & evalCtx)76 static void evalSwitchUniform	(ShaderEvalContext& evalCtx)	{ evalCtx.color.xyz() = evalCtx.coords.swizzle(1,2,3);	}
evalSwitchDynamic(ShaderEvalContext & evalCtx)77 static void evalSwitchDynamic	(ShaderEvalContext& evalCtx)
78 {
79 	switch (int(deFloatFloor(evalCtx.coords.z()*1.5f + 2.0f)))
80 	{
81 		case 0:		evalCtx.color.xyz() = evalCtx.coords.swizzle(0,1,2);	break;
82 		case 1:		evalCtx.color.xyz() = evalCtx.coords.swizzle(3,2,1);	break;
83 		case 2:		evalCtx.color.xyz() = evalCtx.coords.swizzle(1,2,3);	break;
84 		case 3:		evalCtx.color.xyz() = evalCtx.coords.swizzle(2,1,0);	break;
85 		default:	evalCtx.color.xyz() = evalCtx.coords.swizzle(0,0,0);	break;
86 	}
87 }
88 
makeSwitchCase(Context & context,const char * name,const char * desc,SwitchType type,bool isVertex,const LineStream & switchBody)89 static tcu::TestCase* makeSwitchCase (Context& context, const char* name, const char* desc, SwitchType type, bool isVertex, const LineStream& switchBody)
90 {
91 	std::ostringstream	vtx;
92 	std::ostringstream	frag;
93 	std::ostringstream&	op		= isVertex ? vtx : frag;
94 
95 	vtx << "#version 300 es\n"
96 		<< "in highp vec4 a_position;\n"
97 		<< "in highp vec4 a_coords;\n";
98 	frag << "#version 300 es\n"
99 		 << "layout(location = 0) out mediump vec4 o_color;\n";
100 
101 	if (isVertex)
102 	{
103 		vtx << "out mediump vec4 v_color;\n";
104 		frag << "in mediump vec4 v_color;\n";
105 	}
106 	else
107 	{
108 		vtx << "out highp vec4 v_coords;\n";
109 		frag << "in highp vec4 v_coords;\n";
110 	}
111 
112 	if (type == SWITCHTYPE_UNIFORM)
113 		op << "uniform highp int ui_two;\n";
114 
115 	vtx << "\n"
116 		<< "void main (void)\n"
117 		<< "{\n"
118 		<< "	gl_Position = a_position;\n";
119 	frag << "\n"
120 		 << "void main (void)\n"
121 		 << "{\n";
122 
123 	// Setup.
124 	op << "	highp vec4 coords = " << (isVertex ? "a_coords" : "v_coords") << ";\n";
125 	op << "	mediump vec3 res = vec3(0.0);\n\n";
126 
127 	// Switch body.
128 	map<string, string> params;
129 	params["CONDITION"] = type == SWITCHTYPE_STATIC		? "2"								:
130 						  type == SWITCHTYPE_UNIFORM	? "ui_two"							:
131 						  type == SWITCHTYPE_DYNAMIC	? "int(floor(coords.z*1.5 + 2.0))"	: "???";
132 
133 	op << tcu::StringTemplate(switchBody.str()).specialize(params).c_str();
134 	op << "\n";
135 
136 	if (isVertex)
137 	{
138 		vtx << "	v_color = vec4(res, 1.0);\n";
139 		frag << "	o_color = v_color;\n";
140 	}
141 	else
142 	{
143 		vtx << "	v_coords = a_coords;\n";
144 		frag << "	o_color = vec4(res, 1.0);\n";
145 	}
146 
147 	vtx << "}\n";
148 	frag << "}\n";
149 
150 	return new ShaderSwitchCase(context, name, desc, isVertex, vtx.str().c_str(), frag.str().c_str(),
151 								type == SWITCHTYPE_STATIC	? evalSwitchStatic	:
152 								type == SWITCHTYPE_UNIFORM	? evalSwitchUniform	:
153 								type == SWITCHTYPE_DYNAMIC	? evalSwitchDynamic	: (ShaderEvalFunc)DE_NULL);
154 }
155 
makeSwitchCases(TestCaseGroup * group,const char * name,const char * desc,const LineStream & switchBody,const bool skipDynamicType=false)156 static void makeSwitchCases (TestCaseGroup* group, const char* name, const char* desc, const LineStream& switchBody, const bool skipDynamicType = false)
157 {
158 	static const char* switchTypeNames[] = { "static", "uniform", "dynamic" };
159 	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(switchTypeNames) == SWITCHTYPE_LAST);
160 
161 	for (int type = 0; type < SWITCHTYPE_LAST; type++)
162 	{
163 		if (skipDynamicType && (type == SWITCHTYPE_DYNAMIC))
164 			continue;
165 
166 		group->addChild(makeSwitchCase(group->getContext(), (string(name) + "_" + switchTypeNames[type] + "_vertex").c_str(),	desc, (SwitchType)type, true,	switchBody));
167 		group->addChild(makeSwitchCase(group->getContext(), (string(name) + "_" + switchTypeNames[type] + "_fragment").c_str(),	desc, (SwitchType)type, false,	switchBody));
168 	}
169 }
170 
ShaderSwitchTests(Context & context)171 ShaderSwitchTests::ShaderSwitchTests (Context& context)
172 	: TestCaseGroup(context, "switch", "Switch statement tests")
173 {
174 }
175 
~ShaderSwitchTests(void)176 ShaderSwitchTests::~ShaderSwitchTests (void)
177 {
178 }
179 
init(void)180 void ShaderSwitchTests::init (void)
181 {
182 	// Expected swizzles:
183 	// 0: xyz
184 	// 1: wzy
185 	// 2: yzw
186 	// 3: zyx
187 
188 	makeSwitchCases(this, "basic", "Basic switch statement usage",
189 		LineStream(1)
190 		<< "switch (${CONDITION})"
191 		<< "{"
192 		<< "	case 0:		res = coords.xyz;	break;"
193 		<< "	case 1:		res = coords.wzy;	break;"
194 		<< "	case 2:		res = coords.yzw;	break;"
195 		<< "	case 3:		res = coords.zyx;	break;"
196 		<< "}");
197 
198 	makeSwitchCases(this, "const_expr_in_label", "Constant expression in label",
199 		LineStream(1)
200 		<< "const int t = 2;"
201 		<< "switch (${CONDITION})"
202 		<< "{"
203 		<< "	case int(0.0):	res = coords.xyz;	break;"
204 		<< "	case 2-1:		res = coords.wzy;	break;"
205 		<< "	case 3&(1<<1):	res = coords.yzw;	break;"
206 		<< "	case t+1:		res = coords.zyx;	break;"
207 		<< "}");
208 
209 	makeSwitchCases(this, "default_label", "Default label usage",
210 		LineStream(1)
211 		<< "switch (${CONDITION})"
212 		<< "{"
213 		<< "	case 0:		res = coords.xyz;	break;"
214 		<< "	case 1:		res = coords.wzy;	break;"
215 		<< "	case 3:		res = coords.zyx;	break;"
216 		<< "	default:	res = coords.yzw;"
217 		<< "}");
218 
219 	makeSwitchCases(this, "default_not_last", "Default label usage",
220 		LineStream(1)
221 		<< "switch (${CONDITION})"
222 		<< "{"
223 		<< "	case 0:		res = coords.xyz;	break;"
224 		<< "	default:	res = coords.yzw;	break;"
225 		<< "	case 1:		res = coords.wzy;	break;"
226 		<< "	case 3:		res = coords.zyx;	break;"
227 		<< "}");
228 
229 	makeSwitchCases(this, "no_default_label", "No match in switch without default label",
230 		LineStream(1)
231 		<< "res = coords.yzw;\n"
232 		<< "switch (${CONDITION})"
233 		<< "{"
234 		<< "	case 0:		res = coords.xyz;	break;"
235 		<< "	case 1:		res = coords.wzy;	break;"
236 		<< "	case 3:		res = coords.zyx;	break;"
237 		<< "}");
238 
239 	makeSwitchCases(this, "default_only", "Default case only",
240 		LineStream(1)
241 		<< "switch (${CONDITION})"
242 		<< "{"
243 		<< "	default:"
244 		<< "		res = coords.yzw;"
245 		<< "}", true);
246 
247 	makeSwitchCases(this, "empty_case_default", "Empty case and default",
248 		LineStream(1)
249 		<< "switch (${CONDITION})"
250 		<< "{"
251 		<< "	case 2:"
252 		<< "	default:"
253 		<< "		res = coords.yzw;"
254 		<< "}", true);
255 
256 	makeSwitchCases(this, "fall_through", "Fall-through",
257 		LineStream(1)
258 		<< "switch (${CONDITION})"
259 		<< "{"
260 		<< "	case 0:		res = coords.xyz;	break;"
261 		<< "	case 1:		res = coords.wzy;	break;"
262 		<< "	case 2:		coords = coords.yzwx;"
263 		<< "	case 4:		res = vec3(coords);	break;"
264 		<< "	case 3:		res = coords.zyx;	break;"
265 		<< "}");
266 
267 	makeSwitchCases(this, "fall_through_default", "Fall-through",
268 		LineStream(1)
269 		<< "switch (${CONDITION})"
270 		<< "{"
271 		<< "	case 0:		res = coords.xyz;	break;"
272 		<< "	case 1:		res = coords.wzy;	break;"
273 		<< "	case 3:		res = coords.zyx;	break;"
274 		<< "	case 2:		coords = coords.yzwx;"
275 		<< "	default:	res = vec3(coords);"
276 		<< "}");
277 
278 	makeSwitchCases(this, "conditional_fall_through", "Fall-through",
279 		LineStream(1)
280 		<< "highp vec4 tmp = coords;"
281 		<< "switch (${CONDITION})"
282 		<< "{"
283 		<< "	case 0:		res = coords.xyz;	break;"
284 		<< "	case 1:		res = coords.wzy;	break;"
285 		<< "	case 2:"
286 		<< "		tmp = coords.yzwx;"
287 		<< "	case 3:"
288 		<< "		res = vec3(tmp);"
289 		<< "		if (${CONDITION} != 3)"
290 		<< "			break;"
291 		<< "	default:	res = tmp.zyx;		break;"
292 		<< "}");
293 
294 	makeSwitchCases(this, "conditional_fall_through_2", "Fall-through",
295 		LineStream(1)
296 		<< "highp vec4 tmp = coords;"
297 		<< "mediump int c = ${CONDITION};"
298 		<< "switch (c)"
299 		<< "{"
300 		<< "	case 0:		res = coords.xyz;	break;"
301 		<< "	case 1:		res = coords.wzy;	break;"
302 		<< "	case 2:"
303 		<< "		c += ${CONDITION};"
304 		<< "		tmp = coords.yzwx;"
305 		<< "	case 3:"
306 		<< "		res = vec3(tmp);"
307 		<< "		if (c == 4)"
308 		<< "			break;"
309 		<< "	default:	res = tmp.zyx;		break;"
310 		<< "}");
311 
312 	makeSwitchCases(this, "scope", "Basic switch statement usage",
313 		LineStream(1)
314 		<< "switch (${CONDITION})"
315 		<< "{"
316 		<< "	case 0:		res = coords.xyz;	break;"
317 		<< "	case 1:		res = coords.wzy;	break;"
318 		<< "	case 2:"
319 		<< "	{"
320 		<< "		mediump vec3 t = coords.yzw;"
321 		<< "		res = t;"
322 		<< "		break;"
323 		<< "	}"
324 		<< "	case 3:		res = coords.zyx;	break;"
325 		<< "}");
326 
327 	makeSwitchCases(this, "switch_in_if", "Switch in for loop",
328 		LineStream(1)
329 		<< "if (${CONDITION} >= 0)"
330 		<< "{"
331 		<< "	switch (${CONDITION})"
332 		<< "	{"
333 		<< "		case 0:		res = coords.xyz;	break;"
334 		<< "		case 1:		res = coords.wzy;	break;"
335 		<< "		case 2:		res = coords.yzw;	break;"
336 		<< "		case 3:		res = coords.zyx;	break;"
337 		<< "	}"
338 		<< "}");
339 
340 	makeSwitchCases(this, "switch_in_for_loop", "Switch in for loop",
341 		LineStream(1)
342 		<< "for (int i = 0; i <= ${CONDITION}; i++)"
343 		<< "{"
344 		<< "	switch (i)"
345 		<< "	{"
346 		<< "		case 0:		res = coords.xyz;	break;"
347 		<< "		case 1:		res = coords.wzy;	break;"
348 		<< "		case 2:		res = coords.yzw;	break;"
349 		<< "		case 3:		res = coords.zyx;	break;"
350 		<< "	}"
351 		<< "}");
352 
353 	makeSwitchCases(this, "switch_in_while_loop", "Switch in while loop",
354 		LineStream(1)
355 		<< "int i = 0;"
356 		<< "while (i <= ${CONDITION})"
357 		<< "{"
358 		<< "	switch (i)"
359 		<< "	{"
360 		<< "		case 0:		res = coords.xyz;	break;"
361 		<< "		case 1:		res = coords.wzy;	break;"
362 		<< "		case 2:		res = coords.yzw;	break;"
363 		<< "		case 3:		res = coords.zyx;	break;"
364 		<< "	}"
365 		<< "	i += 1;"
366 		<< "}");
367 
368 	makeSwitchCases(this, "switch_in_do_while_loop", "Switch in do-while loop",
369 		LineStream(1)
370 		<< "int i = 0;"
371 		<< "do"
372 		<< "{"
373 		<< "	switch (i)"
374 		<< "	{"
375 		<< "		case 0:		res = coords.xyz;	break;"
376 		<< "		case 1:		res = coords.wzy;	break;"
377 		<< "		case 2:		res = coords.yzw;	break;"
378 		<< "		case 3:		res = coords.zyx;	break;"
379 		<< "	}"
380 		<< "	i += 1;"
381 		<< "} while (i <= ${CONDITION});");
382 
383 	makeSwitchCases(this, "if_in_switch", "Basic switch statement usage",
384 		LineStream(1)
385 		<< "switch (${CONDITION})"
386 		<< "{"
387 		<< "	case 0:		res = coords.xyz;	break;"
388 		<< "	case 1:		res = coords.wzy;	break;"
389 		<< "	default:"
390 		<< "		if (${CONDITION} == 2)"
391 		<< "			res = coords.yzw;"
392 		<< "		else"
393 		<< "			res = coords.zyx;"
394 		<< "		break;"
395 		<< "}");
396 
397 	makeSwitchCases(this, "for_loop_in_switch", "Basic switch statement usage",
398 		LineStream(1)
399 		<< "switch (${CONDITION})"
400 		<< "{"
401 		<< "	case 0:		res = coords.xyz;	break;"
402 		<< "	case 1:"
403 		<< "	case 2:"
404 		<< "	{"
405 		<< "		highp vec3 t = coords.yzw;"
406 		<< "		for (int i = 0; i < ${CONDITION}; i++)"
407 		<< "			t = t.zyx;"
408 		<< "		res = t;"
409 		<< "		break;"
410 		<< "	}"
411 		<< "	default:	res = coords.zyx;	break;"
412 		<< "}");
413 
414 	makeSwitchCases(this, "while_loop_in_switch", "Basic switch statement usage",
415 		LineStream(1)
416 		<< "switch (${CONDITION})"
417 		<< "{"
418 		<< "	case 0:		res = coords.xyz;	break;"
419 		<< "	case 1:"
420 		<< "	case 2:"
421 		<< "	{"
422 		<< "		highp vec3 t = coords.yzw;"
423 		<< "		int i = 0;"
424 		<< "		while (i < ${CONDITION})"
425 		<< "		{"
426 		<< "			t = t.zyx;"
427 		<< "			i += 1;"
428 		<< "		}"
429 		<< "		res = t;"
430 		<< "		break;"
431 		<< "	}"
432 		<< "	default:	res = coords.zyx;	break;"
433 		<< "}");
434 
435 	makeSwitchCases(this, "do_while_loop_in_switch", "Basic switch statement usage",
436 		LineStream(1)
437 		<< "switch (${CONDITION})"
438 		<< "{"
439 		<< "	case 0:		res = coords.xyz;	break;"
440 		<< "	case 1:"
441 		<< "	case 2:"
442 		<< "	{"
443 		<< "		highp vec3 t = coords.yzw;"
444 		<< "		int i = 0;"
445 		<< "		do"
446 		<< "		{"
447 		<< "			t = t.zyx;"
448 		<< "			i += 1;"
449 		<< "		} while (i < ${CONDITION});"
450 		<< "		res = t;"
451 		<< "		break;"
452 		<< "	}"
453 		<< "	default:	res = coords.zyx;	break;"
454 		<< "}");
455 
456 	makeSwitchCases(this, "switch_in_switch", "Basic switch statement usage",
457 		LineStream(1)
458 		<< "switch (${CONDITION})"
459 		<< "{"
460 		<< "	case 0:		res = coords.xyz;	break;"
461 		<< "	case 1:"
462 		<< "	case 2:"
463 		<< "		switch (${CONDITION} - 1)"
464 		<< "		{"
465 		<< "			case 0:		res = coords.wzy;	break;"
466 		<< "			case 1:		res = coords.yzw;	break;"
467 		<< "		}"
468 		<< "		break;"
469 		<< "	default:	res = coords.zyx;	break;"
470 		<< "}");
471 
472 	// Negative cases.
473 	ShaderLibrary library(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo());
474 	vector<tcu::TestNode*> negativeCases = library.loadShaderFile("shaders/switch.test");
475 
476 	for (vector<tcu::TestNode*>::iterator i = negativeCases.begin(); i != negativeCases.end(); i++)
477 		addChild(*i);
478 }
479 
480 } // Functional
481 } // gles3
482 } // deqp
483