xref: /aosp_15_r20/external/deqp/external/openglcts/modules/common/glcShaderNegativeTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*-------------------------------------------------------------------------
2  * OpenGL Conformance Test Suite
3  * -----------------------------
4  *
5  * Copyright (c) 2015-2016 The Khronos Group Inc.
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
22  */ /*-------------------------------------------------------------------*/
23 
24 /*!
25  * \file glcShaderNegativeTests.cpp
26  * \brief Negative tests for shaders and interface matching.
27  */ /*-------------------------------------------------------------------*/
28 
29 #include "glcShaderNegativeTests.hpp"
30 #include "deString.h"
31 #include "deStringUtil.hpp"
32 #include "gluContextInfo.hpp"
33 #include "gluShaderProgram.hpp"
34 #include "glw.h"
35 #include "tcuStringTemplate.hpp"
36 #include "tcuTestLog.hpp"
37 
38 namespace deqp
39 {
40 
41 using tcu::TestLog;
42 using namespace glu;
43 
44 struct ShaderVariants
45 {
46     GLSLVersion minimum_supported_version;
47     const char *vertex_precision;
48     const char *vertex_body;
49     const char *frag_precision;
50     const char *frag_body;
51     bool should_link;
52 };
53 
54 class ShaderUniformInitializeGlobalCase : public TestCase
55 {
56 public:
ShaderUniformInitializeGlobalCase(Context & context,const char * name,const char * description,GLSLVersion glslVersion)57     ShaderUniformInitializeGlobalCase(Context &context, const char *name, const char *description,
58                                       GLSLVersion glslVersion)
59         : TestCase(context, name, description)
60         , m_glslVersion(glslVersion)
61     {
62     }
63 
~ShaderUniformInitializeGlobalCase()64     ~ShaderUniformInitializeGlobalCase()
65     {
66         // empty
67     }
68 
iterate()69     IterateResult iterate()
70     {
71         qpTestResult result = QP_TEST_RESULT_PASS;
72 
73         static const char vertex_source_template[] =
74             "${VERSION_DECL}\n"
75             "precision mediump float;\n"
76             "uniform vec4 nonconstantexpression;\n"
77             "vec4 globalconstant0 = vec4(1.0, 1.0, 1.0, 1.0);\n"
78             "vec4 globalconstant1 = nonconstantexpression;\n"
79             "\n"
80             "void main(void) { gl_Position = globalconstant0+globalconstant1; }\n";
81         static const char fragment_source_template[] = "${VERSION_DECL}\n"
82                                                        "precision mediump float;\n"
83                                                        "uniform vec4 nonconstantexpression;\n"
84                                                        "vec4 globalconstant0 = vec4(1.0, 1.0, 1.0, 1.0);\n"
85                                                        "vec4 globalconstant1 = nonconstantexpression;\n"
86                                                        "\n"
87                                                        "void main(void) { }\n";
88 
89         std::map<std::string, std::string> args;
90         args["VERSION_DECL"] = getGLSLVersionDeclaration(m_glslVersion);
91 
92         std::string vertex_code   = tcu::StringTemplate(vertex_source_template).specialize(args);
93         std::string fragment_code = tcu::StringTemplate(fragment_source_template).specialize(args);
94 
95         // Setup program.
96         ShaderProgram program(m_context.getRenderContext(),
97                               makeVtxFragSources(vertex_code.c_str(), fragment_code.c_str()));
98 
99         // GLSL ES does not allow initialization of global variables with non-constant
100         // expressions, but GLSL does.
101         // Check that either compilation or linking fails for ES, and that everything
102         // succeeds for GL.
103         bool vertexOk   = program.getShaderInfo(SHADERTYPE_VERTEX).compileOk;
104         bool fragmentOk = program.getShaderInfo(SHADERTYPE_FRAGMENT).compileOk;
105         bool linkOk     = program.getProgramInfo().linkOk;
106 
107         if (glslVersionIsES(m_glslVersion))
108         {
109             if (vertexOk && fragmentOk && linkOk)
110                 result = QP_TEST_RESULT_FAIL;
111         }
112         else
113         {
114             if (!vertexOk && !fragmentOk && !linkOk)
115                 result = QP_TEST_RESULT_FAIL;
116         }
117 
118         m_testCtx.setTestResult(result, qpGetTestResultName(result));
119 
120         return STOP;
121     }
122 
123 protected:
124     GLSLVersion m_glslVersion;
125 };
126 
127 class ShaderUniformPrecisionLinkCase : public TestCase
128 {
129 public:
ShaderUniformPrecisionLinkCase(Context & context,const char * name,const char * description,const ShaderVariants * shaderVariants,unsigned int shaderVariantsCount,GLSLVersion glslVersion)130     ShaderUniformPrecisionLinkCase(Context &context, const char *name, const char *description,
131                                    const ShaderVariants *shaderVariants, unsigned int shaderVariantsCount,
132                                    GLSLVersion glslVersion)
133         : TestCase(context, name, description)
134         , m_glslVersion(glslVersion)
135         , m_shaderVariants(shaderVariants)
136         , m_shaderVariantsCount(shaderVariantsCount)
137     {
138     }
139 
~ShaderUniformPrecisionLinkCase()140     ~ShaderUniformPrecisionLinkCase()
141     {
142         // empty
143     }
144 
iterate()145     IterateResult iterate()
146     {
147         TestLog &log        = m_testCtx.getLog();
148         qpTestResult result = QP_TEST_RESULT_PASS;
149 
150         static const char vertex_source_template[] = "${VERSION_DECL}\n"
151                                                      "uniform ${PREC_QUALIFIER} vec4 value;\n"
152                                                      "\n"
153                                                      "void main(void) { ${BODY} }\n";
154 
155         static const char fragment_source_template[] = "${VERSION_DECL}\n"
156                                                        "out highp vec4 result;\n"
157                                                        "uniform ${PREC_QUALIFIER} vec4 value;\n"
158                                                        "\n"
159                                                        "void main(void) { ${BODY} }\n";
160 
161         for (unsigned int i = 0; i < m_shaderVariantsCount; i++)
162         {
163             std::map<std::string, std::string> args;
164 
165             if (m_glslVersion <= m_shaderVariants[i].minimum_supported_version)
166             {
167                 continue;
168             }
169 
170             args["VERSION_DECL"]   = getGLSLVersionDeclaration(m_glslVersion);
171             args["PREC_QUALIFIER"] = m_shaderVariants[i].vertex_precision;
172             args["BODY"]           = m_shaderVariants[i].vertex_body;
173             std::string vcode      = tcu::StringTemplate(vertex_source_template).specialize(args);
174 
175             args["PREC_QUALIFIER"] = m_shaderVariants[i].frag_precision;
176             args["BODY"]           = m_shaderVariants[i].frag_body;
177             std::string fcode      = tcu::StringTemplate(fragment_source_template).specialize(args);
178 
179             // Setup program.
180             ShaderProgram program(m_context.getRenderContext(), makeVtxFragSources(vcode.c_str(), fcode.c_str()));
181 
182             // Check that compile/link results are what we expect.
183             bool vertexOk          = program.getShaderInfo(SHADERTYPE_VERTEX).compileOk;
184             bool fragmentOk        = program.getShaderInfo(SHADERTYPE_FRAGMENT).compileOk;
185             bool linkOk            = program.getProgramInfo().linkOk;
186             const char *failReason = DE_NULL;
187 
188             if (!vertexOk || !fragmentOk)
189             {
190                 failReason = "expected shaders to compile, but failed.";
191             }
192             else if (m_shaderVariants[i].should_link && !linkOk)
193             {
194                 failReason = "expected shaders to link, but failed.";
195             }
196             else if (!m_shaderVariants[i].should_link && linkOk)
197             {
198                 failReason = "expected shaders to fail linking, but succeeded.";
199             }
200 
201             if (failReason != DE_NULL)
202             {
203                 log << TestLog::Message << "ERROR: " << failReason << TestLog::EndMessage;
204                 result = QP_TEST_RESULT_FAIL;
205             }
206         }
207 
208         m_testCtx.setTestResult(result, qpGetTestResultName(result));
209 
210         return STOP;
211     }
212 
213 protected:
214     GLSLVersion m_glslVersion;
215     const ShaderVariants *m_shaderVariants;
216     unsigned int m_shaderVariantsCount;
217 };
218 
219 class ShaderConstantSequenceExpressionCase : public TestCase
220 {
221 public:
ShaderConstantSequenceExpressionCase(Context & context,const char * name,const char * description,GLSLVersion glslVersion)222     ShaderConstantSequenceExpressionCase(Context &context, const char *name, const char *description,
223                                          GLSLVersion glslVersion)
224         : TestCase(context, name, description)
225         , m_glslVersion(glslVersion)
226     {
227     }
228 
~ShaderConstantSequenceExpressionCase()229     ~ShaderConstantSequenceExpressionCase()
230     {
231         // empty
232     }
233 
iterate()234     IterateResult iterate()
235     {
236         qpTestResult result = QP_TEST_RESULT_PASS;
237 
238         static const char vertex_source_template[] = "${VERSION_DECL}\n"
239                                                      "precision mediump float;\n"
240                                                      "const int test = (1, 2);\n"
241                                                      "\n"
242                                                      "void main(void) { gl_Position = vec4(test); }\n";
243 
244         static const char fragment_source_template[] = "${VERSION_DECL}\n"
245                                                        "precision mediump float;\n"
246                                                        "\n"
247                                                        "void main(void) { }\n";
248 
249         std::map<std::string, std::string> args;
250         args["VERSION_DECL"] = getGLSLVersionDeclaration(m_glslVersion);
251 
252         std::string vertex_code   = tcu::StringTemplate(vertex_source_template).specialize(args);
253         std::string fragment_code = tcu::StringTemplate(fragment_source_template).specialize(args);
254 
255         // Setup program.
256         ShaderProgram program(m_context.getRenderContext(),
257                               makeVtxFragSources(vertex_code.c_str(), fragment_code.c_str()));
258 
259         // GLSL does not allow the sequence operator in a constant expression
260         // Check that either compilation or linking fails
261         bool vertexOk   = program.getShaderInfo(SHADERTYPE_VERTEX).compileOk;
262         bool fragmentOk = program.getShaderInfo(SHADERTYPE_FRAGMENT).compileOk;
263         bool linkOk     = program.getProgramInfo().linkOk;
264 
265         bool run_test_es      = (glslVersionIsES(m_glslVersion) && m_glslVersion > GLSL_VERSION_100_ES);
266         bool run_test_desktop = (m_glslVersion > GLSL_VERSION_420);
267         if (run_test_es || run_test_desktop)
268         {
269             if (vertexOk && fragmentOk && linkOk)
270                 result = QP_TEST_RESULT_FAIL;
271         }
272 
273         m_testCtx.setTestResult(result, qpGetTestResultName(result));
274 
275         return STOP;
276     }
277 
278 protected:
279     GLSLVersion m_glslVersion;
280 };
281 
282 class ShaderNonPrecisionQualifiersStructCase : public TestCase
283 {
284 public:
ShaderNonPrecisionQualifiersStructCase(Context & context,const char * name,const char * description,GLSLVersion glslVersion)285     ShaderNonPrecisionQualifiersStructCase(Context &context, const char *name, const char *description,
286                                            GLSLVersion glslVersion)
287         : TestCase(context, name, description)
288         , m_glslVersion(glslVersion)
289     {
290     }
291 
~ShaderNonPrecisionQualifiersStructCase()292     ~ShaderNonPrecisionQualifiersStructCase()
293     {
294         // empty
295     }
296 
iterate()297     IterateResult iterate()
298     {
299         static const char *qualifier_values[] = {
300             // Storage Qualifiers
301             "const",
302             "in",
303             "out",
304             "attribute",
305             "uniform",
306             "varying",
307             "buffer",
308             "shared",
309 
310             // Interpolation Qualifiers
311             "smooth in",
312             "flat in",
313             "noperspective in",
314             "smooth out",
315             "flat out",
316             "noperspective out",
317 
318             // Invariant Qualifier
319             "invariant",
320 
321             // Precise Qualifier
322             "precise",
323 
324             // Memory Qualifiers
325             "coherent",
326             "volatile",
327             "restrict",
328             "readonly",
329             "writeonly",
330         };
331         static const unsigned qualifier_count = sizeof(qualifier_values) / sizeof(qualifier_values[0]);
332 
333         static const char *layout_values[] = {
334             "(shared)",    "(packed)",       "(std140)", "(std430)",
335 
336             "(row_major)", "(column_major)",
337         };
338         static const unsigned layout_count = sizeof(layout_values) / sizeof(layout_values[0]);
339 
340         const std::string layout_str = "layout";
341 
342         std::map<std::string, std::string> args;
343         args["VERSION_DECL"] = getGLSLVersionDeclaration(m_glslVersion);
344 
345         // Vertex and fragment shaders
346         {
347             // Layout qualifier test
348             args["QUALIFIER"] = layout_str;
349             for (unsigned i = 0; i < layout_count; ++i)
350             {
351                 args["LAYOUT_VALUE"] = layout_values[i];
352                 if (testVertexFragment(args, layout_str + layout_values[i]))
353                     return STOP;
354             }
355 
356             // Remaining qualifier tests
357             args["LAYOUT_VALUE"] = "";
358             for (unsigned i = 0; i < qualifier_count; ++i)
359             {
360                 args["QUALIFIER"] = qualifier_values[i];
361                 if (testVertexFragment(args, qualifier_values[i]))
362                     return STOP;
363             }
364         }
365 
366         // Compute shader, not available for GLES2 and GLES3
367         if (!glslVersionIsES(m_glslVersion) || m_glslVersion >= GLSL_VERSION_310_ES)
368         {
369             // Layout qualifier test
370             args["QUALIFIER"] = layout_str;
371             for (unsigned i = 0; i < layout_count; ++i)
372             {
373                 args["LAYOUT_VALUE"] = layout_values[i];
374                 if (testCompute(args, layout_str + layout_values[i]))
375                     return STOP;
376             }
377 
378             // Remaining qualifier tests
379             args["LAYOUT_VALUE"] = "";
380             for (unsigned i = 0; i < qualifier_count; ++i)
381             {
382                 args["QUALIFIER"] = qualifier_values[i];
383                 if (testCompute(args, qualifier_values[i]))
384                     return STOP;
385             }
386         }
387 
388         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, qpGetTestResultName(QP_TEST_RESULT_PASS));
389 
390         return STOP;
391     }
392 
393 protected:
testVertexFragment(const std::map<std::string,std::string> & args,const std::string & qualifier_name)394     bool testVertexFragment(const std::map<std::string, std::string> &args, const std::string &qualifier_name)
395     {
396         static const char *vertex_source_template = "${VERSION_DECL}\n"
397                                                     "precision mediump float;\n"
398                                                     "struct Base\n"
399                                                     "{\n"
400                                                     "  ${QUALIFIER} ${LAYOUT_VALUE} mat4 some_matrix;\n"
401                                                     "};\n"
402                                                     "\n"
403                                                     "void main(void)\n"
404                                                     "{\n"
405                                                     "  gl_Position = vec4(1.0f, 0.0f, 0.0f, 1.0f);\n"
406                                                     "}\n";
407 
408         static const char *fragment_source_template = "${VERSION_DECL}\n"
409                                                       "precision mediump float;\n"
410                                                       "struct Base\n"
411                                                       "{\n"
412                                                       "  ${QUALIFIER} ${LAYOUT_VALUE} mat4 some_matrix;\n"
413                                                       "};\n"
414                                                       "\n"
415                                                       "void main(void) { }\n";
416 
417         std::string vertex_code   = tcu::StringTemplate(vertex_source_template).specialize(args);
418         std::string fragment_code = tcu::StringTemplate(fragment_source_template).specialize(args);
419         ShaderProgram program(m_context.getRenderContext(),
420                               makeVtxFragSources(vertex_code.c_str(), fragment_code.c_str()));
421         if (program.getShaderInfo(SHADERTYPE_VERTEX).compileOk || program.getShaderInfo(SHADERTYPE_FRAGMENT).compileOk)
422         {
423             m_testCtx.getLog() << TestLog::Message << "ERROR: expected shaders not to compile, but failed with \'"
424                                << qualifier_name << "\' qualifier." << TestLog::EndMessage;
425             m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, qpGetTestResultName(QP_TEST_RESULT_FAIL));
426             return true;
427         }
428         return false;
429     }
430 
testCompute(const std::map<std::string,std::string> & args,const std::string & qualifier_name)431     bool testCompute(const std::map<std::string, std::string> &args, const std::string &qualifier_name)
432     {
433         static const char *compute_source_template = "${VERSION_DECL}\n"
434                                                      "precision mediump float;\n"
435                                                      "struct Base\n"
436                                                      "{\n"
437                                                      "  ${QUALIFIER} ${LAYOUT_VALUE} mat4 some_matrix;\n"
438                                                      "};\n"
439                                                      "\n"
440                                                      "void main(void) { }\n";
441 
442         std::string compute_code = tcu::StringTemplate(compute_source_template).specialize(args);
443         ProgramSources sources;
444         sources.sources[SHADERTYPE_COMPUTE].emplace_back(compute_code);
445         ShaderProgram program(m_context.getRenderContext(), sources);
446         if (program.getShaderInfo(SHADERTYPE_COMPUTE).compileOk)
447         {
448             m_testCtx.getLog() << TestLog::Message
449                                << "ERROR: expected compute shader not to compile, but failed with \'" << qualifier_name
450                                << "\' qualifier." << TestLog::EndMessage;
451             m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, qpGetTestResultName(QP_TEST_RESULT_FAIL));
452             return true;
453         }
454         return false;
455     }
456 
457     GLSLVersion m_glslVersion;
458 };
459 
ShaderNegativeTests(Context & context,GLSLVersion glslVersion)460 ShaderNegativeTests::ShaderNegativeTests(Context &context, GLSLVersion glslVersion)
461     : TestCaseGroup(context, "negative", "Shader Negative tests")
462     , m_glslVersion(glslVersion)
463 {
464     // empty
465 }
466 
~ShaderNegativeTests()467 ShaderNegativeTests::~ShaderNegativeTests()
468 {
469     // empty
470 }
471 
init(void)472 void ShaderNegativeTests::init(void)
473 {
474     addChild(new ShaderUniformInitializeGlobalCase(
475         m_context, "initialize", "Verify initialization of globals with non-constant expressions fails on ES.",
476         m_glslVersion));
477 
478     addChild(new ShaderConstantSequenceExpressionCase(
479         m_context, "constant_sequence", "Verify that the sequence operator cannot be used as a constant expression.",
480         m_glslVersion));
481 
482     addChild(new ShaderNonPrecisionQualifiersStructCase(
483         m_context, "non_precision_qualifiers_in_struct_members",
484         "Verify non-precision qualifiers in struct members are not allowed.", m_glslVersion));
485 
486     if (isGLSLVersionSupported(m_context.getRenderContext().getType(), GLSL_VERSION_320_ES))
487     {
488         static const ShaderVariants used_variables_variants[] = {
489             /* These variants should pass since the precision qualifiers match.
490              * These variants require highp to be supported, so will not be run for GLSL_VERSION_100_ES.
491              */
492             {GLSL_VERSION_300_ES, "", "gl_Position = vec4(1.0) + value;", "highp", "result = value;", true},
493             {GLSL_VERSION_300_ES, "highp", "gl_Position = vec4(1.0) + value;", "highp", "result = value;", true},
494 
495             /* Use highp in vertex shaders, mediump in fragment shaders. Check variations as above.
496              * These variants should fail since the precision qualifiers do not match, and matching is done
497              * based on declaration - independent of static use.
498              */
499             {GLSL_VERSION_100_ES, "", "gl_Position = vec4(1.0) + value;", "mediump", "result = value;", false},
500             {GLSL_VERSION_100_ES, "highp", "gl_Position = vec4(1.0) + value;", "mediump", "result = value;", false},
501         };
502         unsigned int used_variables_variants_count = sizeof(used_variables_variants) / sizeof(ShaderVariants);
503 
504         addChild(new ShaderUniformPrecisionLinkCase(
505             m_context, "used_uniform_precision_matching",
506             "Verify that linking fails if precision qualifiers on default uniform do not match",
507             used_variables_variants, used_variables_variants_count, m_glslVersion));
508     }
509 }
510 
511 } // namespace deqp
512