1/*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.1 Module
3 * -------------------------------------------------
4 *
5 * Copyright 2015 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 Atomic Counter Tests
22 *//*--------------------------------------------------------------------*/
23
24#include "es31fNegativeAtomicCounterTests.hpp"
25
26#include "deUniquePtr.hpp"
27
28#include "glwEnums.hpp"
29#include "gluShaderProgram.hpp"
30
31#include "tcuTestLog.hpp"
32
33namespace deqp
34{
35namespace gles31
36{
37namespace Functional
38{
39namespace NegativeTestShared
40{
41namespace
42{
43
44enum TestCase
45{
46	TESTCASE_LAYOUT_LARGE_BINDING = 0,
47	TESTCASE_LAYOUT_MEDIUMP_PRECISION,
48	TESTCASE_LAYOUT_LOWP_PRECISION,
49	TESTCASE_LAYOUT_BINDING_OFFSET_OVERLAP,
50	TESTCASE_LAYOUT_BINDING_OMITTED,
51	TESTCASE_STRUCT,
52	TESTCASE_BODY_WRITE,
53	TESTCASE_BODY_DECLARE,
54
55	TESTCASE_LAST
56};
57
58static const glu::ShaderType s_shaders[] =
59{
60	glu::SHADERTYPE_VERTEX,
61	glu::SHADERTYPE_FRAGMENT,
62	glu::SHADERTYPE_GEOMETRY,
63	glu::SHADERTYPE_TESSELLATION_CONTROL,
64	glu::SHADERTYPE_TESSELLATION_EVALUATION,
65	glu::SHADERTYPE_COMPUTE
66};
67
68std::string genShaderSource (NegativeTestContext& ctx, TestCase test, glu::ShaderType type)
69{
70	DE_ASSERT(test < TESTCASE_LAST && type < glu::SHADERTYPE_LAST);
71
72	glw::GLint maxBuffers = -1;
73	std::ostringstream shader;
74
75	ctx.glGetIntegerv(GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS, &maxBuffers);
76
77	shader << getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n";
78
79	switch (type)
80	{
81		case glu::SHADERTYPE_GEOMETRY:
82			shader << "#extension GL_EXT_geometry_shader : enable\n";
83			shader << "layout(max_vertices = 3) out;\n";
84			break;
85
86		case glu::SHADERTYPE_TESSELLATION_CONTROL:
87		case glu::SHADERTYPE_TESSELLATION_EVALUATION:
88			shader << "#extension GL_EXT_tessellation_shader : enable\n";
89			break;
90
91		default:
92			break;
93	}
94
95	switch (test)
96	{
97		case TESTCASE_LAYOUT_LARGE_BINDING:
98			shader << "layout (binding = " << maxBuffers << ", offset = 0) uniform atomic_uint counter0;\n";
99			break;
100
101		case TESTCASE_LAYOUT_MEDIUMP_PRECISION:
102			shader << "layout (binding = 1, offset = 0) " << glu::getPrecisionName(glu::PRECISION_MEDIUMP) << " uniform atomic_uint counter0;\n";
103			break;
104
105		case TESTCASE_LAYOUT_LOWP_PRECISION:
106			shader << "layout (binding = 1, offset = 0) " << glu::getPrecisionName(glu::PRECISION_LOWP) << " uniform atomic_uint counter0;\n";
107			break;
108
109		case TESTCASE_LAYOUT_BINDING_OFFSET_OVERLAP:
110			shader << "layout (binding = 1, offset = 0) uniform atomic_uint counter0;\n"
111				   << "layout (binding = 1, offset = 2) uniform atomic_uint counter1;\n";
112			break;
113
114		case TESTCASE_LAYOUT_BINDING_OMITTED:
115			shader << "layout (offset = 0) uniform atomic_uint counter0;\n";
116			break;
117
118		case TESTCASE_STRUCT:
119			shader << "struct\n"
120				   << "{\n"
121				   << "  int a;\n"
122				   << "  atomic_uint counter;\n"
123				   << "} S;\n";
124			break;
125
126		case TESTCASE_BODY_WRITE:
127			shader << "layout (binding = 1) uniform atomic_uint counter;\n";
128			break;
129
130		default:
131			break;
132	}
133
134	shader << "void main (void)\n"
135				 << "{\n";
136
137	switch (test)
138	{
139		case TESTCASE_BODY_WRITE:
140			shader << "counter = 1;\n";
141			break;
142
143		case TESTCASE_BODY_DECLARE:
144			shader << "atomic_uint counter;\n";
145			break;
146
147		default:
148			break;
149	}
150
151	shader << "}\n";
152
153	return shader.str();
154}
155
156void iterateShaders (NegativeTestContext& ctx, TestCase testCase)
157{
158	tcu::TestLog& log = ctx.getLog();
159	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_shaders); ndx++)
160	{
161		if (ctx.isShaderSupported(s_shaders[ndx]))
162		{
163			ctx.beginSection(std::string("Verify shader: ") + glu::getShaderTypeName(s_shaders[ndx]));
164			const glu::ShaderProgram program(ctx.getRenderContext(), glu::ProgramSources() << glu::ShaderSource(s_shaders[ndx], genShaderSource(ctx, testCase, s_shaders[ndx])));
165			if (program.getShaderInfo(s_shaders[ndx]).compileOk)
166			{
167				log << program;
168				log << tcu::TestLog::Message << "Expected program to fail, but compilation passed." << tcu::TestLog::EndMessage;
169				ctx.fail("Shader was not expected to compile.");
170			}
171			ctx.endSection();
172		}
173	}
174}
175
176void atomic_max_counter_bindings (NegativeTestContext& ctx)
177{
178	ctx.beginSection("It is a compile-time error to bind an atomic counter with a binding value greater than or equal to gl_MaxAtomicCounterBindings.");
179	iterateShaders(ctx, TESTCASE_LAYOUT_LARGE_BINDING);
180	ctx.endSection();
181}
182
183void atomic_precision (NegativeTestContext& ctx)
184{
185	ctx.beginSection("It is an error to declare an atomic type with a lowp or mediump precision.");
186	iterateShaders(ctx, TESTCASE_LAYOUT_MEDIUMP_PRECISION);
187	iterateShaders(ctx, TESTCASE_LAYOUT_LOWP_PRECISION);
188	ctx.endSection();
189}
190
191void atomic_binding_offset_overlap (NegativeTestContext& ctx)
192{
193	ctx.beginSection("Atomic counters may not have overlapping offsets in the same binding.");
194	iterateShaders(ctx, TESTCASE_LAYOUT_BINDING_OFFSET_OVERLAP);
195	ctx.endSection();
196}
197
198void atomic_binding_omitted (NegativeTestContext& ctx)
199{
200	ctx.beginSection("Atomic counters must specify a binding point");
201	iterateShaders(ctx, TESTCASE_LAYOUT_BINDING_OMITTED);
202	ctx.endSection();
203}
204
205void atomic_struct (NegativeTestContext& ctx)
206{
207	ctx.beginSection("Structures may not have an atomic_uint variable.");
208	iterateShaders(ctx, TESTCASE_STRUCT);
209	ctx.endSection();
210}
211
212void atomic_body_write (NegativeTestContext& ctx)
213{
214	ctx.beginSection("An atomic_uint variable cannot be directly written to.");
215	iterateShaders(ctx, TESTCASE_BODY_WRITE);
216	ctx.endSection();
217}
218
219void atomic_body_declare (NegativeTestContext& ctx)
220{
221	ctx.beginSection("An atomic_uint variable cannot be declared in local scope");
222	iterateShaders(ctx, TESTCASE_BODY_DECLARE);
223	ctx.endSection();
224}
225
226} // anonymous
227
228std::vector<FunctionContainer> getNegativeAtomicCounterTestFunctions ()
229{
230	const FunctionContainer funcs[] =
231	{
232		{atomic_max_counter_bindings,		"atomic_max_counter_bindings",		"Invalid atomic counter buffer binding."	},
233		{atomic_precision,					"atomic_precision",					"Invalid precision qualifier."				},
234		{atomic_binding_offset_overlap,		"atomic_binding_offset_overlap",	"Invalid offset."							},
235		{atomic_binding_omitted,			"atomic_binding_omitted",			"Binding not specified."					},
236		{atomic_struct,						"atomic_struct",					"Invalid atomic_uint usage in struct."		},
237		{atomic_body_write,					"atomic_body_write",				"Invalid write access to atomic_uint."		},
238		{atomic_body_declare,				"atomic_body_declare",				"Invalid precision qualifier."				},
239	};
240
241	return std::vector<FunctionContainer>(DE_ARRAY_BEGIN(funcs), DE_ARRAY_END(funcs));
242}
243
244} // NegativeTestShared
245} // Functional
246} // gles31
247} // deqp
248