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 discard statement tests.
22 *//*--------------------------------------------------------------------*/
23
24#include "es3fShaderDiscardTests.hpp"
25#include "glsShaderRenderCase.hpp"
26#include "tcuStringTemplate.hpp"
27#include "gluTexture.hpp"
28
29#include <map>
30#include <sstream>
31#include <string>
32
33#include "glwEnums.hpp"
34#include "glwFunctions.hpp"
35
36using tcu::StringTemplate;
37
38using std::map;
39using std::string;
40using std::ostringstream;
41
42using namespace glu;
43using namespace deqp::gls;
44
45namespace deqp
46{
47namespace gles3
48{
49namespace Functional
50{
51
52class ShaderDiscardCase : public ShaderRenderCase
53{
54public:
55						ShaderDiscardCase			(Context& context, const char* name, const char* description, const char* shaderSource, ShaderEvalFunc evalFunc, bool usesTexture);
56	virtual				~ShaderDiscardCase			(void);
57
58	void				init						(void);
59	void				deinit						(void);
60
61	void				setupUniforms				(int programID, const tcu::Vec4& constCoords);
62
63private:
64	bool				m_usesTexture;
65	glu::Texture2D*		m_brickTexture;
66};
67
68ShaderDiscardCase::ShaderDiscardCase (Context& context, const char* name, const char* description, const char* shaderSource, ShaderEvalFunc evalFunc, bool usesTexture)
69	: ShaderRenderCase	(context.getTestContext(), context.getRenderContext(), context.getContextInfo(), name, description, false, evalFunc)
70	, m_usesTexture		(usesTexture)
71	, m_brickTexture	(DE_NULL)
72{
73	m_fragShaderSource	= shaderSource;
74	m_vertShaderSource	=
75		"#version 300 es\n"
76		"in  highp   vec4 a_position;\n"
77		"in  highp   vec4 a_coords;\n"
78		"out mediump vec4 v_color;\n"
79		"out mediump vec4 v_coords;\n\n"
80		"void main (void)\n"
81		"{\n"
82		"    gl_Position = a_position;\n"
83		"    v_color = vec4(a_coords.xyz, 1.0);\n"
84		"    v_coords = a_coords;\n"
85		"}\n";
86}
87
88ShaderDiscardCase::~ShaderDiscardCase (void)
89{
90	delete m_brickTexture;
91}
92
93void ShaderDiscardCase::init (void)
94{
95	if (m_usesTexture)
96	{
97		m_brickTexture = glu::Texture2D::create(m_renderCtx, m_ctxInfo, m_testCtx.getArchive(), "data/brick.png");
98		m_textures.push_back(TextureBinding(m_brickTexture, tcu::Sampler(tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE,
99																		 tcu::Sampler::LINEAR, tcu::Sampler::LINEAR)));
100	}
101	gls::ShaderRenderCase::init();
102}
103
104void ShaderDiscardCase::deinit (void)
105{
106	gls::ShaderRenderCase::deinit();
107	delete m_brickTexture;
108	m_brickTexture = DE_NULL;
109}
110
111void ShaderDiscardCase::setupUniforms (int programID, const tcu::Vec4&)
112{
113	const glw::Functions& gl = m_renderCtx.getFunctions();
114	gl.uniform1i(gl.getUniformLocation(programID, "ut_brick"), 0);
115}
116
117ShaderDiscardTests::ShaderDiscardTests (Context& context)
118	: TestCaseGroup(context, "discard", "Discard statement tests")
119{
120}
121
122ShaderDiscardTests::~ShaderDiscardTests (void)
123{
124}
125
126enum DiscardMode
127{
128	DISCARDMODE_ALWAYS = 0,
129	DISCARDMODE_NEVER,
130	DISCARDMODE_UNIFORM,
131	DISCARDMODE_DYNAMIC,
132	DISCARDMODE_TEXTURE,
133
134	DISCARDMODE_LAST
135};
136
137enum DiscardTemplate
138{
139	DISCARDTEMPLATE_MAIN_BASIC = 0,
140	DISCARDTEMPLATE_FUNCTION_BASIC,
141	DISCARDTEMPLATE_MAIN_STATIC_LOOP,
142	DISCARDTEMPLATE_MAIN_DYNAMIC_LOOP,
143	DISCARDTEMPLATE_FUNCTION_STATIC_LOOP,
144
145	DISCARDTEMPLATE_LAST
146};
147
148// Evaluation functions
149inline void evalDiscardAlways	(ShaderEvalContext& c) { c.discard(); }
150inline void evalDiscardNever	(ShaderEvalContext& c) { c.color.xyz() = c.coords.swizzle(0,1,2); }
151inline void evalDiscardDynamic	(ShaderEvalContext& c) { c.color.xyz() = c.coords.swizzle(0,1,2); if (c.coords.x()+c.coords.y() > 0.0f) c.discard(); }
152
153inline void evalDiscardTexture (ShaderEvalContext& c)
154{
155	c.color.xyz() = c.coords.swizzle(0,1,2);
156	if (c.texture2D(0, c.coords.swizzle(0,1) * 0.25f + 0.5f).x() < 0.7f)
157		c.discard();
158}
159
160static ShaderEvalFunc getEvalFunc (DiscardMode mode)
161{
162	switch (mode)
163	{
164		case DISCARDMODE_ALWAYS:	return evalDiscardAlways;
165		case DISCARDMODE_NEVER:		return evalDiscardNever;
166		case DISCARDMODE_UNIFORM:	return evalDiscardAlways;
167		case DISCARDMODE_DYNAMIC:	return evalDiscardDynamic;
168		case DISCARDMODE_TEXTURE:	return evalDiscardTexture;
169		default:
170			DE_ASSERT(DE_FALSE);
171			return evalDiscardAlways;
172	}
173}
174
175static const char* getTemplate (DiscardTemplate variant)
176{
177	switch (variant)
178	{
179		case DISCARDTEMPLATE_MAIN_BASIC:
180			return "#version 300 es\n"
181				   "in mediump vec4 v_color;\n"
182				   "in mediump vec4 v_coords;\n"
183				   "layout(location = 0) out mediump vec4 o_color;\n"
184				   "uniform sampler2D    ut_brick;\n"
185				   "uniform mediump int  ui_one;\n\n"
186				   "void main (void)\n"
187				   "{\n"
188				   "    o_color = v_color;\n"
189				   "    ${DISCARD};\n"
190				   "}\n";
191
192		case DISCARDTEMPLATE_FUNCTION_BASIC:
193			return "#version 300 es\n"
194				   "in mediump vec4 v_color;\n"
195				   "in mediump vec4 v_coords;\n"
196				   "layout(location = 0) out mediump vec4 o_color;\n"
197				   "uniform sampler2D    ut_brick;\n"
198				   "uniform mediump int  ui_one;\n\n"
199				   "void myfunc (void)\n"
200				   "{\n"
201				   "    ${DISCARD};\n"
202				   "}\n\n"
203				   "void main (void)\n"
204				   "{\n"
205				   "    o_color = v_color;\n"
206				   "    myfunc();\n"
207				   "}\n";
208
209		case DISCARDTEMPLATE_MAIN_STATIC_LOOP:
210			return "#version 300 es\n"
211				   "in mediump vec4 v_color;\n"
212				   "in mediump vec4 v_coords;\n"
213				   "layout(location = 0) out mediump vec4 o_color;\n"
214				   "uniform sampler2D    ut_brick;\n"
215				   "uniform mediump int  ui_one;\n\n"
216				   "void main (void)\n"
217				   "{\n"
218				   "    o_color = v_color;\n"
219				   "    for (int i = 0; i < 2; i++)\n"
220				   "    {\n"
221				   "        if (i > 0)\n"
222				   "            ${DISCARD};\n"
223				   "    }\n"
224				   "}\n";
225
226		case DISCARDTEMPLATE_MAIN_DYNAMIC_LOOP:
227			return "#version 300 es\n"
228				   "in mediump vec4 v_color;\n"
229				   "in mediump vec4 v_coords;\n"
230				   "layout(location = 0) out mediump vec4 o_color;\n"
231				   "uniform sampler2D    ut_brick;\n"
232				   "uniform mediump int  ui_one;\n"
233				   "uniform mediump int  ui_two;\n\n"
234				   "void main (void)\n"
235				   "{\n"
236				   "    o_color = v_color;\n"
237				   "    for (int i = 0; i < ui_two; i++)\n"
238				   "    {\n"
239				   "        if (i > 0)\n"
240				   "            ${DISCARD};\n"
241				   "    }\n"
242				   "}\n";
243
244		case DISCARDTEMPLATE_FUNCTION_STATIC_LOOP:
245			return "#version 300 es\n"
246				   "in mediump vec4 v_color;\n"
247				   "in mediump vec4 v_coords;\n"
248				   "layout(location = 0) out mediump vec4 o_color;\n"
249				   "uniform sampler2D    ut_brick;\n"
250				   "uniform mediump int  ui_one;\n\n"
251				   "void myfunc (void)\n"
252				   "{\n"
253				   "    for (int i = 0; i < 2; i++)\n"
254				   "    {\n"
255				   "        if (i > 0)\n"
256				   "            ${DISCARD};\n"
257				   "    }\n"
258				   "}\n\n"
259				   "void main (void)\n"
260				   "{\n"
261				   "    o_color = v_color;\n"
262				   "    myfunc();\n"
263				   "}\n";
264
265		default:
266			DE_ASSERT(DE_FALSE);
267			return DE_NULL;
268	}
269}
270
271static const char* getTemplateName (DiscardTemplate variant)
272{
273	switch (variant)
274	{
275		case DISCARDTEMPLATE_MAIN_BASIC:			return "basic";
276		case DISCARDTEMPLATE_FUNCTION_BASIC:		return "function";
277		case DISCARDTEMPLATE_MAIN_STATIC_LOOP:		return "static_loop";
278		case DISCARDTEMPLATE_MAIN_DYNAMIC_LOOP:		return "dynamic_loop";
279		case DISCARDTEMPLATE_FUNCTION_STATIC_LOOP:	return "function_static_loop";
280		default:
281			DE_ASSERT(DE_FALSE);
282			return DE_NULL;
283	}
284}
285
286static const char* getModeName (DiscardMode mode)
287{
288	switch (mode)
289	{
290		case DISCARDMODE_ALWAYS:	return "always";
291		case DISCARDMODE_NEVER:		return "never";
292		case DISCARDMODE_UNIFORM:	return "uniform";
293		case DISCARDMODE_DYNAMIC:	return "dynamic";
294		case DISCARDMODE_TEXTURE:	return "texture";
295		default:
296			DE_ASSERT(DE_FALSE);
297			return DE_NULL;
298	}
299}
300
301static const char* getTemplateDesc (DiscardTemplate variant)
302{
303	switch (variant)
304	{
305		case DISCARDTEMPLATE_MAIN_BASIC:			return "main";
306		case DISCARDTEMPLATE_FUNCTION_BASIC:		return "function";
307		case DISCARDTEMPLATE_MAIN_STATIC_LOOP:		return "static loop";
308		case DISCARDTEMPLATE_MAIN_DYNAMIC_LOOP:		return "dynamic loop";
309		case DISCARDTEMPLATE_FUNCTION_STATIC_LOOP:	return "static loop in function";
310		default:
311			DE_ASSERT(DE_FALSE);
312			return DE_NULL;
313	}
314}
315
316static const char* getModeDesc (DiscardMode mode)
317{
318	switch (mode)
319	{
320		case DISCARDMODE_ALWAYS:	return "Always discard";
321		case DISCARDMODE_NEVER:		return "Never discard";
322		case DISCARDMODE_UNIFORM:	return "Discard based on uniform value";
323		case DISCARDMODE_DYNAMIC:	return "Discard based on varying values";
324		case DISCARDMODE_TEXTURE:	return "Discard based on texture value";
325		default:
326			DE_ASSERT(DE_FALSE);
327			return DE_NULL;
328	}
329}
330
331ShaderDiscardCase* makeDiscardCase (Context& context, DiscardTemplate tmpl, DiscardMode mode)
332{
333	StringTemplate shaderTemplate(getTemplate(tmpl));
334
335	map<string, string> params;
336
337	switch (mode)
338	{
339		case DISCARDMODE_ALWAYS:	params["DISCARD"] = "discard";										break;
340		case DISCARDMODE_NEVER:		params["DISCARD"] = "if (false) discard";							break;
341		case DISCARDMODE_UNIFORM:	params["DISCARD"] = "if (ui_one > 0) discard";						break;
342		case DISCARDMODE_DYNAMIC:	params["DISCARD"] = "if (v_coords.x+v_coords.y > 0.0) discard";		break;
343		case DISCARDMODE_TEXTURE:	params["DISCARD"] = "if (texture(ut_brick, v_coords.xy*0.25+0.5).x < 0.7) discard";	break;
344		default:
345			DE_ASSERT(DE_FALSE);
346			break;
347	}
348
349	string name			= string(getTemplateName(tmpl)) + "_" + getModeName(mode);
350	string description	= string(getModeDesc(mode)) + " in " + getTemplateDesc(tmpl);
351
352	return new ShaderDiscardCase(context, name.c_str(), description.c_str(), shaderTemplate.specialize(params).c_str(), getEvalFunc(mode), mode == DISCARDMODE_TEXTURE);
353}
354
355void ShaderDiscardTests::init (void)
356{
357	for (int tmpl = 0; tmpl < DISCARDTEMPLATE_LAST; tmpl++)
358		for (int mode = 0; mode < DISCARDMODE_LAST; mode++)
359			addChild(makeDiscardCase(m_context, (DiscardTemplate)tmpl, (DiscardMode)mode));
360}
361
362} // Functional
363} // gles3
364} // deqp
365