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 state query tests
22 *//*--------------------------------------------------------------------*/
23
24#include "es31fShaderStateQueryTests.hpp"
25#include "es31fInfoLogQueryShared.hpp"
26#include "glsStateQueryUtil.hpp"
27#include "tcuTestLog.hpp"
28#include "tcuStringTemplate.hpp"
29#include "gluShaderProgram.hpp"
30#include "gluRenderContext.hpp"
31#include "gluCallLogWrapper.hpp"
32#include "gluContextInfo.hpp"
33#include "gluStrUtil.hpp"
34#include "glwFunctions.hpp"
35#include "glwEnums.hpp"
36
37namespace deqp
38{
39namespace gles31
40{
41namespace Functional
42{
43namespace
44{
45
46static inline std::string brokenShaderSource (const glu::ContextType &contextType)
47{
48	const std::string glslVersionDecl = glu::getGLSLVersionDeclaration(glu::getContextTypeGLSLVersion(contextType));
49
50	return	glslVersionDecl + "\n"
51			"broken, this should not compile,\n"
52			"{";
53}
54
55class BaseTypeCase : public TestCase
56{
57public:
58	struct TestTypeInfo
59	{
60		glw::GLenum	glType;
61		const char*	declarationStr;
62		const char*	accessStr;
63	};
64
65										BaseTypeCase		(Context& ctx, const char* name, const char* desc, const char* extension);
66
67private:
68	IterateResult						iterate				(void);
69	virtual std::vector<TestTypeInfo>	getInfos			(void) const = 0;
70	virtual void						checkRequirements	(void) const;
71
72	const char* const					m_extension;
73};
74
75BaseTypeCase::BaseTypeCase (Context& ctx, const char* name, const char* desc, const char* extension)
76	: TestCase		(ctx, name, desc)
77	, m_extension	(extension)
78{
79}
80
81BaseTypeCase::IterateResult BaseTypeCase::iterate (void)
82{
83	static const char* const	vertexSourceTemplate	=	"${VERSIONDECL}\n"
84															"in highp vec4 a_position;\n"
85															"void main(void)\n"
86															"{\n"
87															"	gl_Position = a_position;\n"
88															"}\n";
89	static const char* const	fragmentSourceTemplate	=	"${VERSIONDECL}\n"
90															"${EXTENSIONSTATEMENT}"
91															"${DECLARATIONSTR};\n"
92															"layout(location = 0) out highp vec4 dEQP_FragColor;\n"
93															"void main(void)\n"
94															"{\n"
95															"	dEQP_FragColor = vec4(${ACCESSSTR});\n"
96															"}\n";
97
98	tcu::ResultCollector		result			(m_testCtx.getLog());
99	std::vector<TestTypeInfo>	samplerTypes	= getInfos();
100	auto						ctxType			= m_context.getRenderContext().getType();
101	const bool					isES32orGL45	= glu::contextSupports(ctxType, glu::ApiType::es(3, 2)) ||
102												  glu::contextSupports(ctxType, glu::ApiType::core(4, 5));
103
104	if (m_extension && !isES32orGL45 && !m_context.getContextInfo().isExtensionSupported(m_extension))
105		throw tcu::NotSupportedError("Test requires " + std::string(m_extension));
106	checkRequirements();
107
108	for (int typeNdx = 0; typeNdx < (int)samplerTypes.size(); ++typeNdx)
109	{
110		const tcu::ScopedLogSection			section	(m_testCtx.getLog(),
111													 std::string(glu::getShaderVarTypeStr(samplerTypes[typeNdx].glType).toString()),
112													 "Uniform type " + glu::getShaderVarTypeStr(samplerTypes[typeNdx].glType).toString());
113
114		std::map<std::string, std::string>	shaderArgs;
115		shaderArgs["DECLARATIONSTR"]		= samplerTypes[typeNdx].declarationStr;
116		shaderArgs["ACCESSSTR"]				= samplerTypes[typeNdx].accessStr;
117		shaderArgs["EXTENSIONSTATEMENT"]	= (m_extension && !isES32orGL45) ? (std::string() + "#extension " + m_extension + " : require\n") : ("");
118		shaderArgs["VERSIONDECL"]			= glu::getGLSLVersionDeclaration(glu::getContextTypeGLSLVersion(ctxType));
119
120		const std::string					fragmentSource	= tcu::StringTemplate(fragmentSourceTemplate).specialize(shaderArgs);
121		const std::string					vertexSource	= tcu::StringTemplate(vertexSourceTemplate).specialize(shaderArgs);
122		const glw::Functions&				gl				= m_context.getRenderContext().getFunctions();
123		glu::ShaderProgram					program			(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(vertexSource) << glu::FragmentSource(fragmentSource));
124
125		m_testCtx.getLog() << tcu::TestLog::Message << "Building program with uniform sampler of type " << glu::getShaderVarTypeStr(samplerTypes[typeNdx].glType) << tcu::TestLog::EndMessage;
126
127		if (!program.isOk())
128		{
129			m_testCtx.getLog() << program;
130			result.fail("could not build shader");
131		}
132		else
133		{
134			// only one uniform -- uniform at index 0
135			int uniforms = 0;
136			gl.getProgramiv(program.getProgram(), GL_ACTIVE_UNIFORMS, &uniforms);
137
138			if (uniforms != 1)
139				result.fail("Unexpected GL_ACTIVE_UNIFORMS, expected 1");
140			else
141			{
142				// check type
143				const glw::GLuint	uniformIndex	= 0;
144				glw::GLint			type			= 0;
145
146				m_testCtx.getLog() << tcu::TestLog::Message << "Verifying uniform type." << tcu::TestLog::EndMessage;
147				gl.getActiveUniformsiv(program.getProgram(), 1, &uniformIndex, GL_UNIFORM_TYPE, &type);
148
149				if (type != (glw::GLint)samplerTypes[typeNdx].glType)
150				{
151					std::ostringstream buf;
152					buf << "Invalid type, expected " << samplerTypes[typeNdx].glType << ", got " << type;
153					result.fail(buf.str());
154				}
155			}
156		}
157
158		GLU_EXPECT_NO_ERROR(gl.getError(), "");
159	}
160
161	result.setTestContextResult(m_testCtx);
162	return STOP;
163}
164
165void BaseTypeCase::checkRequirements (void) const
166{
167}
168
169class CoreSamplerTypeCase : public BaseTypeCase
170{
171public:
172								CoreSamplerTypeCase	(Context& ctx, const char* name, const char* desc);
173
174private:
175	std::vector<TestTypeInfo>	getInfos			(void) const;
176};
177
178CoreSamplerTypeCase::CoreSamplerTypeCase (Context& ctx, const char* name, const char* desc)
179	: BaseTypeCase(ctx, name, desc, DE_NULL)
180{
181}
182
183std::vector<BaseTypeCase::TestTypeInfo> CoreSamplerTypeCase::getInfos (void) const
184{
185	static const TestTypeInfo samplerTypes[] =
186	{
187		{ GL_SAMPLER_2D_MULTISAMPLE,				"uniform highp sampler2DMS u_sampler",	"texelFetch(u_sampler, ivec2(gl_FragCoord.xy), 0)" },
188		{ GL_INT_SAMPLER_2D_MULTISAMPLE,			"uniform highp isampler2DMS u_sampler",	"texelFetch(u_sampler, ivec2(gl_FragCoord.xy), 0)" },
189		{ GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE,	"uniform highp usampler2DMS u_sampler",	"texelFetch(u_sampler, ivec2(gl_FragCoord.xy), 0)" },
190	};
191
192	std::vector<TestTypeInfo> infos;
193	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(samplerTypes); ++ndx)
194		infos.push_back(samplerTypes[ndx]);
195
196	return infos;
197}
198
199class MSArraySamplerTypeCase : public BaseTypeCase
200{
201public:
202								MSArraySamplerTypeCase	(Context& ctx, const char* name, const char* desc);
203
204private:
205	std::vector<TestTypeInfo>	getInfos				(void) const;
206};
207
208MSArraySamplerTypeCase::MSArraySamplerTypeCase (Context& ctx, const char* name, const char* desc)
209	: BaseTypeCase(ctx, name, desc, "GL_OES_texture_storage_multisample_2d_array")
210{
211}
212
213std::vector<BaseTypeCase::TestTypeInfo> MSArraySamplerTypeCase::getInfos (void) const
214{
215	static const TestTypeInfo samplerTypes[] =
216	{
217		{ GL_SAMPLER_2D_MULTISAMPLE_ARRAY,				"uniform highp sampler2DMSArray u_sampler",		"texelFetch(u_sampler, ivec3(gl_FragCoord.xyz), 0)" },
218		{ GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY,			"uniform highp isampler2DMSArray u_sampler",	"texelFetch(u_sampler, ivec3(gl_FragCoord.xyz), 0)" },
219		{ GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY,	"uniform highp usampler2DMSArray u_sampler",	"texelFetch(u_sampler, ivec3(gl_FragCoord.xyz), 0)" },
220	};
221
222	std::vector<TestTypeInfo> infos;
223	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(samplerTypes); ++ndx)
224		infos.push_back(samplerTypes[ndx]);
225
226	return infos;
227}
228
229class TextureBufferSamplerTypeCase : public BaseTypeCase
230{
231public:
232								TextureBufferSamplerTypeCase	(Context& ctx, const char* name, const char* desc);
233
234private:
235	std::vector<TestTypeInfo>	getInfos						(void) const;
236};
237
238TextureBufferSamplerTypeCase::TextureBufferSamplerTypeCase (Context& ctx, const char* name, const char* desc)
239	: BaseTypeCase(ctx, name, desc, "GL_EXT_texture_buffer")
240{
241}
242
243std::vector<BaseTypeCase::TestTypeInfo> TextureBufferSamplerTypeCase::getInfos (void) const
244{
245	static const TestTypeInfo samplerTypes[] =
246	{
247		{ GL_SAMPLER_BUFFER,				"uniform highp samplerBuffer u_sampler",	"texelFetch(u_sampler, int(gl_FragCoord.x))" },
248		{ GL_INT_SAMPLER_BUFFER,			"uniform highp isamplerBuffer u_sampler",	"texelFetch(u_sampler, int(gl_FragCoord.x))" },
249		{ GL_UNSIGNED_INT_SAMPLER_BUFFER,	"uniform highp usamplerBuffer u_sampler",	"texelFetch(u_sampler, int(gl_FragCoord.x))" },
250	};
251
252	std::vector<TestTypeInfo> infos;
253	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(samplerTypes); ++ndx)
254		infos.push_back(samplerTypes[ndx]);
255
256	return infos;
257}
258
259class TextureBufferImageTypeCase : public BaseTypeCase
260{
261public:
262								TextureBufferImageTypeCase	(Context& ctx, const char* name, const char* desc);
263
264private:
265	std::vector<TestTypeInfo>	getInfos					(void) const;
266	void						checkRequirements			(void) const;
267};
268
269TextureBufferImageTypeCase::TextureBufferImageTypeCase (Context& ctx, const char* name, const char* desc)
270	: BaseTypeCase(ctx, name, desc, "GL_EXT_texture_buffer")
271{
272}
273
274std::vector<BaseTypeCase::TestTypeInfo> TextureBufferImageTypeCase::getInfos (void) const
275{
276	static const TestTypeInfo samplerTypes[] =
277	{
278		{ GL_IMAGE_BUFFER,				"layout(binding=0, rgba8) readonly uniform highp imageBuffer u_image",	"imageLoad(u_image, int(gl_FragCoord.x))" },
279		{ GL_INT_IMAGE_BUFFER,			"layout(binding=0, r32i) readonly uniform highp iimageBuffer u_image",	"imageLoad(u_image, int(gl_FragCoord.x))" },
280		{ GL_UNSIGNED_INT_IMAGE_BUFFER,	"layout(binding=0, r32ui) readonly uniform highp uimageBuffer u_image",	"imageLoad(u_image, int(gl_FragCoord.x))" },
281	};
282
283	std::vector<TestTypeInfo> infos;
284	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(samplerTypes); ++ndx)
285		infos.push_back(samplerTypes[ndx]);
286
287	return infos;
288}
289
290void TextureBufferImageTypeCase::checkRequirements (void) const
291{
292	if (m_context.getContextInfo().getInt(GL_MAX_FRAGMENT_IMAGE_UNIFORMS) < 1)
293		throw tcu::NotSupportedError("Test requires fragment images");
294}
295
296class CubeArraySamplerTypeCase : public BaseTypeCase
297{
298public:
299								CubeArraySamplerTypeCase	(Context& ctx, const char* name, const char* desc);
300
301private:
302	std::vector<TestTypeInfo>	getInfos						(void) const;
303};
304
305CubeArraySamplerTypeCase::CubeArraySamplerTypeCase (Context& ctx, const char* name, const char* desc)
306	: BaseTypeCase(ctx, name, desc, "GL_EXT_texture_cube_map_array")
307{
308}
309
310std::vector<BaseTypeCase::TestTypeInfo> CubeArraySamplerTypeCase::getInfos (void) const
311{
312	static const TestTypeInfo samplerTypes[] =
313	{
314		{ GL_SAMPLER_CUBE_MAP_ARRAY,				"uniform highp samplerCubeArray u_sampler",			"texture(u_sampler, gl_FragCoord.xxyz)"			},
315		{ GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW,			"uniform highp samplerCubeArrayShadow u_sampler",	"texture(u_sampler, gl_FragCoord.xxyz, 0.5)"	},
316		{ GL_INT_SAMPLER_CUBE_MAP_ARRAY,			"uniform highp isamplerCubeArray u_sampler",		"texture(u_sampler, gl_FragCoord.xxyz)"			},
317		{ GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY,	"uniform highp usamplerCubeArray u_sampler",		"texture(u_sampler, gl_FragCoord.xxyz)"			},
318	};
319
320	std::vector<TestTypeInfo> infos;
321	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(samplerTypes); ++ndx)
322		infos.push_back(samplerTypes[ndx]);
323
324	return infos;
325}
326
327class CubeArrayImageTypeCase : public BaseTypeCase
328{
329public:
330								CubeArrayImageTypeCase	(Context& ctx, const char* name, const char* desc);
331
332private:
333	std::vector<TestTypeInfo>	getInfos				(void) const;
334	void						checkRequirements		(void) const;
335};
336
337CubeArrayImageTypeCase::CubeArrayImageTypeCase (Context& ctx, const char* name, const char* desc)
338	: BaseTypeCase(ctx, name, desc, "GL_EXT_texture_cube_map_array")
339{
340}
341
342std::vector<BaseTypeCase::TestTypeInfo> CubeArrayImageTypeCase::getInfos (void) const
343{
344	static const TestTypeInfo samplerTypes[] =
345	{
346		{ GL_IMAGE_CUBE_MAP_ARRAY,				"layout(binding=0, rgba8) readonly uniform highp imageCubeArray u_image",	"imageLoad(u_image, ivec3(gl_FragCoord.xyx))"	},
347		{ GL_INT_IMAGE_CUBE_MAP_ARRAY,			"layout(binding=0, r32i) readonly uniform highp iimageCubeArray u_image",	"imageLoad(u_image, ivec3(gl_FragCoord.xyx))"	},
348		{ GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY,	"layout(binding=0, r32ui) readonly uniform highp uimageCubeArray u_image",	"imageLoad(u_image, ivec3(gl_FragCoord.xyx))"	},
349	};
350
351	std::vector<TestTypeInfo> infos;
352	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(samplerTypes); ++ndx)
353		infos.push_back(samplerTypes[ndx]);
354
355	return infos;
356}
357
358void CubeArrayImageTypeCase::checkRequirements (void) const
359{
360	if (m_context.getContextInfo().getInt(GL_MAX_FRAGMENT_IMAGE_UNIFORMS) < 1)
361		throw tcu::NotSupportedError("Test requires fragment images");
362}
363
364class ShaderLogCase : public TestCase
365{
366public:
367							ShaderLogCase	(Context& ctx, const char* name, const char* desc, glu::ShaderType shaderType);
368
369private:
370	void					init			(void);
371	IterateResult			iterate			(void);
372
373	const glu::ShaderType	m_shaderType;
374};
375
376ShaderLogCase::ShaderLogCase (Context& ctx, const char* name, const char* desc, glu::ShaderType shaderType)
377	: TestCase		(ctx, name, desc)
378	, m_shaderType	(shaderType)
379{
380}
381
382void ShaderLogCase::init (void)
383{
384	auto		ctxType			= m_context.getRenderContext().getType();
385	const bool	isES32orGL45	= glu::contextSupports(ctxType, glu::ApiType::es(3, 2)) ||
386								  glu::contextSupports(ctxType, glu::ApiType::core(4, 5));
387
388	switch (m_shaderType)
389	{
390		case glu::SHADERTYPE_VERTEX:
391		case glu::SHADERTYPE_FRAGMENT:
392		case glu::SHADERTYPE_COMPUTE:
393			break;
394
395		case glu::SHADERTYPE_GEOMETRY:
396			if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader") && !isES32orGL45)
397				throw tcu::NotSupportedError("Test requires GL_EXT_geometry_shader extension or an OpenGL ES 3.2 or higher context.");
398			break;
399
400		case glu::SHADERTYPE_TESSELLATION_CONTROL:
401		case glu::SHADERTYPE_TESSELLATION_EVALUATION:
402			if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_tessellation_shader") && !isES32orGL45)
403				throw tcu::NotSupportedError("Test requires GL_EXT_tessellation_shader extension or an OpenGL ES 3.2 or higher context.");
404			break;
405
406		default:
407			DE_ASSERT(false);
408			break;
409	}
410}
411
412ShaderLogCase::IterateResult ShaderLogCase::iterate (void)
413{
414	using gls::StateQueryUtil::StateQueryMemoryWriteGuard;
415
416	tcu::ResultCollector					result			(m_testCtx.getLog());
417	glu::CallLogWrapper						gl				(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
418	deUint32								shader			= 0;
419	const std::string						source			= brokenShaderSource(m_context.getRenderContext().getType());
420	const char* const						brokenSource	= source.c_str();
421	StateQueryMemoryWriteGuard<glw::GLint>	logLen;
422
423	gl.enableLogging(true);
424
425	m_testCtx.getLog() << tcu::TestLog::Message << "Trying to compile broken shader source." << tcu::TestLog::EndMessage;
426
427	shader = gl.glCreateShader(glu::getGLShaderType(m_shaderType));
428	GLS_COLLECT_GL_ERROR(result, gl.glGetError(), "create shader");
429
430	gl.glShaderSource(shader, 1, &brokenSource, DE_NULL);
431	gl.glCompileShader(shader);
432	GLS_COLLECT_GL_ERROR(result, gl.glGetError(), "compile");
433
434	gl.glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLen);
435	logLen.verifyValidity(result);
436
437	if (!logLen.isUndefined())
438		verifyInfoLogQuery(result, gl, logLen, shader, &glu::CallLogWrapper::glGetShaderInfoLog, "glGetShaderInfoLog");
439
440	gl.glDeleteShader(shader);
441	GLS_COLLECT_GL_ERROR(result, gl.glGetError(), "delete");
442
443	result.setTestContextResult(m_testCtx);
444	return STOP;
445}
446
447} // anonymous
448
449ShaderStateQueryTests::ShaderStateQueryTests (Context& context)
450	: TestCaseGroup(context, "shader", "Shader state query tests")
451{
452}
453
454ShaderStateQueryTests::~ShaderStateQueryTests (void)
455{
456}
457
458void ShaderStateQueryTests::init (void)
459{
460	addChild(new CoreSamplerTypeCase			(m_context, "sampler_type",						"Sampler type cases"));
461	addChild(new MSArraySamplerTypeCase			(m_context, "sampler_type_multisample_array",	"MSAA array sampler type cases"));
462	addChild(new TextureBufferSamplerTypeCase	(m_context, "sampler_type_texture_buffer",		"Texture buffer sampler type cases"));
463	addChild(new TextureBufferImageTypeCase		(m_context, "image_type_texture_buffer",		"Texture buffer image type cases"));
464	addChild(new CubeArraySamplerTypeCase		(m_context, "sampler_type_cube_array",			"Cube array sampler type cases"));
465	addChild(new CubeArrayImageTypeCase			(m_context, "image_type_cube_array",			"Cube array image type cases"));
466
467	// shader info log tests
468	// \note, there exists similar tests in gles3 module. However, the gles31 could use a different
469	//        shader compiler with different INFO_LOG bugs.
470	{
471		static const struct
472		{
473			const char*		caseName;
474			glu::ShaderType	caseType;
475		} shaderTypes[] =
476		{
477			{ "info_log_vertex",		glu::SHADERTYPE_VERTEX					},
478			{ "info_log_fragment",		glu::SHADERTYPE_FRAGMENT				},
479			{ "info_log_geometry",		glu::SHADERTYPE_GEOMETRY				},
480			{ "info_log_tess_ctrl",		glu::SHADERTYPE_TESSELLATION_CONTROL	},
481			{ "info_log_tess_eval",		glu::SHADERTYPE_TESSELLATION_EVALUATION	},
482			{ "info_log_compute",		glu::SHADERTYPE_COMPUTE					},
483		};
484
485		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(shaderTypes); ++ndx)
486			addChild(new ShaderLogCase(m_context, shaderTypes[ndx].caseName, "", shaderTypes[ndx].caseType));
487	}
488}
489
490} // Functional
491} // gles31
492} // deqp
493