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 struct tests.
22 *//*--------------------------------------------------------------------*/
23
24#include "es3fShaderFunctionTests.hpp"
25#include "glsShaderRenderCase.hpp"
26#include "gluTexture.hpp"
27#include "tcuStringTemplate.hpp"
28#include "tcuTextureUtil.hpp"
29
30using namespace deqp::gls;
31
32namespace deqp
33{
34namespace gles3
35{
36namespace Functional
37{
38
39typedef void (*SetupUniformsFunc) (const glw::Functions& gl, deUint32 programID, const tcu::Vec4& constCoords);
40
41class ShaderFunctionCase : public ShaderRenderCase
42{
43public:
44						ShaderFunctionCase		(Context& context, const char* name, const char* description, bool isVertexCase, bool usesTextures, ShaderEvalFunc evalFunc, SetupUniformsFunc setupUniformsFunc, const char* vertShaderSource, const char* fragShaderSource);
45						~ShaderFunctionCase		(void);
46
47	void				init					(void);
48	void				deinit					(void);
49
50	virtual void		setupUniforms			(int programID, const tcu::Vec4& constCoords);
51
52private:
53						ShaderFunctionCase		(const ShaderFunctionCase&);
54	ShaderFunctionCase&	operator=				(const ShaderFunctionCase&);
55
56	SetupUniformsFunc	m_setupUniforms;
57	bool				m_usesTexture;
58
59	glu::Texture2D*		m_brickTexture;
60};
61
62ShaderFunctionCase::ShaderFunctionCase (Context& context, const char* name, const char* description, bool isVertexCase, bool usesTextures, ShaderEvalFunc evalFunc, SetupUniformsFunc setupUniformsFunc, const char* vertShaderSource, const char* fragShaderSource)
63	: ShaderRenderCase	(context.getTestContext(), context.getRenderContext(), context.getContextInfo(), name, description, isVertexCase, evalFunc)
64	, m_setupUniforms	(setupUniformsFunc)
65	, m_usesTexture		(usesTextures)
66	, m_brickTexture	(DE_NULL)
67{
68	m_vertShaderSource	= vertShaderSource;
69	m_fragShaderSource	= fragShaderSource;
70}
71
72ShaderFunctionCase::~ShaderFunctionCase (void)
73{
74	delete m_brickTexture;
75}
76
77void ShaderFunctionCase::init (void)
78{
79	if (m_usesTexture)
80	{
81		m_brickTexture = glu::Texture2D::create(m_renderCtx, m_ctxInfo, m_testCtx.getArchive(), "data/brick.png");
82		m_textures.push_back(TextureBinding(m_brickTexture, tcu::Sampler(tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE,
83																		 tcu::Sampler::LINEAR, tcu::Sampler::LINEAR)));
84		DE_ASSERT(m_textures.size() == 1);
85	}
86	gls::ShaderRenderCase::init();
87}
88
89void ShaderFunctionCase::deinit (void)
90{
91	gls::ShaderRenderCase::deinit();
92	delete m_brickTexture;
93	m_brickTexture = DE_NULL;
94}
95
96void ShaderFunctionCase::setupUniforms (int programID, const tcu::Vec4& constCoords)
97{
98	ShaderRenderCase::setupUniforms(programID, constCoords);
99	if (m_setupUniforms)
100		m_setupUniforms(m_renderCtx.getFunctions(), programID, constCoords);
101}
102
103static ShaderFunctionCase* createStructCase (Context& context, const char* name, const char* description, bool isVertexCase, bool usesTextures, ShaderEvalFunc evalFunc, SetupUniformsFunc setupUniforms, const LineStream& shaderSrc, const std::map<std::string, std::string>* additionalParams)
104{
105	static const char* defaultVertSrc =
106		"#version 300 es\n"
107		"in highp vec4 a_position;\n"
108		"in highp vec4 a_coords;\n"
109		"out mediump vec4 v_coords;\n\n"
110		"void main (void)\n"
111		"{\n"
112		"	v_coords = a_coords;\n"
113		"	gl_Position = a_position;\n"
114		"}\n";
115	static const char* defaultFragSrc =
116		"#version 300 es\n"
117		"in mediump vec4 v_color;\n"
118		"layout(location = 0) out mediump vec4 o_color;\n\n"
119		"void main (void)\n"
120		"{\n"
121		"	o_color = v_color;\n"
122		"}\n";
123
124	// Fill in specialization parameters.
125	std::map<std::string, std::string> spParams;
126	if (isVertexCase)
127	{
128		spParams["HEADER"] =
129			"#version 300 es\n"
130			"in highp vec4 a_position;\n"
131			"in highp vec4 a_coords;\n"
132			"out mediump vec4 v_color;";
133		spParams["COORDS"]		= "a_coords";
134		spParams["DST"]			= "v_color";
135		spParams["ASSIGN_POS"]	= "gl_Position = a_position;";
136	}
137	else
138	{
139		spParams["HEADER"]	=
140			"#version 300 es\n"
141			"precision mediump float;\n"
142			"in mediump vec4 v_coords;\n"
143			"layout(location = 0) out mediump vec4 o_color;";
144		spParams["COORDS"]			= "v_coords";
145		spParams["DST"]				= "o_color";
146		spParams["ASSIGN_POS"]		= "";
147	}
148	if (additionalParams)
149		spParams.insert(additionalParams->begin(), additionalParams->end());
150
151	if (isVertexCase)
152		return new ShaderFunctionCase(context, name, description, isVertexCase, usesTextures, evalFunc, setupUniforms, tcu::StringTemplate(shaderSrc.str()).specialize(spParams).c_str(), defaultFragSrc);
153	else
154		return new ShaderFunctionCase(context, name, description, isVertexCase, usesTextures, evalFunc, setupUniforms, defaultVertSrc, tcu::StringTemplate(shaderSrc.str()).specialize(spParams).c_str());
155}
156
157ShaderFunctionTests::ShaderFunctionTests (Context& context)
158	: TestCaseGroup(context, "function", "Function Tests")
159{
160}
161
162ShaderFunctionTests::~ShaderFunctionTests (void)
163{
164}
165
166void ShaderFunctionTests::init (void)
167{
168	#define FUNCTION_CASE_PARAMETERIZED(NAME, DESCRIPTION, SHADER_SRC, EVAL_FUNC_BODY, PARAMS)												\
169		do {																																	\
170			struct Eval_##NAME { static void eval (ShaderEvalContext& c) EVAL_FUNC_BODY };	/* NOLINT(EVAL_FUNC_BODY) */						\
171			addChild(createStructCase(m_context, #NAME "_vertex", DESCRIPTION, true, false, &Eval_##NAME::eval, DE_NULL, SHADER_SRC, PARAMS));	\
172			addChild(createStructCase(m_context, #NAME "_fragment", DESCRIPTION, false, false,&Eval_##NAME::eval, DE_NULL, SHADER_SRC, PARAMS));\
173		} while (deGetFalse())
174
175	#define FUNCTION_CASE(NAME, DESCRIPTION, SHADER_SRC, EVAL_FUNC_BODY) \
176		FUNCTION_CASE_PARAMETERIZED(NAME, DESCRIPTION, SHADER_SRC, EVAL_FUNC_BODY, DE_NULL)
177
178	FUNCTION_CASE(local_variable_aliasing, "Function out parameter aliases local variable",
179		LineStream()
180		<< "${HEADER}"
181		<< ""
182		<< "bool out_params_are_distinct(float x, out float y) {"
183		<< "    y = 2.;"
184		<< "    return x == 1. && y == 2.;"
185		<< "}"
186		<< ""
187		<< "void main (void)"
188		<< "{"
189		<< "    float x = 1.;"
190		<< "    ${DST} = out_params_are_distinct(x, x) ? vec4(0.,1.,0.,1.) : vec4(1.,0.,0.,1.);"
191		<< "	${ASSIGN_POS}"
192		<< "}",
193		{ c.color.xyz() = tcu::Vec3(0.0f, 1.0f, 0.0f); });
194
195	FUNCTION_CASE(global_variable_aliasing, "Function out parameter aliases global variable",
196		LineStream()
197		<< "${HEADER}"
198		<< ""
199		<< ""
200		<< "float x = 1.;"
201		<< "bool out_params_are_distinct_from_global(out float y) {"
202		<< "    y = 2.;"
203		<< "    return x == 1. && y == 2.;"
204		<< "}"
205		<< ""
206		<< "void main (void)"
207		<< "{"
208		<< "    ${DST} = out_params_are_distinct_from_global(x) ? vec4(0.,1.,0.,1.) : vec4(1.,0.,0.,1.);"
209		<< "	${ASSIGN_POS}"
210		<< "}",
211		{ c.color.xyz() = tcu::Vec3(0.0f, 1.0f, 0.0f); });
212}
213
214} // Functional
215} // gles3
216} // deqp
217