xref: /aosp_15_r20/external/deqp/modules/gles31/functional/es31fNegativeTessellationTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 3.1 Module
3  * -------------------------------------------------
4  *
5  * Copyright 2016 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Negative Tessellation tests.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "es31fNegativeTessellationTests.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 
44 using tcu::TestLog;
45 using namespace glw;
46 
47 static const char *vertexShaderSource = "${GLSL_VERSION_STRING}\n"
48                                         "${GLSL_PER_VERTEX_OUT}\n"
49                                         "void main (void)\n"
50                                         "{\n"
51                                         "    gl_Position = vec4(0.0);\n"
52                                         "}\n";
53 
54 static const char *fragmentShaderSource = "${GLSL_VERSION_STRING}\n"
55                                           "precision mediump float;\n"
56                                           "layout(location = 0) out mediump vec4 fragColor;\n"
57                                           "\n"
58                                           "void main (void)\n"
59                                           "{\n"
60                                           "    fragColor = vec4(1.0);\n"
61                                           "}\n";
62 
63 static const char *tessControlShaderSource =
64     "${GLSL_VERSION_STRING}\n"
65     "${GLSL_TESS_EXTENSION_STRING}\n"
66     "${GLSL_PER_VERTEX_IN_ARR}\n"
67     "${GLSL_PER_VERTEX_OUT_ARR}\n"
68     "layout (vertices=3) out;\n"
69     "\n"
70     "void main()\n"
71     "{\n"
72     "    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
73     "}\n";
74 
75 static const char *tessEvalShaderSource = "${GLSL_VERSION_STRING}\n"
76                                           "${GLSL_TESS_EXTENSION_STRING}\n"
77                                           "${GLSL_PER_VERTEX_IN_ARR}\n"
78                                           "${GLSL_PER_VERTEX_OUT}\n"
79                                           "layout(triangles) in;\n"
80                                           "\n"
81                                           "void main()\n"
82                                           "{\n"
83                                           "    gl_Position = gl_TessCoord[0] * gl_in[0].gl_Position;\n"
84                                           "}\n";
85 
checkExtensionSupport(NegativeTestContext & ctx,const char * extName)86 static void checkExtensionSupport(NegativeTestContext &ctx, const char *extName)
87 {
88     if (!ctx.getContextInfo().isExtensionSupported(extName))
89         throw tcu::NotSupportedError(string(extName) + " not supported");
90 }
91 
checkTessellationSupport(NegativeTestContext & ctx)92 static void checkTessellationSupport(NegativeTestContext &ctx)
93 {
94     if (glu::isContextTypeES(ctx.getRenderContext().getType()))
95         checkExtensionSupport(ctx, "GL_EXT_tessellation_shader");
96 }
97 
98 // Helper for constructing tessellation pipeline sources.
makeTessPipelineSources(const std::string & vertexSrc,const std::string & fragmentSrc,const std::string & tessCtrlSrc,const std::string & tessEvalSrc)99 static glu::ProgramSources makeTessPipelineSources(const std::string &vertexSrc, const std::string &fragmentSrc,
100                                                    const std::string &tessCtrlSrc, const std::string &tessEvalSrc)
101 {
102     glu::ProgramSources sources;
103     sources.sources[glu::SHADERTYPE_VERTEX].push_back(vertexSrc);
104     sources.sources[glu::SHADERTYPE_FRAGMENT].push_back(fragmentSrc);
105 
106     if (!tessCtrlSrc.empty())
107         sources.sources[glu::SHADERTYPE_TESSELLATION_CONTROL].push_back(tessCtrlSrc);
108 
109     if (!tessEvalSrc.empty())
110         sources.sources[glu::SHADERTYPE_TESSELLATION_EVALUATION].push_back(tessEvalSrc);
111 
112     return sources;
113 }
114 
constructSpecializationMap(NegativeTestContext & ctx)115 map<string, string> constructSpecializationMap(NegativeTestContext &ctx)
116 {
117     glu::GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(ctx.getRenderContext().getType());
118     bool isES31                  = (glslVersion == glu::GLSL_VERSION_310_ES);
119     string ext                   = isES31 ? "#extension GL_EXT_tessellation_shader : require" : "";
120     return {{"GLSL_VERSION_STRING", getGLSLVersionDeclaration(glslVersion)},
121             {"GLSL_TESS_EXTENSION_STRING", ext},
122             {"GLSL_PER_VERTEX_OUT", ""}, // needed for GL4.5
123             {"GLSL_PER_VERTEX_IN_ARR", ""},
124             {"GLSL_PER_VERTEX_OUT_ARR", ""}};
125 }
126 
127 // Incomplete active tess shaders
single_tessellation_stage(NegativeTestContext & ctx)128 void single_tessellation_stage(NegativeTestContext &ctx)
129 {
130     // this case does not apply to GL4.5
131     if (!glu::isContextTypeES(ctx.getRenderContext().getType()))
132         return;
133 
134     const bool requireTES    = !ctx.getContextInfo().isExtensionSupported("GL_NV_gpu_shader5");
135     map<string, string> args = constructSpecializationMap(ctx);
136 
137     checkTessellationSupport(ctx);
138 
139     {
140         glu::ShaderProgram program(
141             ctx.getRenderContext(),
142             makeTessPipelineSources(tcu::StringTemplate(vertexShaderSource).specialize(args),
143                                     tcu::StringTemplate(fragmentShaderSource).specialize(args),
144                                     tcu::StringTemplate(tessControlShaderSource).specialize(args),
145                                     "")); // missing tessEvalShaderSource
146         tcu::TestLog &log = ctx.getLog();
147         log << program;
148 
149         ctx.beginSection("A link error is generated if a non-separable program has a tessellation control shader but "
150                          "no tessellation evaluation shader, unless GL_NV_gpu_shader5 is supported.");
151 
152         if (requireTES && program.isOk())
153             ctx.fail("Program was not expected to link");
154         else if (!requireTES && !program.isOk())
155             ctx.fail("Program was expected to link");
156 
157         ctx.endSection();
158     }
159 
160     {
161         glu::ShaderProgram program(
162             ctx.getRenderContext(),
163             makeTessPipelineSources(tcu::StringTemplate(vertexShaderSource).specialize(args),
164                                     tcu::StringTemplate(fragmentShaderSource).specialize(args),
165                                     tcu::StringTemplate(tessControlShaderSource).specialize(args),
166                                     "") // missing tessEvalShaderSource
167                 << glu::ProgramSeparable(true));
168         tcu::TestLog &log = ctx.getLog();
169         log << program;
170 
171         if (!program.isOk())
172             TCU_THROW(TestError, "failed to build program");
173 
174         ctx.glUseProgram(program.getProgram());
175         ctx.expectError(GL_NO_ERROR);
176 
177         ctx.beginSection("GL_INVALID_OPERATION is generated if current program state has tessellation control shader "
178                          "but no tessellation evaluation shader, unless GL_NV_gpu_shader5 is supported.");
179         ctx.glDrawArrays(GL_PATCHES, 0, 3);
180         ctx.expectError(requireTES ? GL_INVALID_OPERATION : GL_NO_ERROR);
181         ctx.endSection();
182 
183         ctx.glUseProgram(0);
184     }
185 
186     {
187         glu::ShaderProgram program(ctx.getRenderContext(),
188                                    makeTessPipelineSources(tcu::StringTemplate(vertexShaderSource).specialize(args),
189                                                            tcu::StringTemplate(fragmentShaderSource).specialize(args),
190                                                            "", // missing tessControlShaderSource
191                                                            tcu::StringTemplate(tessEvalShaderSource).specialize(args)));
192         tcu::TestLog &log = ctx.getLog();
193         log << program;
194 
195         ctx.beginSection("A link error is generated if a non-separable program has a tessellation evaluation shader "
196                          "but no tessellation control shader.");
197 
198         if (program.isOk())
199             ctx.fail("Program was not expected to link");
200 
201         ctx.endSection();
202     }
203 
204     {
205         glu::ShaderProgram program(ctx.getRenderContext(),
206                                    makeTessPipelineSources(tcu::StringTemplate(vertexShaderSource).specialize(args),
207                                                            tcu::StringTemplate(fragmentShaderSource).specialize(args),
208                                                            "", // missing tessControlShaderSource
209                                                            tcu::StringTemplate(tessEvalShaderSource).specialize(args))
210                                        << glu::ProgramSeparable(true));
211         tcu::TestLog &log = ctx.getLog();
212         log << program;
213 
214         if (!program.isOk())
215             TCU_THROW(TestError, "failed to build program");
216 
217         ctx.glUseProgram(program.getProgram());
218         ctx.expectError(GL_NO_ERROR);
219 
220         ctx.beginSection("GL_INVALID_OPERATION is generated if current program state has tessellation evaluation "
221                          "shader but no tessellation control shader.");
222         ctx.glDrawArrays(GL_PATCHES, 0, 3);
223         ctx.expectError(GL_INVALID_OPERATION);
224         ctx.endSection();
225 
226         ctx.glUseProgram(0);
227     }
228 }
229 
230 // Complete active tess shaders invalid primitive mode
invalid_primitive_mode(NegativeTestContext & ctx)231 void invalid_primitive_mode(NegativeTestContext &ctx)
232 {
233     checkTessellationSupport(ctx);
234 
235     map<string, string> args = constructSpecializationMap(ctx);
236     glu::ShaderProgram program(ctx.getRenderContext(),
237                                makeTessPipelineSources(tcu::StringTemplate(vertexShaderSource).specialize(args),
238                                                        tcu::StringTemplate(fragmentShaderSource).specialize(args),
239                                                        tcu::StringTemplate(tessControlShaderSource).specialize(args),
240                                                        tcu::StringTemplate(tessEvalShaderSource).specialize(args)));
241     tcu::TestLog &log = ctx.getLog();
242     log << program;
243 
244     ctx.glUseProgram(program.getProgram());
245     ctx.expectError(GL_NO_ERROR);
246 
247     ctx.beginSection(
248         "GL_INVALID_OPERATION is generated if tessellation is active and primitive mode is not GL_PATCHES.");
249     ctx.glDrawArrays(GL_TRIANGLES, 0, 3);
250     ctx.expectError(GL_INVALID_OPERATION);
251     ctx.endSection();
252 
253     ctx.glUseProgram(0);
254 }
255 
tessellation_not_active(NegativeTestContext & ctx)256 void tessellation_not_active(NegativeTestContext &ctx)
257 {
258     checkTessellationSupport(ctx);
259 
260     const glw::GLenum tessErr =
261         ctx.getContextInfo().isExtensionSupported("GL_NV_gpu_shader5") ? GL_NO_ERROR : GL_INVALID_OPERATION;
262     map<string, string> args = constructSpecializationMap(ctx);
263     glu::ShaderProgram program(ctx.getRenderContext(),
264                                makeTessPipelineSources(tcu::StringTemplate(vertexShaderSource).specialize(args),
265                                                        tcu::StringTemplate(fragmentShaderSource).specialize(args),
266                                                        "",   // missing tessControlShaderSource
267                                                        "")); // missing tessEvalShaderSource
268     tcu::TestLog &log = ctx.getLog();
269     log << program;
270 
271     GLuint vao = 0;
272     if (!glu::isContextTypeES(ctx.getRenderContext().getType()))
273     {
274         ctx.glGenVertexArrays(1, &vao);
275         ctx.glBindVertexArray(vao);
276     }
277 
278     ctx.glUseProgram(program.getProgram());
279     ctx.expectError(GL_NO_ERROR);
280 
281     ctx.beginSection("GL_INVALID_OPERATION is generated if tessellation is not active and primitive mode is "
282                      "GL_PATCHES, unless GL_NV_gpu_shader5 is supported.");
283     ctx.glDrawArrays(GL_PATCHES, 0, 3);
284     ctx.expectError(tessErr);
285     ctx.endSection();
286 
287     ctx.glUseProgram(0);
288 
289     if (vao)
290         ctx.glDeleteVertexArrays(1, &vao);
291 }
292 
invalid_program_state(NegativeTestContext & ctx)293 void invalid_program_state(NegativeTestContext &ctx)
294 {
295     checkTessellationSupport(ctx);
296 
297     const glu::RenderContext &rc = ctx.getRenderContext();
298     map<string, string> args     = constructSpecializationMap(ctx);
299 
300     // for gl4.5 we need to add per vertex sections
301     if (!glu::isContextTypeES(rc.getType()))
302     {
303         args["GLSL_PER_VERTEX_OUT"]     = "out gl_PerVertex { vec4 gl_Position; };\n";
304         args["GLSL_PER_VERTEX_IN_ARR"]  = "in gl_PerVertex { vec4 gl_Position; } gl_in[];\n";
305         args["GLSL_PER_VERTEX_OUT_ARR"] = "out gl_PerVertex { vec4 gl_Position; } gl_out[];\n";
306     }
307 
308     glu::FragmentSource frgSource(tcu::StringTemplate(fragmentShaderSource).specialize(args));
309     glu::TessellationControlSource tessCtrlSource(tcu::StringTemplate(tessControlShaderSource).specialize(args));
310     glu::TessellationEvaluationSource tessEvalSource(tcu::StringTemplate(tessEvalShaderSource).specialize(args));
311 
312     glu::ProgramPipeline pipeline(rc);
313 
314     glu::ShaderProgram fragProgram(rc, glu::ProgramSources() << glu::ProgramSeparable(true) << frgSource);
315     glu::ShaderProgram tessCtrlProgram(rc, glu::ProgramSources() << glu::ProgramSeparable(true) << tessCtrlSource);
316     glu::ShaderProgram tessEvalProgram(rc, glu::ProgramSources() << glu::ProgramSeparable(true) << tessEvalSource);
317 
318     tcu::TestLog &log = ctx.getLog();
319     log << fragProgram << tessCtrlProgram << tessEvalProgram;
320 
321     if (!fragProgram.isOk() || !tessCtrlProgram.isOk() || !tessEvalProgram.isOk())
322         throw tcu::TestError("failed to build program");
323 
324     ctx.glBindProgramPipeline(pipeline.getPipeline());
325     ctx.expectError(GL_NO_ERROR);
326 
327     ctx.glUseProgramStages(pipeline.getPipeline(), GL_FRAGMENT_SHADER_BIT, fragProgram.getProgram());
328     ctx.glUseProgramStages(pipeline.getPipeline(), GL_TESS_CONTROL_SHADER_BIT, tessCtrlProgram.getProgram());
329     ctx.glUseProgramStages(pipeline.getPipeline(), GL_TESS_EVALUATION_SHADER_BIT, tessEvalProgram.getProgram());
330     ctx.expectError(GL_NO_ERROR);
331 
332     ctx.beginSection("GL_INVALID_OPERATION is generated if tessellation is active and vertex shader is missing.");
333     ctx.glDrawArrays(GL_PATCHES, 0, 3);
334     ctx.expectError(GL_INVALID_OPERATION);
335     ctx.endSection();
336 
337     ctx.glBindProgramPipeline(0);
338     ctx.expectError(GL_NO_ERROR);
339 }
340 
tessellation_control_invalid_vertex_count(NegativeTestContext & ctx)341 void tessellation_control_invalid_vertex_count(NegativeTestContext &ctx)
342 {
343     checkTessellationSupport(ctx);
344 
345     const char *const tessControlVertLimitSource =
346         "${GLSL_VERSION_STRING}\n"
347         "${GLSL_TESS_EXTENSION_STRING}\n"
348         "layout (vertices=${GL_MAX_PATCH_LIMIT}) out;\n"
349         "void main()\n"
350         "{\n"
351         "    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
352         "}\n";
353 
354     map<string, string> args = constructSpecializationMap(ctx);
355     int maxPatchVertices     = 0;
356 
357     ctx.beginSection("Output vertex count exceeds GL_MAX_PATCH_VERTICES.");
358     ctx.glGetIntegerv(GL_MAX_PATCH_VERTICES, &maxPatchVertices);
359     ctx.expectError(GL_NO_ERROR);
360 
361     std::ostringstream oss;
362     oss << (maxPatchVertices + 1);
363     args["GL_MAX_PATCH_LIMIT"] = oss.str();
364 
365     glu::ShaderProgram program(ctx.getRenderContext(),
366                                makeTessPipelineSources(tcu::StringTemplate(vertexShaderSource).specialize(args),
367                                                        tcu::StringTemplate(fragmentShaderSource).specialize(args),
368                                                        tcu::StringTemplate(tessControlVertLimitSource).specialize(args),
369                                                        tcu::StringTemplate(tessEvalShaderSource).specialize(args)));
370     tcu::TestLog &log = ctx.getLog();
371     log << program;
372 
373     bool testFailed = program.getProgramInfo().linkOk;
374 
375     if (testFailed)
376         ctx.fail("Program was not expected to link");
377 
378     ctx.endSection();
379 }
380 
invalid_get_programiv(NegativeTestContext & ctx)381 void invalid_get_programiv(NegativeTestContext &ctx)
382 {
383     checkTessellationSupport(ctx);
384 
385     GLuint program  = ctx.glCreateProgram();
386     GLint params[1] = {0};
387 
388     ctx.beginSection("GL_INVALID_OPERATION is generated if GL_TESS_CONTROL_OUTPUT_VERTICES is queried for a program "
389                      "which has not been linked properly.");
390     ctx.glGetProgramiv(program, GL_TESS_CONTROL_OUTPUT_VERTICES, &params[0]);
391     ctx.expectError(GL_INVALID_OPERATION);
392     ctx.endSection();
393 
394     ctx.beginSection("GL_INVALID_OPERATION is generated if GL_TESS_GEN_MODE is queried for a program which has not "
395                      "been linked properly.");
396     ctx.glGetProgramiv(program, GL_TESS_GEN_MODE, &params[0]);
397     ctx.expectError(GL_INVALID_OPERATION);
398     ctx.endSection();
399 
400     ctx.beginSection("GL_INVALID_OPERATION is generated if GL_TESS_GEN_SPACING is queried for a program which has not "
401                      "been linked properly.");
402     ctx.glGetProgramiv(program, GL_TESS_GEN_SPACING, &params[0]);
403     ctx.expectError(GL_INVALID_OPERATION);
404     ctx.endSection();
405 
406     ctx.beginSection("GL_INVALID_OPERATION is generated if GL_TESS_GEN_VERTEX_ORDER is queried for a program which has "
407                      "not been linked properly.");
408     ctx.glGetProgramiv(program, GL_TESS_GEN_VERTEX_ORDER, &params[0]);
409     ctx.expectError(GL_INVALID_OPERATION);
410     ctx.endSection();
411 
412     ctx.beginSection("GL_INVALID_OPERATION is generated if GL_TESS_GEN_POINT_MODE is queried for a program which has "
413                      "not been linked properly.");
414     ctx.glGetProgramiv(program, GL_TESS_GEN_POINT_MODE, &params[0]);
415     ctx.expectError(GL_INVALID_OPERATION);
416     ctx.endSection();
417 
418     ctx.glDeleteProgram(program);
419 }
420 
invalid_patch_parameteri(NegativeTestContext & ctx)421 void invalid_patch_parameteri(NegativeTestContext &ctx)
422 {
423     checkTessellationSupport(ctx);
424 
425     ctx.beginSection("GL_INVALID_ENUM is generated if pname is not GL_PATCH_VERTICES.");
426     ctx.glPatchParameteri(-1, 1);
427     ctx.expectError(GL_INVALID_ENUM);
428     ctx.endSection();
429 
430     ctx.beginSection("GL_INVALID_VALUE is generated if value is less than or equal to zero.");
431     ctx.glPatchParameteri(GL_PATCH_VERTICES, 0);
432     ctx.expectError(GL_INVALID_VALUE);
433     ctx.endSection();
434 
435     int maxPatchVertices = 0;
436     ctx.glGetIntegerv(GL_MAX_PATCH_VERTICES, &maxPatchVertices);
437     ctx.expectError(GL_NO_ERROR);
438 
439     ctx.beginSection("GL_INVALID_VALUE is generated if value is greater than GL_MAX_PATCH_VERTICES.");
440     ctx.glPatchParameteri(GL_PATCH_VERTICES, maxPatchVertices + 1);
441     ctx.expectError(GL_INVALID_VALUE);
442     ctx.endSection();
443 }
444 
getNegativeTessellationTestFunctions(void)445 std::vector<FunctionContainer> getNegativeTessellationTestFunctions(void)
446 {
447     const FunctionContainer funcs[] = {
448         {single_tessellation_stage, "single_tessellation_stage",
449          "Invalid program state with single tessellation stage"},
450         {invalid_primitive_mode, "invalid_primitive_mode", "Invalid primitive mode when tessellation is active"},
451         {tessellation_not_active, "tessellation_not_active", "Use of GL_PATCHES when tessellation is not active"},
452         {invalid_program_state, "invalid_program_state",
453          "Invalid program state when tessellation active but no vertex shader present"},
454         {invalid_get_programiv, "get_programiv", "Invalid glGetProgramiv() usage"},
455         {invalid_patch_parameteri, "invalid_program_queries", "Invalid glPatchParameteri() usage"},
456         {tessellation_control_invalid_vertex_count, "tessellation_control_invalid_vertex_count",
457          "Exceed vertex count limit in tessellation control shader"},
458     };
459 
460     return std::vector<FunctionContainer>(DE_ARRAY_BEGIN(funcs), DE_ARRAY_END(funcs));
461 }
462 
463 } // namespace NegativeTestShared
464 } // namespace Functional
465 } // namespace gles31
466 } // namespace deqp
467