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