1/*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.1 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 built-in constant tests.
22 *//*--------------------------------------------------------------------*/
23
24#include "es31fShaderBuiltinConstantTests.hpp"
25#include "glsShaderExecUtil.hpp"
26#include "deUniquePtr.hpp"
27#include "deStringUtil.hpp"
28#include "tcuTestLog.hpp"
29#include "gluStrUtil.hpp"
30#include "gluContextInfo.hpp"
31#include "glwEnums.hpp"
32#include "glwFunctions.hpp"
33
34using std::string;
35using std::vector;
36using tcu::TestLog;
37
38namespace deqp
39{
40namespace gles31
41{
42namespace Functional
43{
44namespace
45{
46
47static int getInteger (const glw::Functions& gl, deUint32 pname)
48{
49	int value = -1;
50	gl.getIntegerv(pname, &value);
51	GLU_EXPECT_NO_ERROR(gl.getError(), ("glGetIntegerv(" + glu::getGettableStateStr((int)pname).toString() + ")").c_str());
52	return value;
53}
54
55template<deUint32 Pname>
56static int getInteger (const glw::Functions& gl)
57{
58	return getInteger(gl, Pname);
59}
60
61static int getVectorsFromComps (const glw::Functions& gl, deUint32 pname)
62{
63	int value = -1;
64	gl.getIntegerv(pname, &value);
65	GLU_EXPECT_NO_ERROR(gl.getError(), ("glGetIntegerv(" + glu::getGettableStateStr((int)pname).toString() + ")").c_str());
66	TCU_CHECK_MSG(value%4 == 0, ("Expected " + glu::getGettableStateStr((int)pname).toString() + " to be divisible by 4").c_str());
67	return value/4;
68}
69
70template<deUint32 Pname>
71static int getVectorsFromComps (const glw::Functions& gl)
72{
73	return getVectorsFromComps(gl, Pname);
74}
75
76static tcu::IVec3 getIVec3 (const glw::Functions& gl, deUint32 pname)
77{
78	tcu::IVec3 value(-1);
79	for (int ndx = 0; ndx < 3; ndx++)
80		gl.getIntegeri_v(pname, (glw::GLuint)ndx, &value[ndx]);
81	GLU_EXPECT_NO_ERROR(gl.getError(), ("glGetIntegeri_v(" + glu::getGettableStateStr((int)pname).toString() + ")").c_str());
82	return value;
83}
84
85template<deUint32 Pname>
86static tcu::IVec3 getIVec3 (const glw::Functions& gl)
87{
88	return getIVec3(gl, Pname);
89}
90
91static std::string makeCaseName (const std::string& varName)
92{
93	DE_ASSERT(varName.length() > 3);
94	DE_ASSERT(varName.substr(0,3) == "gl_");
95
96	std::ostringstream name;
97	name << de::toLower(char(varName[3]));
98
99	for (size_t ndx = 4; ndx < varName.length(); ndx++)
100	{
101		const char c = char(varName[ndx]);
102		if (de::isUpper(c))
103			name << '_' << de::toLower(c);
104		else
105			name << c;
106	}
107
108	return name.str();
109}
110
111enum
112{
113	VS = (1<<glu::SHADERTYPE_VERTEX),
114	TC = (1<<glu::SHADERTYPE_TESSELLATION_CONTROL),
115	TE = (1<<glu::SHADERTYPE_TESSELLATION_EVALUATION),
116	GS = (1<<glu::SHADERTYPE_GEOMETRY),
117	FS = (1<<glu::SHADERTYPE_FRAGMENT),
118	CS = (1<<glu::SHADERTYPE_COMPUTE),
119
120	SHADER_TYPES = VS|TC|TE|GS|FS|CS
121};
122
123template<typename DataType>
124class ShaderBuiltinConstantCase : public TestCase
125{
126public:
127	typedef DataType (*GetConstantValueFunc) (const glw::Functions& gl);
128
129								ShaderBuiltinConstantCase	(Context& context, const char* varName, GetConstantValueFunc getValue, const char* requiredExt);
130								~ShaderBuiltinConstantCase	(void);
131
132	void						init						(void);
133	IterateResult				iterate						(void);
134
135private:
136	bool						verifyInShaderType			(glu::ShaderType shaderType, DataType reference);
137
138	const std::string			m_varName;
139	const GetConstantValueFunc	m_getValue;
140	const std::string			m_requiredExt;
141};
142
143template<typename DataType>
144ShaderBuiltinConstantCase<DataType>::ShaderBuiltinConstantCase (Context& context, const char* varName, GetConstantValueFunc getValue, const char* requiredExt)
145	: TestCase		(context, makeCaseName(varName).c_str(), varName)
146	, m_varName		(varName)
147	, m_getValue	(getValue)
148	, m_requiredExt	(requiredExt ? requiredExt : "")
149{
150	DE_ASSERT(!requiredExt == m_requiredExt.empty());
151}
152
153template<typename DataType>
154ShaderBuiltinConstantCase<DataType>::~ShaderBuiltinConstantCase (void)
155{
156}
157
158template<typename DataType>
159void ShaderBuiltinConstantCase<DataType>::init (void)
160{
161	const bool isES32 = contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2));
162
163	if (m_requiredExt == "GL_OES_sample_variables" || m_requiredExt == "GL_EXT_geometry_shader" || m_requiredExt == "GL_EXT_tessellation_shader")
164	{
165		if(!isES32)
166		{
167			const std::string message = "The test requires a 3.2 context or support for the extension " + m_requiredExt + ".";
168			TCU_CHECK_AND_THROW(NotSupportedError, m_context.getContextInfo().isExtensionSupported(m_requiredExt.c_str()), message.c_str());
169		}
170	}
171	else if (!m_requiredExt.empty() && !m_context.getContextInfo().isExtensionSupported(m_requiredExt.c_str()))
172			throw tcu::NotSupportedError(m_requiredExt + " not supported");
173
174	if (!isES32 && (m_varName == "gl_MaxTessControlImageUniforms"	||
175		m_varName == "gl_MaxTessEvaluationImageUniforms"			||
176		m_varName == "gl_MaxTessControlAtomicCounters"				||
177		m_varName == "gl_MaxTessEvaluationAtomicCounters"			||
178		m_varName == "gl_MaxTessControlAtomicCounterBuffers"		||
179		m_varName == "gl_MaxTessEvaluationAtomicCounterBuffers"))
180	{
181		std::string message = "The test requires a 3.2 context. The constant '" + m_varName + "' is not supported.";
182		TCU_THROW(NotSupportedError, message.c_str());
183	}
184}
185
186static gls::ShaderExecUtil::ShaderExecutor* createGetConstantExecutor (const glu::RenderContext&	renderCtx,
187																	   glu::ShaderType				shaderType,
188																	   glu::DataType				dataType,
189																	   const std::string&			varName,
190																	   const std::string&			extName)
191{
192	using namespace gls::ShaderExecUtil;
193
194	const bool	isES32		= contextSupports(renderCtx.getType(), glu::ApiType::es(3, 2));
195	ShaderSpec	shaderSpec;
196
197	shaderSpec.version	= isES32 ? glu::GLSL_VERSION_320_ES : glu::GLSL_VERSION_310_ES;
198	shaderSpec.source	= string("result = ") + varName + ";\n";
199
200	shaderSpec.outputs.push_back(Symbol("result", glu::VarType(dataType, glu::PRECISION_HIGHP)));
201
202	if (!extName.empty() && !(isES32 && (extName == "GL_OES_sample_variables" || extName == "GL_EXT_geometry_shader" || extName == "GL_EXT_tessellation_shader")))
203		shaderSpec.globalDeclarations = "#extension " + extName + " : require\n";
204
205	return createExecutor(renderCtx, shaderType, shaderSpec);
206}
207
208template<typename DataType>
209static void logVarValue (tcu::TestLog& log, const std::string& varName, DataType value)
210{
211	log << TestLog::Message << varName << " = " << value << TestLog::EndMessage;
212}
213
214template<>
215void logVarValue<int> (tcu::TestLog& log, const std::string& varName, int value)
216{
217	log << TestLog::Integer(varName, varName, "", QP_KEY_TAG_NONE, value);
218}
219
220template<typename DataType>
221bool ShaderBuiltinConstantCase<DataType>::verifyInShaderType (glu::ShaderType shaderType, DataType reference)
222{
223	using namespace gls::ShaderExecUtil;
224
225	const de::UniquePtr<ShaderExecutor>	shaderExecutor	(createGetConstantExecutor(m_context.getRenderContext(), shaderType, glu::dataTypeOf<DataType>(), m_varName, m_requiredExt));
226	DataType							result			= DataType(-1);
227	void* const							outputs			= &result;
228
229	if (!shaderExecutor->isOk())
230	{
231		shaderExecutor->log(m_testCtx.getLog());
232		TCU_FAIL("Compile failed");
233	}
234
235	shaderExecutor->useProgram();
236	shaderExecutor->execute(1, DE_NULL, &outputs);
237
238	logVarValue(m_testCtx.getLog(), m_varName, result);
239
240	if (result != reference)
241	{
242		m_testCtx.getLog() << TestLog::Message << "ERROR: Expected " << m_varName << " = " << reference << TestLog::EndMessage
243						   << TestLog::Message << "Test shader:" << TestLog::EndMessage;
244		shaderExecutor->log(m_testCtx.getLog());
245		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid builtin constant value");
246		return false;
247	}
248	else
249		return true;
250}
251
252template<typename DataType>
253TestCase::IterateResult ShaderBuiltinConstantCase<DataType>::iterate (void)
254{
255	const DataType	reference	= m_getValue(m_context.getRenderContext().getFunctions());
256
257	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
258
259	for (int shaderType = 0; shaderType < glu::SHADERTYPE_LAST; shaderType++)
260	{
261		if ((SHADER_TYPES & (1<<shaderType)) != 0)
262		{
263			const char* const			shaderTypeName	= glu::getShaderTypeName(glu::ShaderType(shaderType));
264			const tcu::ScopedLogSection	section			(m_testCtx.getLog(), shaderTypeName, shaderTypeName);
265
266			try
267			{
268				const bool isOk = verifyInShaderType(glu::ShaderType(shaderType), reference);
269				DE_ASSERT(isOk || m_testCtx.getTestResult() != QP_TEST_RESULT_PASS);
270				DE_UNREF(isOk);
271			}
272			catch (const tcu::NotSupportedError& e)
273			{
274				m_testCtx.getLog() << TestLog::Message << "Not checking " << shaderTypeName << ": " << e.what() << TestLog::EndMessage;
275			}
276			catch (const tcu::TestError& e)
277			{
278				m_testCtx.getLog() << TestLog::Message << e.what() << TestLog::EndMessage;
279				m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, e.getMessage());
280			}
281		}
282	}
283
284	return STOP;
285}
286
287} // anonymous
288
289ShaderBuiltinConstantTests::ShaderBuiltinConstantTests (Context& context)
290	: TestCaseGroup(context, "builtin_constants", "Built-in Constant Tests")
291{
292}
293
294ShaderBuiltinConstantTests::~ShaderBuiltinConstantTests (void)
295{
296}
297
298void ShaderBuiltinConstantTests::init (void)
299{
300	// Core builtin constants
301	{
302		static const struct
303		{
304			const char*												varName;
305			ShaderBuiltinConstantCase<int>::GetConstantValueFunc	getValue;
306		} intConstants[] =
307		{
308			{ "gl_MaxVertexAttribs",					getInteger<GL_MAX_VERTEX_ATTRIBS>						},
309			{ "gl_MaxVertexUniformVectors",				getInteger<GL_MAX_VERTEX_UNIFORM_VECTORS>				},
310			{ "gl_MaxVertexOutputVectors",				getVectorsFromComps<GL_MAX_VERTEX_OUTPUT_COMPONENTS>	},
311			{ "gl_MaxFragmentInputVectors",				getVectorsFromComps<GL_MAX_FRAGMENT_INPUT_COMPONENTS>	},
312			{ "gl_MaxFragmentUniformVectors",			getInteger<GL_MAX_FRAGMENT_UNIFORM_VECTORS>				},
313			{ "gl_MaxDrawBuffers",						getInteger<GL_MAX_DRAW_BUFFERS>							},
314
315			{ "gl_MaxVertexTextureImageUnits",			getInteger<GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS>			},
316			{ "gl_MaxCombinedTextureImageUnits",		getInteger<GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS>			},
317			{ "gl_MaxTextureImageUnits",				getInteger<GL_MAX_TEXTURE_IMAGE_UNITS>					},
318
319			{ "gl_MinProgramTexelOffset",				getInteger<GL_MIN_PROGRAM_TEXEL_OFFSET>					},
320			{ "gl_MaxProgramTexelOffset",				getInteger<GL_MAX_PROGRAM_TEXEL_OFFSET>					},
321
322			{ "gl_MaxImageUnits",						getInteger<GL_MAX_IMAGE_UNITS>							},
323			{ "gl_MaxVertexImageUniforms",				getInteger<GL_MAX_VERTEX_IMAGE_UNIFORMS>				},
324			{ "gl_MaxFragmentImageUniforms",			getInteger<GL_MAX_FRAGMENT_IMAGE_UNIFORMS>				},
325			{ "gl_MaxComputeImageUniforms",				getInteger<GL_MAX_COMPUTE_IMAGE_UNIFORMS>				},
326			{ "gl_MaxCombinedImageUniforms",			getInteger<GL_MAX_COMBINED_IMAGE_UNIFORMS>				},
327
328			{ "gl_MaxCombinedShaderOutputResources",	getInteger<GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES>		},
329
330			{ "gl_MaxComputeUniformComponents",			getInteger<GL_MAX_COMPUTE_UNIFORM_COMPONENTS>			},
331			{ "gl_MaxComputeTextureImageUnits",			getInteger<GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS>			},
332
333			{ "gl_MaxComputeAtomicCounters",			getInteger<GL_MAX_COMPUTE_ATOMIC_COUNTERS>				},
334			{ "gl_MaxComputeAtomicCounterBuffers",		getInteger<GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS>		},
335
336			{ "gl_MaxVertexAtomicCounters",				getInteger<GL_MAX_VERTEX_ATOMIC_COUNTERS>				},
337			{ "gl_MaxFragmentAtomicCounters",			getInteger<GL_MAX_FRAGMENT_ATOMIC_COUNTERS>				},
338			{ "gl_MaxCombinedAtomicCounters",			getInteger<GL_MAX_COMBINED_ATOMIC_COUNTERS>				},
339			{ "gl_MaxAtomicCounterBindings",			getInteger<GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS>		},
340
341			{ "gl_MaxVertexAtomicCounterBuffers",		getInteger<GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS>		},
342			{ "gl_MaxFragmentAtomicCounterBuffers",		getInteger<GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS>		},
343			{ "gl_MaxCombinedAtomicCounterBuffers",		getInteger<GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS>		},
344			{ "gl_MaxAtomicCounterBufferSize",			getInteger<GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE>			},
345		};
346
347		static const struct
348		{
349			const char*													varName;
350			ShaderBuiltinConstantCase<tcu::IVec3>::GetConstantValueFunc	getValue;
351		} ivec3Constants[] =
352		{
353			{ "gl_MaxComputeWorkGroupCount",			getIVec3<GL_MAX_COMPUTE_WORK_GROUP_COUNT>				},
354			{ "gl_MaxComputeWorkGroupSize",				getIVec3<GL_MAX_COMPUTE_WORK_GROUP_SIZE>				},
355		};
356
357		tcu::TestCaseGroup* const coreGroup = new tcu::TestCaseGroup(m_testCtx, "core", "Core Specification");
358		addChild(coreGroup);
359
360		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(intConstants); ndx++)
361			coreGroup->addChild(new ShaderBuiltinConstantCase<int>(m_context, intConstants[ndx].varName, intConstants[ndx].getValue, DE_NULL));
362
363		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(ivec3Constants); ndx++)
364			coreGroup->addChild(new ShaderBuiltinConstantCase<tcu::IVec3>(m_context, ivec3Constants[ndx].varName, ivec3Constants[ndx].getValue, DE_NULL));
365	}
366
367	// OES_sample_variables
368	{
369		tcu::TestCaseGroup* const sampleVarGroup = new tcu::TestCaseGroup(m_testCtx, "sample_variables", "GL_OES_sample_variables");
370		addChild(sampleVarGroup);
371		sampleVarGroup->addChild(new ShaderBuiltinConstantCase<int>(m_context, "gl_MaxSamples", getInteger<GL_MAX_SAMPLES>, "GL_OES_sample_variables"));
372	}
373
374	// EXT_geometry_shader
375	{
376		static const struct
377		{
378			const char*												varName;
379			ShaderBuiltinConstantCase<int>::GetConstantValueFunc	getValue;
380		} intConstants[] =
381		{
382			{ "gl_MaxGeometryInputComponents",			getInteger<GL_MAX_GEOMETRY_INPUT_COMPONENTS>			},
383			{ "gl_MaxGeometryOutputComponents",			getInteger<GL_MAX_GEOMETRY_OUTPUT_COMPONENTS>			},
384			{ "gl_MaxGeometryImageUniforms",			getInteger<GL_MAX_GEOMETRY_IMAGE_UNIFORMS>				},
385			{ "gl_MaxGeometryTextureImageUnits",		getInteger<GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS>			},
386			{ "gl_MaxGeometryOutputVertices",			getInteger<GL_MAX_GEOMETRY_OUTPUT_VERTICES>				},
387			{ "gl_MaxGeometryTotalOutputComponents",	getInteger<GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS>		},
388			{ "gl_MaxGeometryUniformComponents",		getInteger<GL_MAX_GEOMETRY_UNIFORM_COMPONENTS>			},
389			{ "gl_MaxGeometryAtomicCounters",			getInteger<GL_MAX_GEOMETRY_ATOMIC_COUNTERS>				},
390			{ "gl_MaxGeometryAtomicCounterBuffers",		getInteger<GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS>		},
391		};
392
393		tcu::TestCaseGroup* const geomGroup = new tcu::TestCaseGroup(m_testCtx, "geometry_shader", "GL_EXT_geometry_shader");
394		addChild(geomGroup);
395
396		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(intConstants); ndx++)
397			geomGroup->addChild(new ShaderBuiltinConstantCase<int>(m_context, intConstants[ndx].varName, intConstants[ndx].getValue, "GL_EXT_geometry_shader"));
398	}
399
400	// EXT_tessellation_shader
401	{
402		static const struct
403		{
404			const char*												varName;
405			ShaderBuiltinConstantCase<int>::GetConstantValueFunc	getValue;
406		} intConstants[] =
407		{
408			{ "gl_MaxTessControlInputComponents",			getInteger<GL_MAX_TESS_CONTROL_INPUT_COMPONENTS>			},
409			{ "gl_MaxTessControlOutputComponents",			getInteger<GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS>			},
410			{ "gl_MaxTessControlTextureImageUnits",			getInteger<GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS>			},
411			{ "gl_MaxTessControlUniformComponents",			getInteger<GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS>			},
412			{ "gl_MaxTessControlTotalOutputComponents",		getInteger<GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS>		},
413
414			{ "gl_MaxTessControlImageUniforms",				getInteger<GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS>				},
415			{ "gl_MaxTessEvaluationImageUniforms",			getInteger<GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS>			},
416			{ "gl_MaxTessControlAtomicCounters",			getInteger<GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS>				},
417			{ "gl_MaxTessEvaluationAtomicCounters",			getInteger<GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS>			},
418			{ "gl_MaxTessControlAtomicCounterBuffers",		getInteger<GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS>		},
419			{ "gl_MaxTessEvaluationAtomicCounterBuffers",	getInteger<GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS>	},
420
421			{ "gl_MaxTessEvaluationInputComponents",		getInteger<GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS>			},
422			{ "gl_MaxTessEvaluationOutputComponents",		getInteger<GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS>		},
423			{ "gl_MaxTessEvaluationTextureImageUnits",		getInteger<GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS>		},
424			{ "gl_MaxTessEvaluationUniformComponents",		getInteger<GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS>		},
425
426			{ "gl_MaxTessPatchComponents",					getInteger<GL_MAX_TESS_PATCH_COMPONENTS>					},
427
428			{ "gl_MaxPatchVertices",						getInteger<GL_MAX_PATCH_VERTICES>							},
429			{ "gl_MaxTessGenLevel",							getInteger<GL_MAX_TESS_GEN_LEVEL>							},
430		};
431
432		tcu::TestCaseGroup* const tessGroup = new tcu::TestCaseGroup(m_testCtx, "tessellation_shader", "GL_EXT_tessellation_shader");
433		addChild(tessGroup);
434
435		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(intConstants); ndx++)
436			tessGroup->addChild(new ShaderBuiltinConstantCase<int>(m_context, intConstants[ndx].varName, intConstants[ndx].getValue, "GL_EXT_tessellation_shader"));
437	}
438}
439
440} // Functional
441} // gles31
442} // deqp
443