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