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
31 namespace deqp
32 {
33
34 using std::string;
35 using std::map;
36
37 namespace gles31
38 {
39 namespace Functional
40 {
41 namespace NegativeTestShared
42 {
43 namespace
44 {
45
46 using tcu::TestLog;
47 using namespace glw;
48
49 static 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
56 static 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
65 static 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
71 static 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
getResourceLimit(NegativeTestContext & ctx,GLenum resource)78 int getResourceLimit (NegativeTestContext& ctx, GLenum resource)
79 {
80 int limit = 0;
81 ctx.glGetIntegerv(resource, &limit);
82
83 return limit;
84 }
85
verifyLinkError(NegativeTestContext & ctx,const glu::ShaderProgram & program)86 void 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
verifyCompileError(NegativeTestContext & ctx,const glu::ShaderProgram & program,glu::ShaderType shaderType)103 void 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
generateComputeShader(NegativeTestContext & ctx,const string & shaderDeclarations,const string & shaderBody)120 string 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
genBuiltInSource(glu::ShaderType shaderType)140 string 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
exceed_uniform_block_limit(NegativeTestContext & ctx)184 void 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
exceed_shader_storage_block_limit(NegativeTestContext & ctx)202 void 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
exceed_texture_image_units_limit(NegativeTestContext & ctx)220 void 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
exceed_image_uniforms_limit(NegativeTestContext & ctx)256 void 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
exceed_shared_memory_size_limit(NegativeTestContext & ctx)280 void 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
exceed_uniform_components_limit(NegativeTestContext & ctx)303 void 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
exceed_atomic_counter_buffer_limit(NegativeTestContext & ctx)326 void 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
exceed_atomic_counters_limit(NegativeTestContext & ctx)358 void 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
program_not_active(NegativeTestContext & ctx)383 void 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
invalid_program_query(NegativeTestContext & ctx)444 void 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
invalid_dispatch_compute_indirect(NegativeTestContext & ctx)494 void 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
invalid_maximum_work_group_counts(NegativeTestContext & ctx)585 void 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
invalid_maximum_work_group_sizes(NegativeTestContext & ctx)631 void 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((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
invalid_layout_qualifiers(NegativeTestContext & ctx)707 void 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
invalid_write_built_in_constants(NegativeTestContext & ctx)801 void 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
getNegativeComputeTestFunctions(void)849 std::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