1/*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.1 Module
3 * -------------------------------------------------
4 *
5 * Copyright 2017 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 Compute tests.
22 *//*--------------------------------------------------------------------*/
23
24#include "es31fNegativeComputeTests.hpp"
25#include "gluContextInfo.hpp"
26#include "gluShaderProgram.hpp"
27#include "glwDefs.hpp"
28#include "glwEnums.hpp"
29#include "tcuStringTemplate.hpp"
30
31namespace deqp
32{
33
34using std::string;
35using std::map;
36
37namespace gles31
38{
39namespace Functional
40{
41namespace NegativeTestShared
42{
43namespace
44{
45
46using tcu::TestLog;
47using namespace glw;
48
49static const char* const vertexShaderSource			=	"${GLSL_VERSION_STRING}\n"
50														"\n"
51														"void main (void)\n"
52														"{\n"
53														"	gl_Position = vec4(0.0);\n"
54														"}\n";
55
56static const char* const fragmentShaderSource		=	"${GLSL_VERSION_STRING}\n"
57														"precision mediump float;\n"
58														"layout(location = 0) out mediump vec4 fragColor;\n"
59														"\n"
60														"void main (void)\n"
61														"{\n"
62														"	fragColor = vec4(1.0);\n"
63														"}\n";
64
65static const char* const computeShaderSource		=	"${GLSL_VERSION_STRING}\n"
66														"layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
67														"void main (void)\n"
68														"{\n"
69														"}\n";
70
71static const char* const invalidComputeShaderSource	=	"${GLSL_VERSION_STRING}\n"
72														"layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
73														"void main (void)\n"
74														"{\n"
75														"	highp uint var = -1;\n" // error
76														"}\n";
77
78int getResourceLimit (NegativeTestContext& ctx, GLenum resource)
79{
80	int limit = 0;
81	ctx.glGetIntegerv(resource, &limit);
82
83	return limit;
84}
85
86void verifyLinkError (NegativeTestContext& ctx, const glu::ShaderProgram& program)
87{
88	bool testFailed = false;
89
90	tcu::TestLog& log = ctx.getLog();
91	log << program;
92
93	testFailed = program.getProgramInfo().linkOk;
94
95	if (testFailed)
96	{
97		const char* const message("Program was not expected to link.");
98		log << tcu::TestLog::Message << message << tcu::TestLog::EndMessage;
99		ctx.fail(message);
100	}
101}
102
103void verifyCompileError (NegativeTestContext& ctx, const glu::ShaderProgram& program, glu::ShaderType shaderType)
104{
105	bool testFailed = false;
106
107	tcu::TestLog& log = ctx.getLog();
108	log << program;
109
110	testFailed = program.getShaderInfo(shaderType).compileOk;
111
112	if (testFailed)
113	{
114		const char* const message("Program was not expected to compile.");
115		log << tcu::TestLog::Message << message << tcu::TestLog::EndMessage;
116		ctx.fail(message);
117	}
118}
119
120string generateComputeShader (NegativeTestContext& ctx, const string& shaderDeclarations, const string& shaderBody)
121{
122	const bool			isES32			= glu::contextSupports(ctx.getRenderContext().getType(), glu::ApiType::es(3, 2));
123	const char* const	shaderVersion	= isES32
124										? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES)
125										: getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
126
127	std::ostringstream compShaderSource;
128
129	compShaderSource	<<	shaderVersion << "\n"
130						<<	"layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
131						<<	shaderDeclarations << "\n"
132						<<	"void main (void)\n"
133						<<	"{\n"
134						<<	shaderBody
135						<<	"}\n";
136
137	return compShaderSource.str();
138}
139
140string genBuiltInSource (glu::ShaderType shaderType)
141{
142	std::ostringstream		source;
143	source << "${GLSL_VERSION_STRING}\n";
144
145	switch (shaderType)
146	{
147		case glu::SHADERTYPE_VERTEX:
148		case glu::SHADERTYPE_FRAGMENT:
149			break;
150
151		case glu::SHADERTYPE_COMPUTE:
152			source << "layout (local_size_x = 1) in;\n";
153			break;
154
155		case glu::SHADERTYPE_GEOMETRY:
156			source << "layout(points) in;\n"
157				   << "layout(line_strip, max_vertices = 3) out;\n";
158			break;
159
160		case glu::SHADERTYPE_TESSELLATION_CONTROL:
161			source << "${GLSL_TESS_EXTENSION_STRING}\n"
162				   << "layout(vertices = 10) out;\n";
163			break;
164
165		case glu::SHADERTYPE_TESSELLATION_EVALUATION:
166			source << "${GLSL_TESS_EXTENSION_STRING}\n"
167				   << "layout(triangles) in;\n";
168			break;
169
170		default:
171			DE_FATAL("Unknown shader type");
172			break;
173	}
174
175	source	<< "\n"
176			<< "void main(void)\n"
177			<< "{\n"
178			<< "${COMPUTE_BUILT_IN_CONSTANTS_STRING}"
179			<< "}\n";
180
181	return source.str();
182}
183
184void exceed_uniform_block_limit (NegativeTestContext& ctx)
185{
186	std::ostringstream shaderDecl;
187	std::ostringstream shaderBody;
188
189	shaderDecl	<< "layout(std140, binding = 0) uniform Block\n"
190				<< "{\n"
191				<< "    highp vec4 val;\n"
192				<< "} block[" << getResourceLimit(ctx, GL_MAX_COMPUTE_UNIFORM_BLOCKS) + 1 << "];\n";
193
194	glu::ShaderProgram	program(ctx.getRenderContext(), glu::ProgramSources()
195			<< glu::ComputeSource(generateComputeShader(ctx, shaderDecl.str(), shaderBody.str())));
196
197	ctx.beginSection("Link error is generated if a compute shader exceeds GL_MAX_COMPUTE_UNIFORM_BLOCKS.");
198	verifyLinkError(ctx, program);
199	ctx.endSection();
200}
201
202void exceed_shader_storage_block_limit (NegativeTestContext& ctx)
203{
204	std::ostringstream shaderDecl;
205	std::ostringstream shaderBody;
206
207	shaderDecl	<< "layout(std140, binding = 0) buffer Block\n"
208				<< "{\n"
209				<< "    highp vec4 val;\n"
210				<< "} block[" << getResourceLimit(ctx, GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS) + 1 << "];\n";
211
212	glu::ShaderProgram	program(ctx.getRenderContext(), glu::ProgramSources()
213			<< glu::ComputeSource(generateComputeShader(ctx, shaderDecl.str(), shaderBody.str())));
214
215	ctx.beginSection("Link error is generated if compute shader exceeds GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS.");
216	verifyLinkError(ctx, program);
217	ctx.endSection();
218}
219
220void exceed_texture_image_units_limit (NegativeTestContext& ctx)
221{
222	const int			limit			= getResourceLimit(ctx, GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS) + 1;
223	std::ostringstream	shaderDecl;
224	std::ostringstream	shaderBody;
225
226	shaderDecl	<< "layout(binding = 0) "
227				<< "uniform highp sampler2D u_sampler[" << limit + 1 << "];\n"
228				<< "\n"
229				<< "layout(binding = 0) buffer Output {\n"
230				<< "    vec4 values[ " << limit + 1 << " ];\n"
231				<< "} sb_out;\n";
232
233	for (int i = 0; i < limit + 1; ++i)
234		shaderBody	<< "   sb_out.values[" << i << "] = texture(u_sampler[" << i << "], vec2(1.0f));\n";
235
236	glu::ShaderProgram	program(ctx.getRenderContext(), glu::ProgramSources()
237			<< glu::ComputeSource(generateComputeShader(ctx, shaderDecl.str(), shaderBody.str())));
238
239	tcu::TestLog& log = ctx.getLog();
240	log << tcu::TestLog::Message << "Possible link error is generated if compute shader exceeds GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS." << tcu::TestLog::EndMessage;
241	log << program;
242
243	if (program.getProgramInfo().linkOk)
244	{
245		log << tcu::TestLog::Message << "Quality Warning: program was not expected to link." << tcu::TestLog::EndMessage;
246		ctx.glUseProgram(program.getProgram());
247		ctx.expectError(GL_NO_ERROR);
248
249		ctx.beginSection("GL_INVALID_OPERATION error is generated if the sum of the number of active samplers for each active program exceeds the maximum number of texture image units allowed");
250		ctx.glDispatchCompute(1, 1, 1);
251		ctx.expectError(GL_INVALID_OPERATION);
252		ctx.endSection();
253	}
254}
255
256void exceed_image_uniforms_limit (NegativeTestContext& ctx)
257{
258	const int			limit = getResourceLimit(ctx, GL_MAX_COMPUTE_IMAGE_UNIFORMS);
259	std::ostringstream	shaderDecl;
260	std::ostringstream	shaderBody;
261
262	shaderDecl	<< "layout(rgba8, binding = 0) "
263				<< "uniform readonly highp image2D u_image[" << limit + 1 << "];\n"
264				<< "\n"
265				<< "layout(binding = 0) buffer Output {\n"
266				<< "    float values[" << limit + 1 << "];\n"
267				<< "} sb_out;\n";
268
269	for (int i = 0; i < limit + 1; ++i)
270		shaderBody	<< "    sb_out.values[" << i << "]" << "  = imageLoad(u_image[" << i << "], ivec2(gl_GlobalInvocationID.xy)).x;\n";
271
272	glu::ShaderProgram	program(ctx.getRenderContext(), glu::ProgramSources()
273			<< glu::ComputeSource(generateComputeShader(ctx, shaderDecl.str(), shaderBody.str())));
274
275	ctx.beginSection("Link error is generated if compute shader exceeds GL_MAX_COMPUTE_IMAGE_UNIFORMS.");
276	verifyLinkError(ctx, program);
277	ctx.endSection();
278}
279
280void exceed_shared_memory_size_limit (NegativeTestContext& ctx)
281{
282	const int			limit				= getResourceLimit(ctx, GL_MAX_COMPUTE_SHARED_MEMORY_SIZE);
283	const long			numberOfElements	= limit / sizeof(GLuint);
284	std::ostringstream	shaderDecl;
285	std::ostringstream	shaderBody;
286
287	shaderDecl	<< "shared uint values[" << numberOfElements + 1 << "];\n"
288				<< "\n"
289				<< "layout(binding = 0) buffer Output {\n"
290				<< "    uint values;\n"
291				<< "} sb_out;\n";
292
293	shaderBody	<< "    sb_out.values = values[" << numberOfElements << "];\n";
294
295	glu::ShaderProgram	program(ctx.getRenderContext(), glu::ProgramSources()
296			<< glu::ComputeSource(generateComputeShader(ctx, shaderDecl.str(), shaderBody.str())));
297
298	ctx.beginSection("Link error is generated if compute shader exceeds GL_MAX_COMPUTE_SHARED_MEMORY_SIZE.");
299	verifyLinkError(ctx, program);
300	ctx.endSection();
301}
302
303void exceed_uniform_components_limit (NegativeTestContext& ctx)
304{
305	const int			limit = getResourceLimit(ctx, GL_MAX_COMPUTE_UNIFORM_COMPONENTS);
306	std::ostringstream	shaderDecl;
307	std::ostringstream	shaderBody;
308
309	shaderDecl	<< "uniform highp uint u_value[" << limit + 1 << "];\n"
310				<< "\n"
311				<< "layout(binding = 0) buffer Output {\n"
312				<< "    uint values[2];\n"
313				<< "} sb_out;\n";
314
315	shaderBody << "    sb_out.values[0] = u_value[" << limit << "];\n";
316	shaderBody << "    sb_out.values[1] = u_value[0];\n";
317
318	glu::ShaderProgram	program(ctx.getRenderContext(), glu::ProgramSources()
319			<< glu::ComputeSource(generateComputeShader(ctx, shaderDecl.str(), shaderBody.str())));
320
321	ctx.beginSection("Link error is generated if compute shader exceeds GL_MAX_COMPUTE_UNIFORM_COMPONENTS.");
322	verifyLinkError(ctx, program);
323	ctx.endSection();
324}
325
326void exceed_atomic_counter_buffer_limit (NegativeTestContext& ctx)
327{
328	const int			limit = getResourceLimit(ctx, GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS);
329	std::ostringstream	shaderDecl;
330	std::ostringstream	shaderBody;
331
332	for (int i = 0; i < limit + 1; ++i)
333	{
334		shaderDecl	<< "layout(binding = " << i << ") "
335					<< "uniform atomic_uint u_atomic" << i << ";\n";
336
337		if (i == 0)
338			shaderBody	<< "    uint oldVal = atomicCounterIncrement(u_atomic" << i << ");\n";
339		else
340			shaderBody	<< "    oldVal = atomicCounterIncrement(u_atomic" << i << ");\n";
341	}
342
343	shaderBody	<< "    sb_out.value = oldVal;\n";
344
345	shaderDecl	<< "\n"
346				<< "layout(binding = 0) buffer Output {\n"
347				<< "    uint value;\n"
348				<< "} sb_out;\n";
349
350	glu::ShaderProgram	program(ctx.getRenderContext(), glu::ProgramSources()
351			<< glu::ComputeSource(generateComputeShader(ctx, shaderDecl.str(), shaderBody.str())));
352
353	ctx.beginSection("Link error is generated if compute shader exceeds GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS.");
354	verifyLinkError(ctx, program);
355	ctx.endSection();
356}
357
358void exceed_atomic_counters_limit (NegativeTestContext& ctx)
359{
360	std::ostringstream	shaderDecl;
361	std::ostringstream	shaderBody;
362
363	shaderDecl	<< "layout(binding = 0, offset = 0) uniform atomic_uint u_atomic0;\n"
364				<< "layout(binding = " << sizeof(GLuint) * getResourceLimit(ctx, GL_MAX_COMPUTE_ATOMIC_COUNTERS) << ", offset = 0) uniform atomic_uint u_atomic1;\n"
365				<< "\n"
366				<< "layout(binding = 0) buffer Output {\n"
367				<< "    uint value;\n"
368				<< "} sb_out;\n";
369
370	shaderBody	<< "    uint oldVal = 0u;\n"
371				<< "    oldVal = atomicCounterIncrement(u_atomic0);\n"
372				<< "    oldVal = atomicCounterIncrement(u_atomic1);\n"
373				<< "    sb_out.value = oldVal;\n";
374
375	glu::ShaderProgram	program(ctx.getRenderContext(), glu::ProgramSources()
376			<< glu::ComputeSource(generateComputeShader(ctx, shaderDecl.str(), shaderBody.str())));
377
378	ctx.beginSection("Link error is generated if compute shader exceeds GL_MAX_COMPUTE_ATOMIC_COUNTERS.");
379	verifyLinkError(ctx, program);
380	ctx.endSection();
381}
382
383void program_not_active (NegativeTestContext& ctx)
384{
385	const bool					isES32	= glu::contextSupports(ctx.getRenderContext().getType(), glu::ApiType::es(3, 2));
386	map<string, string>			args;
387	args["GLSL_VERSION_STRING"]			= isES32 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
388
389	const glu::VertexSource		vertSource(tcu::StringTemplate(vertexShaderSource).specialize(args));
390	const glu::FragmentSource	fragSource(tcu::StringTemplate(fragmentShaderSource).specialize(args));
391
392	glu::ProgramPipeline		pipeline(ctx.getRenderContext());
393
394	glu::ShaderProgram			vertProgram	(ctx.getRenderContext(), glu::ProgramSources() << glu::ProgramSeparable(true) << vertSource);
395	glu::ShaderProgram			fragProgram	(ctx.getRenderContext(), glu::ProgramSources() << glu::ProgramSeparable(true) << fragSource);
396
397	tcu::TestLog& log			= ctx.getLog();
398	log << vertProgram << fragProgram;
399
400	if (!vertProgram.isOk() || !fragProgram.isOk())
401		TCU_THROW(InternalError, "failed to build program");
402
403	ctx.glBindProgramPipeline(pipeline.getPipeline());
404	ctx.expectError(GL_NO_ERROR);
405
406	ctx.beginSection("Program not set at all");
407	{
408		ctx.beginSection("GL_INVALID_OPERATION is generated by glDispatchCompute if there is no active program for the compute shader stage.");
409		ctx.glDispatchCompute(1, 1, 1);
410		ctx.expectError(GL_INVALID_OPERATION);
411		ctx.endSection();
412
413		ctx.beginSection("GL_INVALID_OPERATION is generated by glDispatchComputeIndirect if there is no active program for the compute shader stage.");
414		GLintptr indirect = 0;
415		ctx.glDispatchComputeIndirect(indirect);
416		ctx.expectError(GL_INVALID_OPERATION);
417		ctx.endSection();
418	}
419	ctx.endSection();
420
421	ctx.beginSection("Program contains graphic pipeline stages");
422	{
423		ctx.glUseProgramStages(pipeline.getPipeline(), GL_VERTEX_SHADER_BIT, vertProgram.getProgram());
424		ctx.glUseProgramStages(pipeline.getPipeline(), GL_FRAGMENT_SHADER_BIT, fragProgram.getProgram());
425		ctx.expectError(GL_NO_ERROR);
426
427		ctx.beginSection("GL_INVALID_OPERATION is generated by glDispatchCompute if there is no active program for the compute shader stage.");
428		ctx.glDispatchCompute(1, 1, 1);
429		ctx.expectError(GL_INVALID_OPERATION);
430		ctx.endSection();
431
432		ctx.beginSection("GL_INVALID_OPERATION is generated by glDispatchComputeIndirect if there is no active program for the compute shader stage.");
433		GLintptr indirect = 0;
434		ctx.glDispatchComputeIndirect(indirect);
435		ctx.expectError(GL_INVALID_OPERATION);
436		ctx.endSection();
437	}
438	ctx.endSection();
439
440	ctx.glBindProgramPipeline(0);
441	ctx.expectError(GL_NO_ERROR);
442}
443
444void invalid_program_query (NegativeTestContext& ctx)
445{
446	const bool					isES32	= glu::contextSupports(ctx.getRenderContext().getType(), glu::ApiType::es(3, 2));
447	map<string, string>			args;
448	args["GLSL_VERSION_STRING"]			= isES32 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
449
450	GLint data[3] = { 0, 0, 0 };
451
452	ctx.beginSection("Compute shader that does not link");
453	{
454		const glu::ComputeSource	compSource(tcu::StringTemplate(invalidComputeShaderSource).specialize(args));
455		glu::ShaderProgram			invalidComputeProgram (ctx.getRenderContext(), glu::ProgramSources() << compSource);
456
457		tcu::TestLog& log = ctx.getLog();
458		log << invalidComputeProgram;
459
460		if (invalidComputeProgram.isOk())
461			TCU_THROW(InternalError, "program should not of built");
462
463		ctx.beginSection("GL_INVALID_OPERATION is generated if GL_COMPUTE_WORK_GROUP_SIZE is queried for a program which has not been linked properly.");
464		ctx.glGetProgramiv(invalidComputeProgram.getProgram(), GL_COMPUTE_WORK_GROUP_SIZE, &data[0]);
465		ctx.expectError(GL_INVALID_OPERATION);
466		ctx.endSection();
467
468		ctx.glUseProgram(0);
469	}
470	ctx.endSection();
471
472	ctx.beginSection("Compute shader not present");
473	{
474		const glu::VertexSource		vertSource(tcu::StringTemplate(vertexShaderSource).specialize(args));
475		const glu::FragmentSource	fragSource(tcu::StringTemplate(fragmentShaderSource).specialize(args));
476		glu::ShaderProgram			graphicsPipelineProgram	(ctx.getRenderContext(), glu::ProgramSources() << vertSource << fragSource);
477
478		tcu::TestLog& log = ctx.getLog();
479		log << graphicsPipelineProgram;
480
481		if (!graphicsPipelineProgram.isOk())
482			TCU_THROW(InternalError, "failed to build program");
483
484		ctx.beginSection("GL_INVALID_OPERATION is generated if GL_COMPUTE_WORK_GROUP_SIZE is queried for a program which has not been linked properly.");
485		ctx.glGetProgramiv(graphicsPipelineProgram.getProgram(), GL_COMPUTE_WORK_GROUP_SIZE, &data[0]);
486		ctx.expectError(GL_INVALID_OPERATION);
487		ctx.endSection();
488
489		ctx.glUseProgram(0);
490	}
491	ctx.endSection();
492}
493
494void invalid_dispatch_compute_indirect (NegativeTestContext& ctx)
495{
496	const bool					isES32	= glu::contextSupports(ctx.getRenderContext().getType(), glu::ApiType::es(3, 2));
497	map<string, string>			args;
498	args["GLSL_VERSION_STRING"]			= isES32 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
499
500	const glu::ComputeSource	compSource(tcu::StringTemplate(computeShaderSource).specialize(args));
501	glu::ShaderProgram			program(ctx.getRenderContext(), glu::ProgramSources() << compSource);
502
503	tcu::TestLog& log = ctx.getLog();
504	log << program;
505
506	if (!program.isOk())
507		TCU_THROW(InternalError, "failed to build program");
508
509	ctx.glUseProgram(program.getProgram());
510	ctx.expectError(GL_NO_ERROR);
511
512	static const struct
513	{
514		GLuint numGroupsX;
515		GLuint numGroupsY;
516		GLuint numGroupsZ;
517	} data = {0, 0, 0};
518
519	{
520		GLuint buffer;
521		ctx.glGenBuffers(1, &buffer);
522		ctx.glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, 0);
523		ctx.expectError(GL_NO_ERROR);
524
525		ctx.beginSection("GL_INVALID_OPERATION is generated by glDispatchComputeIndirect if zero is bound to GL_DISPATCH_INDIRECT_BUFFER.");
526		GLintptr indirect = 0;
527		ctx.glDispatchComputeIndirect(indirect);
528		ctx.expectError(GL_INVALID_OPERATION);
529		ctx.endSection();
530
531		ctx.glDeleteBuffers(1, &buffer);
532	}
533
534	{
535		GLuint buffer;
536		ctx.glGenBuffers(1, &buffer);
537		ctx.expectError(GL_NO_ERROR);
538
539		ctx.glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, buffer);
540		ctx.expectError(GL_NO_ERROR);
541
542		ctx.glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(data), &data, GL_STATIC_DRAW);
543		ctx.expectError(GL_NO_ERROR);
544
545		ctx.beginSection("GL_INVALID_OPERATION is generated by glDispatchComputeIndirect if data is sourced beyond the end of the buffer object.");
546		GLintptr indirect = 1 << 10;
547		ctx.glDispatchComputeIndirect(indirect);
548		ctx.expectError(GL_INVALID_OPERATION);
549		ctx.endSection();
550
551		ctx.glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, 0);
552		ctx.glDeleteBuffers(1, &buffer);
553	}
554
555	{
556		ctx.beginSection("GL_INVALID_VALUE is generated by glDispatchComputeIndirect if the value of indirect is less than zero.");
557		GLintptr indirect = -1;
558		ctx.glDispatchComputeIndirect(indirect);
559		ctx.expectError(GL_INVALID_VALUE);
560		ctx.endSection();
561	}
562
563	{
564		GLuint buffer;
565		ctx.glGenBuffers(1, &buffer);
566		ctx.expectError(GL_NO_ERROR);
567
568		ctx.glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, buffer);
569		ctx.expectError(GL_NO_ERROR);
570
571		ctx.glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(data), &data, GL_STATIC_DRAW);
572		ctx.expectError(GL_NO_ERROR);
573
574		ctx.beginSection("GL_INVALID_VALUE is generated by glDispatchComputeIndirect if indirect is not a multiple of the size, in basic machine units, of uint.");
575		GLintptr indirect = sizeof(data) + 1;
576		ctx.glDispatchComputeIndirect(indirect);
577		ctx.expectError(GL_INVALID_VALUE);
578		ctx.endSection();
579
580		ctx.glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, 0);
581		ctx.glDeleteBuffers(1, &buffer);
582	}
583}
584
585void invalid_maximum_work_group_counts (NegativeTestContext& ctx)
586{
587	const bool					isES32	= glu::contextSupports(ctx.getRenderContext().getType(), glu::ApiType::es(3, 2));
588	map<string, string>			args;
589	args["GLSL_VERSION_STRING"]			= isES32 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
590
591	const glu::ComputeSource	compSource(tcu::StringTemplate(computeShaderSource).specialize(args));
592	glu::ShaderProgram			program(ctx.getRenderContext(), glu::ProgramSources() << compSource);
593
594	tcu::TestLog& log = ctx.getLog();
595	log << program;
596
597	if (!program.isOk())
598		TCU_THROW(InternalError, "failed to build program");
599
600	ctx.glUseProgram(program.getProgram());
601	ctx.expectError(GL_NO_ERROR);
602
603	GLint workGroupCountX;
604	ctx.glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, (GLuint)0, &workGroupCountX);
605	ctx.expectError(GL_NO_ERROR);
606
607	ctx.beginSection("GL_INVALID_VALUE is generated by glDispatchCompute if <numGroupsX> array is larger than the maximum work group count for the x dimension.");
608	ctx.glDispatchCompute(workGroupCountX+1, 1, 1);
609	ctx.expectError(GL_INVALID_VALUE);
610	ctx.endSection();
611
612	GLint workGroupCountY;
613	ctx.glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, (GLuint)1, &workGroupCountY);
614	ctx.expectError(GL_NO_ERROR);
615
616	ctx.beginSection("GL_INVALID_VALUE is generated by glDispatchCompute if <numGroupsY> array is larger than the maximum work group count for the y dimension.");
617	ctx.glDispatchCompute(1, workGroupCountY+1, 1);
618	ctx.expectError(GL_INVALID_VALUE);
619	ctx.endSection();
620
621	GLint workGroupCountZ;
622	ctx.glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, (GLuint)2, &workGroupCountZ);
623	ctx.expectError(GL_NO_ERROR);
624
625	ctx.beginSection("GL_INVALID_VALUE is generated by glDispatchCompute if <numGroupsZ> array is larger than the maximum work group count for the z dimension.");
626	ctx.glDispatchCompute(1, 1, workGroupCountZ+1);
627	ctx.expectError(GL_INVALID_VALUE);
628	ctx.endSection();
629}
630
631void invalid_maximum_work_group_sizes (NegativeTestContext& ctx)
632{
633	GLint maxWorkGroupSizeX;
634	ctx.glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, (GLuint)0, &maxWorkGroupSizeX);
635	ctx.expectError(GL_NO_ERROR);
636
637	GLint maxWorkGroupSizeY;
638	ctx.glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, (GLuint)1, &maxWorkGroupSizeY);
639	ctx.expectError(GL_NO_ERROR);
640
641	GLint maxWorkGroupSizeZ;
642	ctx.glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, (GLuint)2, &maxWorkGroupSizeZ);
643	ctx.expectError(GL_NO_ERROR);
644
645	GLint maxWorkGroupInvocations;
646	ctx.glGetIntegerv(GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS, &maxWorkGroupInvocations);
647	ctx.expectError(GL_NO_ERROR);
648
649	DE_ASSERT(((deInt64) maxWorkGroupSizeX * maxWorkGroupSizeY * maxWorkGroupSizeZ) > maxWorkGroupInvocations );
650
651	const bool				isES32			= glu::contextSupports(ctx.getRenderContext().getType(), glu::ApiType::es(3, 2));
652	const char* const		shaderVersion	= isES32
653											? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES)
654											: getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
655
656	static const struct
657	{
658		GLint x;
659		GLint y;
660		GLint z;
661	} localWorkGroupSizeCases[] =
662	{
663		{	maxWorkGroupSizeX+1,	1,						1						},
664		{	1,						maxWorkGroupSizeY+1,	1						},
665		{	1,						1,						maxWorkGroupSizeZ+1		},
666		{	maxWorkGroupSizeX,		maxWorkGroupSizeY,		maxWorkGroupSizeZ		},
667	};
668
669	for (int testCase = 0; testCase < DE_LENGTH_OF_ARRAY(localWorkGroupSizeCases); ++testCase)
670	{
671		std::ostringstream compShaderSource;
672
673		compShaderSource	<<	shaderVersion << "\n"
674							<<	"layout(local_size_x = " << localWorkGroupSizeCases[testCase].x << ", local_size_y = " << localWorkGroupSizeCases[testCase].y << ", local_size_z = " << localWorkGroupSizeCases[testCase].z << ") in;\n"
675							<<	"void main (void)\n"
676							<<	"{\n"
677							<<	"}\n";
678
679		const glu::ComputeSource	compSource(compShaderSource.str());
680		glu::ShaderProgram			program(ctx.getRenderContext(), glu::ProgramSources() << compSource);
681
682		if (testCase == DE_LENGTH_OF_ARRAY(localWorkGroupSizeCases)-1)
683		{
684			bool testFailed = false;
685			ctx.beginSection("A compile time or link error is generated if the maximum number of invocations in a single local work group (product of the three dimensions) is greater than GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS.");
686
687			ctx.getLog() << program;
688			testFailed = (program.getProgramInfo().linkOk) && (program.getShaderInfo(glu::SHADERTYPE_COMPUTE).compileOk);
689
690			if (testFailed)
691			{
692				const char* const message("Program was not expected to compile or link.");
693				ctx.getLog() << tcu::TestLog::Message << message << tcu::TestLog::EndMessage;
694				ctx.fail(message);
695			}
696		}
697		else
698		{
699			ctx.beginSection("A compile time error is generated if the fixed local group size of the shader in any dimension is greater than the maximum supported.");
700			verifyCompileError(ctx, program, glu::SHADERTYPE_COMPUTE);
701		}
702
703		ctx.endSection();
704	}
705}
706
707void invalid_layout_qualifiers (NegativeTestContext& ctx)
708{
709	const bool				isES32			= glu::contextSupports(ctx.getRenderContext().getType(), glu::ApiType::es(3, 2));
710	const char* const		shaderVersion	= isES32
711											? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES)
712											: getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
713
714	{
715		std::ostringstream compShaderSource;
716		compShaderSource	<<	shaderVersion << "\n"
717							<<	"void main (void)\n"
718							<<	"{\n"
719							<<	"}\n";
720
721		const glu::ComputeSource	compSource(compShaderSource.str());
722		glu::ShaderProgram			program(ctx.getRenderContext(), glu::ProgramSources() << compSource);
723
724		ctx.beginSection("A link error is generated if the compute shader program does not contain an input layout qualifier specifying a fixed local group size.");
725		verifyLinkError(ctx, program);
726		ctx.endSection();
727	}
728
729	{
730		std::ostringstream compShaderSource;
731		compShaderSource	<<	shaderVersion << "\n"
732							<<	"layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
733							<<	"layout(local_size_x = 2, local_size_y = 2, local_size_z = 2) in;\n"
734							<<	"void main (void)\n"
735							<<	"{\n"
736							<<	"}\n";
737
738		const glu::ComputeSource	compSource(compShaderSource.str());
739		glu::ShaderProgram			program(ctx.getRenderContext(), glu::ProgramSources() << compSource);
740
741		ctx.beginSection("A compile-time error is generated if a local work group size qualifier is declared more than once in the same shader.");
742		verifyCompileError(ctx, program, glu::SHADERTYPE_COMPUTE);
743		ctx.endSection();
744	}
745
746	{
747		std::ostringstream compShaderSource;
748		compShaderSource	<<	shaderVersion << "\n"
749							<<	"out mediump vec4 fragColor;\n"
750							<<	"\n"
751							<<	"layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
752							<<	"void main (void)\n"
753							<<	"{\n"
754							<<	"}\n";
755
756		const glu::ComputeSource	compSource(compShaderSource.str());
757		glu::ShaderProgram			program(ctx.getRenderContext(), glu::ProgramSources() << compSource);
758
759		ctx.beginSection("A compile-time error is generated if a user defined output variable is declared in a compute shader.");
760		verifyCompileError(ctx, program, glu::SHADERTYPE_COMPUTE);
761		ctx.endSection();
762	}
763
764	{
765		std::ostringstream compShaderSource;
766		compShaderSource	<<	shaderVersion << "\n"
767							<<	"uvec3 gl_NumWorkGroups;\n"
768							<<	"uvec3 gl_WorkGroupSize;\n"
769							<<	"uvec3 gl_WorkGroupID;\n"
770							<<	"uvec3 gl_LocalInvocationID;\n"
771							<<	"uvec3 gl_GlobalInvocationID;\n"
772							<<	"uvec3 gl_LocalInvocationIndex;\n"
773							<<	"\n"
774							<<	"layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
775							<<	"void main (void)\n"
776							<<	"{\n"
777							<<	"}\n";
778
779		const glu::ComputeSource	compSource(compShaderSource.str());
780		glu::ShaderProgram			program(ctx.getRenderContext(), glu::ProgramSources() << compSource);
781
782		ctx.beginSection("A compile time or link error is generated if compute shader built-in variables are redeclared.");
783		bool testFailed = false;
784
785		tcu::TestLog& log = ctx.getLog();
786		log << program;
787
788		testFailed = (program.getProgramInfo().linkOk) && (program.getShaderInfo(glu::SHADERTYPE_COMPUTE).compileOk);
789
790		if (testFailed)
791		{
792			const char* const message("Program was not expected to compile or link.");
793			log << tcu::TestLog::Message << message << tcu::TestLog::EndMessage;
794			ctx.fail(message);
795		}
796
797		ctx.endSection();
798	}
799}
800
801void invalid_write_built_in_constants (NegativeTestContext& ctx)
802{
803	if ((!ctx.isExtensionSupported("GL_EXT_tessellation_shader") && !ctx.isExtensionSupported("GL_OES_tessellation_shader")) ||
804	    (!ctx.isExtensionSupported("GL_EXT_geometry_shader") && !ctx.isExtensionSupported("GL_OES_geometry_shader")))
805	{
806		TCU_THROW(NotSupportedError, "tessellation and geometry shader extensions not supported");
807	}
808
809	const bool					isES32			= glu::contextSupports(ctx.getRenderContext().getType(), glu::ApiType::es(3, 2));
810	map<string, string>			args;
811
812	args["GLSL_VERSION_STRING"]					=	isES32 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
813	args["GLSL_TESS_EXTENSION_STRING"]			=	isES32 ? "" : "#extension GL_EXT_tessellation_shader : require";
814	args["COMPUTE_BUILT_IN_CONSTANTS_STRING"]	=	"	gl_MaxComputeWorkGroupCount       = ivec3(65535, 65535, 65535);\n"
815													"	gl_MaxComputeWorkGroupCount       = ivec3(1024, 1024, 64);\n"
816													"	gl_MaxComputeWorkGroupSize        = ivec3(512);\n"
817													"	gl_MaxComputeUniformComponents    = 512;\n"
818													"	gl_MaxComputeTextureImageUnits    = 16;\n"
819													"	gl_MaxComputeImageUniforms        = 8;\n"
820													"	gl_MaxComputeAtomicCounters       = 8;\n"
821													"	gl_MaxComputeAtomicCounterBuffers = 1;\n";
822
823	const glu::VertexSource					vertSource		(tcu::StringTemplate(genBuiltInSource(glu::SHADERTYPE_VERTEX)).specialize(args));
824	const glu::FragmentSource				fragSource		(tcu::StringTemplate(genBuiltInSource(glu::SHADERTYPE_FRAGMENT)).specialize(args));
825	const glu::TessellationControlSource	tessCtrlSource	(tcu::StringTemplate(genBuiltInSource(glu::SHADERTYPE_TESSELLATION_CONTROL)).specialize(args));
826	const glu::TessellationEvaluationSource	tessEvalSource	(tcu::StringTemplate(genBuiltInSource(glu::SHADERTYPE_TESSELLATION_EVALUATION)).specialize(args));
827	const glu::GeometrySource				geometrySource	(tcu::StringTemplate(genBuiltInSource(glu::SHADERTYPE_GEOMETRY)).specialize(args));
828	const glu::ComputeSource				computeSource	(tcu::StringTemplate(genBuiltInSource(glu::SHADERTYPE_COMPUTE)).specialize(args));
829
830	glu::ShaderProgram	vertProgram		(ctx.getRenderContext(), glu::ProgramSources() << glu::ProgramSeparable(true) << vertSource);
831	glu::ShaderProgram	fragProgram		(ctx.getRenderContext(), glu::ProgramSources() << glu::ProgramSeparable(true) << fragSource);
832	glu::ShaderProgram	tessCtrlProgram	(ctx.getRenderContext(), glu::ProgramSources() << glu::ProgramSeparable(true) << tessCtrlSource);
833	glu::ShaderProgram	tessEvalProgram	(ctx.getRenderContext(), glu::ProgramSources() << glu::ProgramSeparable(true) << tessEvalSource);
834	glu::ShaderProgram	geometryProgram	(ctx.getRenderContext(), glu::ProgramSources() << glu::ProgramSeparable(true) << geometrySource);
835	glu::ShaderProgram	computeProgram	(ctx.getRenderContext(), glu::ProgramSources() << glu::ProgramSeparable(true) << computeSource);
836
837	ctx.beginSection("A compile time is generated if compute built-in constants provided in all shaders are written to.");
838	verifyCompileError(ctx, vertProgram, glu::SHADERTYPE_VERTEX);
839	verifyCompileError(ctx, fragProgram, glu::SHADERTYPE_FRAGMENT);
840	verifyCompileError(ctx, tessCtrlProgram, glu::SHADERTYPE_TESSELLATION_CONTROL);
841	verifyCompileError(ctx, tessEvalProgram, glu::SHADERTYPE_TESSELLATION_EVALUATION);
842	verifyCompileError(ctx, geometryProgram, glu::SHADERTYPE_GEOMETRY);
843	verifyCompileError(ctx, computeProgram, glu::SHADERTYPE_COMPUTE);
844	ctx.endSection();
845}
846
847} // anonymous
848
849std::vector<FunctionContainer> getNegativeComputeTestFunctions (void)
850{
851	const FunctionContainer funcs[] =
852	{
853		{ program_not_active,					"program_not_active",					"Use dispatch commands with no active program"									},
854		{ invalid_program_query,				"invalid_program_query",				"Querying GL_COMPUTE_WORK_GROUP_SIZE with glGetProgramiv() on invalid programs"	},
855		{ invalid_dispatch_compute_indirect,	"invalid_dispatch_compute_indirect",	"Invalid glDispatchComputeIndirect usage"										},
856		{ invalid_maximum_work_group_counts,	"invalid_maximum_work_group_counts",	"Maximum workgroup counts for dispatch commands"								},
857		{ invalid_maximum_work_group_sizes,		"invalid_maximum_work_group_sizes",		"Maximum local workgroup sizes declared in compute shaders"						},
858		{ invalid_layout_qualifiers,			"invalid_layout_qualifiers",			"Invalid layout qualifiers in compute shaders"									},
859		{ invalid_write_built_in_constants,		"invalid_write_built_in_constants",		"Invalid writes to built-in compute shader constants"							},
860		{ exceed_uniform_block_limit,			"exceed_uniform_block_limit",			"Link error when shader exceeds GL_MAX_COMPUTE_UNIFORM_BLOCKS"					},
861		{ exceed_shader_storage_block_limit,	"exceed_shader_storage_block_limit",	"Link error when shader exceeds GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS"			},
862		{ exceed_texture_image_units_limit,		"exceed_texture_image_units_limit",		"Link error when shader exceeds GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS"				},
863		{ exceed_image_uniforms_limit,			"exceed_image_uniforms_limit",			"Link error when shader exceeds GL_MAX_COMPUTE_IMAGE_UNIFORMS"					},
864		{ exceed_shared_memory_size_limit,		"exceed_shared_memory_size_limit",		"Link error when shader exceeds GL_MAX_COMPUTE_SHARED_MEMORY_SIZE"				},
865		{ exceed_uniform_components_limit,		"exceed_uniform_components_limit",		"Link error when shader exceeds GL_MAX_COMPUTE_UNIFORM_COMPONENTS"				},
866		{ exceed_atomic_counter_buffer_limit,	"exceed_atomic_counter_buffer_limit",	"Link error when shader exceeds GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS"			},
867		{ exceed_atomic_counters_limit,			"exceed_atomic_counters_limit",			"Link error when shader exceeds GL_MAX_COMPUTE_ATOMIC_COUNTERS"					},
868	};
869
870	return std::vector<FunctionContainer>(DE_ARRAY_BEGIN(funcs), DE_ARRAY_END(funcs));
871}
872
873} // NegativeTestShared
874} // Functional
875} // gles31
876} // deqp
877