1/*-------------------------------------------------------------------------
2 * OpenGL Conformance Test Suite
3 * -----------------------------
4 *
5 * Copyright (c) 2016 Google Inc.
6 * Copyright (c) 2016 The Khronos Group Inc.
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 *      http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 *
20 */ /*!
21 * \file
22 * \brief Shader struct tests.
23 */ /*-------------------------------------------------------------------*/
24
25#include "glcShaderFunctionTests.hpp"
26#include "glcShaderRenderCase.hpp"
27#include "gluTexture.hpp"
28#include "tcuStringTemplate.hpp"
29#include "tcuTextureUtil.hpp"
30
31using namespace glu;
32
33namespace deqp
34{
35
36typedef void (*SetupUniformsFunc)(const glw::Functions& gl, deUint32 programID, const tcu::Vec4& constCoords);
37
38class ShaderFunctionCase : public ShaderRenderCase
39{
40public:
41	ShaderFunctionCase(Context& context, const char* name, const char* description, bool isVertexCase, bool usesTextures,
42					 ShaderEvalFunc evalFunc, SetupUniformsFunc setupUniformsFunc, const char* vertShaderSource,
43					 const char* fragShaderSource);
44	~ShaderFunctionCase(void);
45
46	void init(void);
47	void deinit(void);
48
49	virtual void setupUniforms(deUint32 programID, const tcu::Vec4& constCoords);
50
51private:
52	ShaderFunctionCase(const ShaderFunctionCase&);
53	ShaderFunctionCase& operator=(const ShaderFunctionCase&);
54
55	SetupUniformsFunc m_setupUniforms;
56	bool			  m_usesTexture;
57
58	glu::Texture2D* m_gradientTexture;
59};
60
61ShaderFunctionCase::ShaderFunctionCase(Context& context, const char* name, const char* description, bool isVertexCase,
62								   bool usesTextures, ShaderEvalFunc evalFunc, SetupUniformsFunc setupUniformsFunc,
63								   const char* vertShaderSource, const char* fragShaderSource)
64	: ShaderRenderCase(context.getTestContext(), context.getRenderContext(), context.getContextInfo(), name,
65					   description, isVertexCase, evalFunc)
66	, m_setupUniforms(setupUniformsFunc)
67	, m_usesTexture(usesTextures)
68	, m_gradientTexture(DE_NULL)
69{
70	m_vertShaderSource = vertShaderSource;
71	m_fragShaderSource = fragShaderSource;
72}
73
74ShaderFunctionCase::~ShaderFunctionCase(void)
75{
76}
77
78void ShaderFunctionCase::init(void)
79{
80	if (m_usesTexture)
81	{
82		m_gradientTexture = new glu::Texture2D(m_renderCtx, GL_RGBA8, 128, 128);
83
84		m_gradientTexture->getRefTexture().allocLevel(0);
85		tcu::fillWithComponentGradients(m_gradientTexture->getRefTexture().getLevel(0), tcu::Vec4(0.0f),
86										tcu::Vec4(1.0f));
87		m_gradientTexture->upload();
88
89		m_textures.push_back(TextureBinding(
90			m_gradientTexture, tcu::Sampler(tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE,
91											tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::LINEAR, tcu::Sampler::LINEAR)));
92		DE_ASSERT(m_textures.size() == 1);
93	}
94	ShaderRenderCase::init();
95}
96
97void ShaderFunctionCase::deinit(void)
98{
99	if (m_usesTexture)
100	{
101		delete m_gradientTexture;
102	}
103	ShaderRenderCase::deinit();
104}
105
106void ShaderFunctionCase::setupUniforms(deUint32 programID, const tcu::Vec4& constCoords)
107{
108	ShaderRenderCase::setupUniforms(programID, constCoords);
109	if (m_setupUniforms)
110		m_setupUniforms(m_renderCtx.getFunctions(), programID, constCoords);
111}
112
113static ShaderFunctionCase* createStructCase(Context& context, const char* name, const char* description,
114										  glu::GLSLVersion glslVersion, bool isVertexCase, bool usesTextures,
115										  ShaderEvalFunc evalFunc, SetupUniformsFunc setupUniforms,
116										  const LineStream& shaderSrc)
117{
118	const std::string versionDecl = glu::getGLSLVersionDeclaration(glslVersion);
119
120	const std::string defaultVertSrc = versionDecl + "\n"
121													 "in highp vec4 a_position;\n"
122													 "in highp vec4 a_coords;\n"
123													 "out mediump vec4 v_coords;\n\n"
124													 "void main (void)\n"
125													 "{\n"
126													 "   v_coords = a_coords;\n"
127													 "   gl_Position = a_position;\n"
128													 "}\n";
129	const std::string defaultFragSrc = versionDecl + "\n"
130													 "in mediump vec4 v_color;\n"
131													 "layout(location = 0) out mediump vec4 o_color;\n\n"
132													 "void main (void)\n"
133													 "{\n"
134													 "   o_color = v_color;\n"
135													 "}\n";
136
137	// Fill in specialization parameters.
138	std::map<std::string, std::string> spParams;
139	if (isVertexCase)
140	{
141		spParams["HEADER"] = versionDecl + "\n"
142										   "in highp vec4 a_position;\n"
143										   "in highp vec4 a_coords;\n"
144										   "out mediump vec4 v_color;";
145		spParams["COORDS"]	 = "a_coords";
146		spParams["DST"]		   = "v_color";
147		spParams["ASSIGN_POS"] = "gl_Position = a_position;";
148	}
149	else
150	{
151		spParams["HEADER"] = versionDecl + "\n"
152										   "#ifdef GL_ES\n"
153										   "    precision mediump float;\n"
154										   "#endif\n"
155										   "\n"
156										   "in mediump vec4 v_coords;\n"
157										   "layout(location = 0) out mediump vec4 o_color;";
158		spParams["COORDS"]	 = "v_coords";
159		spParams["DST"]		   = "o_color";
160		spParams["ASSIGN_POS"] = "";
161	}
162
163	if (isVertexCase)
164		return new ShaderFunctionCase(context, name, description, isVertexCase, usesTextures, evalFunc, setupUniforms,
165									tcu::StringTemplate(shaderSrc.str()).specialize(spParams).c_str(),
166									defaultFragSrc.c_str());
167	else
168		return new ShaderFunctionCase(context, name, description, isVertexCase, usesTextures, evalFunc, setupUniforms,
169									defaultVertSrc.c_str(),
170									tcu::StringTemplate(shaderSrc.str()).specialize(spParams).c_str());
171}
172
173ShaderFunctionTests::ShaderFunctionTests(Context& context, glu::GLSLVersion glslVersion)
174	: TestCaseGroup(context, "function", "Function Tests"), m_glslVersion(glslVersion)
175{
176}
177
178ShaderFunctionTests::~ShaderFunctionTests(void)
179{
180}
181
182void ShaderFunctionTests::init(void)
183{
184#define FUNCTION_CASE(NAME, DESCRIPTION, SHADER_SRC, EVAL_FUNC_BODY)                                      \
185	do                                                                                                    \
186	{                                                                                                     \
187		struct Eval_##NAME                                                                                \
188		{                                                                                                 \
189			static void eval(ShaderEvalContext& c) EVAL_FUNC_BODY                                         \
190		};                                                                                                \
191		addChild(createStructCase(m_context, #NAME "_vertex", DESCRIPTION, m_glslVersion, true, false,    \
192								  &Eval_##NAME::eval, DE_NULL, SHADER_SRC));                              \
193		addChild(createStructCase(m_context, #NAME "_fragment", DESCRIPTION, m_glslVersion, false, false, \
194								  &Eval_##NAME::eval, DE_NULL, SHADER_SRC));                              \
195	} while (deGetFalse())
196
197	FUNCTION_CASE(local_variable_aliasing, "Function out parameter aliases local variable",
198				  LineStream() << "${HEADER}"
199							   << ""
200							   << "bool out_params_are_distinct(float x, out float y) {"
201							   << "    y = 2.;"
202							   << "    return x == 1. && y == 2.;"
203							   << "}"
204							   << ""
205							   << "void main (void)"
206							   << "{"
207							   << "    float x = 1.;"
208							   << "    ${DST} = out_params_are_distinct(x, 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	FUNCTION_CASE(global_variable_aliasing, "Function out parameter aliases global variable",
214				  LineStream() << "${HEADER}"
215							   << ""
216							   << "float x = 1.;"
217							   << "bool out_params_are_distinct_from_global(out float y) {"
218							   << "    y = 2.;"
219							   << "    return x == 1. && y == 2.;"
220							   << "}"
221							   << ""
222							   << "void main (void)"
223							   << "{"
224							   << "    ${DST} = out_params_are_distinct_from_global(x) ? vec4(0.,1.,0.,1.) : vec4(1.,0.,0.,1.);"
225							   << "    ${ASSIGN_POS}"
226							   << "}",
227				  { c.color.xyz() = tcu::Vec3(0.0f, 1.0f, 0.0f); });
228}
229
230} // deqp
231