1/*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.1 Module
3 * -------------------------------------------------
4 *
5 * Copyright 2016 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 Negative Shader Storage Tests
22 *//*--------------------------------------------------------------------*/
23
24#include "es31fNegativeShaderStorageTests.hpp"
25
26#include "gluShaderProgram.hpp"
27#include "glwDefs.hpp"
28#include "glwEnums.hpp"
29
30namespace deqp
31{
32namespace gles31
33{
34namespace Functional
35{
36namespace NegativeTestShared
37{
38namespace
39{
40
41void verifyProgram(NegativeTestContext& ctx, glu::ProgramSources sources)
42{
43	tcu::TestLog&				log			= ctx.getLog();
44	const glu::ShaderProgram	program		(ctx.getRenderContext(), sources);
45	bool						testFailed	= false;
46
47	log << program;
48
49	testFailed = program.getProgramInfo().linkOk;
50
51	if (testFailed)
52	{
53		const char* const message("Program was not expected to link.");
54		log << tcu::TestLog::Message << message << tcu::TestLog::EndMessage;
55		ctx.fail(message);
56	}
57}
58
59const char* getShaderExtensionDeclaration (glw::GLenum glShaderType)
60{
61	switch (glShaderType)
62	{
63		case GL_TESS_CONTROL_SHADER:
64		case GL_TESS_EVALUATION_SHADER: return "#extension GL_EXT_tessellation_shader : require\n";
65		case GL_GEOMETRY_SHADER:		return "#extension GL_EXT_geometry_shader : require\n";
66		default:
67			return "";
68	}
69}
70
71glu::ShaderType getGLUShaderType (glw::GLenum glShaderType)
72{
73	switch (glShaderType)
74	{
75		case GL_VERTEX_SHADER:			 return glu::SHADERTYPE_VERTEX;
76		case GL_FRAGMENT_SHADER:		 return glu::SHADERTYPE_FRAGMENT;
77		case GL_TESS_CONTROL_SHADER:	 return glu::SHADERTYPE_TESSELLATION_CONTROL;
78		case GL_TESS_EVALUATION_SHADER:	 return glu::SHADERTYPE_TESSELLATION_EVALUATION;
79		case GL_GEOMETRY_SHADER:		 return glu::SHADERTYPE_GEOMETRY;
80		case GL_COMPUTE_SHADER:			 return glu::SHADERTYPE_COMPUTE;
81		default:
82			DE_FATAL("Unknown shader type");
83			return glu::SHADERTYPE_LAST;
84	}
85}
86
87glw::GLenum getMaxSSBlockSizeEnum (glw::GLenum glShaderType)
88{
89	switch (glShaderType)
90	{
91		case GL_VERTEX_SHADER:			 return GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS;
92		case GL_FRAGMENT_SHADER:		 return GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS;
93		case GL_TESS_CONTROL_SHADER:	 return GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS;
94		case GL_TESS_EVALUATION_SHADER:	 return GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS;
95		case GL_GEOMETRY_SHADER:		 return GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS;
96		case GL_COMPUTE_SHADER:			 return GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS;
97		default:
98			 DE_FATAL("Unknown shader type");
99			 return -1;
100	}
101}
102
103int getMaxSSBlockSize (NegativeTestContext& ctx, glw::GLenum glShaderType)
104{
105	int maxSSBlocks = 0;
106	ctx.glGetIntegerv(getMaxSSBlockSizeEnum(glShaderType), &maxSSBlocks);
107
108	return maxSSBlocks;
109}
110
111std::string genBlockSource (NegativeTestContext& ctx, deInt64 numSSBlocks, glw::GLenum shaderType)
112{
113	const bool				isES32		= contextSupports(ctx.getRenderContext().getType(), glu::ApiType::es(3, 2));
114	const glu::GLSLVersion	version		= isES32 ? glu::GLSL_VERSION_320_ES : glu::GLSL_VERSION_310_ES;
115	std::ostringstream		source;
116
117	source	<< glu::getGLSLVersionDeclaration(version) << "\n"
118			<< ((isES32) ? "" : getShaderExtensionDeclaration(shaderType));
119
120	switch (shaderType)
121	{
122		case GL_VERTEX_SHADER:
123		case GL_FRAGMENT_SHADER:
124			break;
125
126		case GL_COMPUTE_SHADER:
127			source << "layout (local_size_x = 1) in;\n";
128			break;
129
130		case GL_GEOMETRY_SHADER:
131			source << "layout(points) in;\n"
132				   << "layout(line_strip, max_vertices = 3) out;\n";
133			break;
134
135		case GL_TESS_CONTROL_SHADER:
136			source << "layout(vertices = 10) out;\n";
137			break;
138
139		case GL_TESS_EVALUATION_SHADER:
140			source << "layout(triangles) in;\n";
141			break;
142
143		default:
144			DE_FATAL("Unknown shader type");
145			break;
146	}
147
148	source  << "\n"
149			<< "layout(std430, binding = 0) buffer Block {\n"
150			<< "    int value;\n"
151			<< "} sb_in[" << numSSBlocks << "];\n"
152			<< "void main(void) { sb_in[0].value = 1; }\n";
153
154	return source.str();
155}
156
157std::string genCommonSource (NegativeTestContext& ctx, glw::GLenum shaderType)
158{
159	const bool				isES32		= contextSupports(ctx.getRenderContext().getType(), glu::ApiType::es(3, 2));
160	const glu::GLSLVersion	version		= isES32 ? glu::GLSL_VERSION_320_ES : glu::GLSL_VERSION_310_ES;
161	std::ostringstream		source;
162
163	source << glu::getGLSLVersionDeclaration(version) << "\n"
164		   << ((isES32) ? "" : getShaderExtensionDeclaration(shaderType));
165
166	switch (shaderType)
167	{
168		case GL_TESS_CONTROL_SHADER:
169			source	<< "layout(vertices = 3) out;\n"
170					<< "void main() {}\n";
171			break;
172
173		case GL_TESS_EVALUATION_SHADER:
174			source	<< "layout(triangles, equal_spacing, cw) in;\n"
175					<< "void main() {}\n";
176			break;
177
178		default:
179			source  << "void main() {}\n";
180			break;
181	}
182
183	return source.str();
184}
185
186int genMaxSSBlocksSource (NegativeTestContext& ctx, glw::GLenum glShaderType, glu::ProgramSources& sources)
187{
188	int		maxSSBlocks				= getMaxSSBlockSize(ctx, glShaderType);
189	const	std::string shaderSrc	= genBlockSource(ctx, (maxSSBlocks), glShaderType);
190
191	sources.sources[getGLUShaderType(glShaderType)].push_back(shaderSrc);
192
193	return maxSSBlocks;
194}
195
196void block_number_limits (NegativeTestContext& ctx)
197{
198	const glw::GLenum glShaderTypes[] =
199	{
200		GL_VERTEX_SHADER,
201		GL_FRAGMENT_SHADER,
202		GL_TESS_CONTROL_SHADER,
203		GL_TESS_EVALUATION_SHADER,
204		GL_GEOMETRY_SHADER,
205		GL_COMPUTE_SHADER,
206	};
207
208	const std::string	vertSource			= genCommonSource(ctx, GL_VERTEX_SHADER);
209	const std::string	fragSource			= genCommonSource(ctx, GL_FRAGMENT_SHADER);
210	const std::string	tessControlSource	= genCommonSource(ctx, GL_TESS_CONTROL_SHADER);
211	const std::string	tessEvalSource		= genCommonSource(ctx, GL_TESS_EVALUATION_SHADER);
212
213	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(glShaderTypes); ndx++)
214	{
215		ctx.beginSection("maxShaderStorageBlocks: Exceed limits");
216
217		if (!ctx.isShaderSupported(static_cast<glu::ShaderType>(getGLUShaderType(glShaderTypes[ndx]))))
218		{
219			ctx.endSection();
220			continue;
221		}
222
223		int					maxSSBlocks			= getMaxSSBlockSize(ctx, glShaderTypes[ndx]);
224		std::string			source				= genBlockSource(ctx, maxSSBlocks+1, glShaderTypes[ndx]);
225
226		glu::ProgramSources sources;
227
228		if (maxSSBlocks == 0)
229		{
230			ctx.endSection();
231			continue;
232		}
233
234		switch (glShaderTypes[ndx])
235		{
236			case GL_VERTEX_SHADER:
237				sources << glu::VertexSource(source)
238						<< glu::FragmentSource(fragSource);
239				break;
240
241			case GL_FRAGMENT_SHADER:
242				sources << glu::VertexSource(vertSource)
243						<< glu::FragmentSource(source);
244				break;
245
246			case GL_TESS_CONTROL_SHADER:
247				sources << glu::VertexSource(vertSource)
248						<< glu::FragmentSource(fragSource)
249						<< glu::TessellationControlSource(source)
250						<< glu::TessellationEvaluationSource(tessEvalSource);
251				break;
252
253			case GL_TESS_EVALUATION_SHADER:
254				sources << glu::VertexSource(vertSource)
255						<< glu::FragmentSource(fragSource)
256						<< glu::TessellationControlSource(tessControlSource)
257						<< glu::TessellationEvaluationSource(source);
258				break;
259
260			case GL_GEOMETRY_SHADER:
261				sources << glu::VertexSource(vertSource)
262						<< glu::FragmentSource(fragSource)
263						<< glu::GeometrySource(source);
264				break;
265
266			case GL_COMPUTE_SHADER:
267				sources << glu::ComputeSource(source);
268				break;
269
270			default:
271				DE_FATAL("Unknown shader type");
272				break;
273		}
274
275		verifyProgram(ctx, sources);
276		ctx.endSection();
277	}
278}
279
280void max_combined_block_number_limit (NegativeTestContext& ctx)
281{
282	ctx.beginSection("maxCombinedShaderStorageBlocks: Exceed limits");
283
284	glu::ProgramSources sources;
285
286	int combinedSSBlocks	= 0;
287	int maxCombinedSSBlocks = 0;
288
289	combinedSSBlocks += genMaxSSBlocksSource(ctx, GL_VERTEX_SHADER, sources);
290	combinedSSBlocks += genMaxSSBlocksSource(ctx, GL_FRAGMENT_SHADER, sources);
291
292	if ((ctx.isShaderSupported(glu::SHADERTYPE_TESSELLATION_CONTROL)) && (ctx.isShaderSupported(glu::SHADERTYPE_TESSELLATION_EVALUATION)))
293	{
294		combinedSSBlocks += genMaxSSBlocksSource(ctx, GL_TESS_CONTROL_SHADER, sources);
295		combinedSSBlocks += genMaxSSBlocksSource(ctx, GL_TESS_EVALUATION_SHADER, sources);
296	}
297
298	if (ctx.isShaderSupported(glu::SHADERTYPE_GEOMETRY))
299		combinedSSBlocks += genMaxSSBlocksSource(ctx, GL_GEOMETRY_SHADER, sources);
300
301	ctx.glGetIntegerv(GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS, &maxCombinedSSBlocks);
302
303	ctx.getLog() << tcu::TestLog::Message << "GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS: " << maxCombinedSSBlocks << tcu::TestLog::EndMessage;
304	ctx.getLog() << tcu::TestLog::Message << "Combined shader storage blocks: " << combinedSSBlocks << tcu::TestLog::EndMessage;
305
306	if (combinedSSBlocks > maxCombinedSSBlocks)
307		verifyProgram(ctx, sources);
308	else
309		ctx.getLog() << tcu::TestLog::Message << "Test skipped: Combined shader storage blocks < GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS: " << tcu::TestLog::EndMessage;
310
311	ctx.endSection();
312}
313
314} // anonymous
315
316std::vector<FunctionContainer> getNegativeShaderStorageTestFunctions ()
317{
318	const FunctionContainer funcs[] =
319	{
320		{ block_number_limits,				"block_number_limits",				"Invalid shader linkage" },
321		{ max_combined_block_number_limit,	"max_combined_block_number_limit",	"Invalid shader linkage" },
322	};
323
324	return std::vector<FunctionContainer>(DE_ARRAY_BEGIN(funcs), DE_ARRAY_END(funcs));
325}
326
327} // NegativeTestShared
328} // Functional
329} // gles31
330} // deqp
331