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), m_glslVersion(glslVersion)
60 {
61 }
62
~ShaderUniformInitializeGlobalCase()63 ~ShaderUniformInitializeGlobalCase()
64 {
65 // empty
66 }
67
iterate()68 IterateResult iterate()
69 {
70 qpTestResult result = QP_TEST_RESULT_PASS;
71
72 static const char vertex_source_template[] =
73 "${VERSION_DECL}\n"
74 "precision mediump float;\n"
75 "uniform vec4 nonconstantexpression;\n"
76 "vec4 globalconstant0 = vec4(1.0, 1.0, 1.0, 1.0);\n"
77 "vec4 globalconstant1 = nonconstantexpression;\n"
78 "\n"
79 "void main(void) { gl_Position = globalconstant0+globalconstant1; }\n";
80 static const char fragment_source_template[] = "${VERSION_DECL}\n"
81 "precision mediump float;\n"
82 "uniform vec4 nonconstantexpression;\n"
83 "vec4 globalconstant0 = vec4(1.0, 1.0, 1.0, 1.0);\n"
84 "vec4 globalconstant1 = nonconstantexpression;\n"
85 "\n"
86 "void main(void) { }\n";
87
88 std::map<std::string, std::string> args;
89 args["VERSION_DECL"] = getGLSLVersionDeclaration(m_glslVersion);
90
91 std::string vertex_code = tcu::StringTemplate(vertex_source_template).specialize(args);
92 std::string fragment_code = tcu::StringTemplate(fragment_source_template).specialize(args);
93
94 // Setup program.
95 ShaderProgram program(m_context.getRenderContext(),
96 makeVtxFragSources(vertex_code.c_str(), fragment_code.c_str()));
97
98 // GLSL ES does not allow initialization of global variables with non-constant
99 // expressions, but GLSL does.
100 // Check that either compilation or linking fails for ES, and that everything
101 // succeeds for GL.
102 bool vertexOk = program.getShaderInfo(SHADERTYPE_VERTEX).compileOk;
103 bool fragmentOk = program.getShaderInfo(SHADERTYPE_FRAGMENT).compileOk;
104 bool linkOk = program.getProgramInfo().linkOk;
105
106 if (glslVersionIsES(m_glslVersion))
107 {
108 if (vertexOk && fragmentOk && linkOk)
109 result = QP_TEST_RESULT_FAIL;
110 }
111 else
112 {
113 if (!vertexOk && !fragmentOk && !linkOk)
114 result = QP_TEST_RESULT_FAIL;
115 }
116
117 m_testCtx.setTestResult(result, qpGetTestResultName(result));
118
119 return STOP;
120 }
121
122 protected:
123 GLSLVersion m_glslVersion;
124 };
125
126 class ShaderUniformPrecisionLinkCase : public TestCase
127 {
128 public:
ShaderUniformPrecisionLinkCase(Context & context,const char * name,const char * description,const ShaderVariants * shaderVariants,unsigned int shaderVariantsCount,GLSLVersion glslVersion)129 ShaderUniformPrecisionLinkCase(Context& context, const char* name, const char* description,
130 const ShaderVariants* shaderVariants, unsigned int shaderVariantsCount,
131 GLSLVersion glslVersion)
132 : TestCase(context, name, description)
133 , m_glslVersion(glslVersion)
134 , m_shaderVariants(shaderVariants)
135 , m_shaderVariantsCount(shaderVariantsCount)
136 {
137 }
138
~ShaderUniformPrecisionLinkCase()139 ~ShaderUniformPrecisionLinkCase()
140 {
141 // empty
142 }
143
iterate()144 IterateResult iterate()
145 {
146 TestLog& log = m_testCtx.getLog();
147 qpTestResult result = QP_TEST_RESULT_PASS;
148
149 static const char vertex_source_template[] = "${VERSION_DECL}\n"
150 "uniform ${PREC_QUALIFIER} vec4 value;\n"
151 "\n"
152 "void main(void) { ${BODY} }\n";
153
154 static const char fragment_source_template[] = "${VERSION_DECL}\n"
155 "out highp vec4 result;\n"
156 "uniform ${PREC_QUALIFIER} vec4 value;\n"
157 "\n"
158 "void main(void) { ${BODY} }\n";
159
160 for (unsigned int i = 0; i < m_shaderVariantsCount; i++)
161 {
162 std::map<std::string, std::string> args;
163
164 if (m_glslVersion <= m_shaderVariants[i].minimum_supported_version)
165 {
166 continue;
167 }
168
169 args["VERSION_DECL"] = getGLSLVersionDeclaration(m_glslVersion);
170 args["PREC_QUALIFIER"] = m_shaderVariants[i].vertex_precision;
171 args["BODY"] = m_shaderVariants[i].vertex_body;
172 std::string vcode = tcu::StringTemplate(vertex_source_template).specialize(args);
173
174 args["PREC_QUALIFIER"] = m_shaderVariants[i].frag_precision;
175 args["BODY"] = m_shaderVariants[i].frag_body;
176 std::string fcode = tcu::StringTemplate(fragment_source_template).specialize(args);
177
178 // Setup program.
179 ShaderProgram program(m_context.getRenderContext(), makeVtxFragSources(vcode.c_str(), fcode.c_str()));
180
181 // Check that compile/link results are what we expect.
182 bool vertexOk = program.getShaderInfo(SHADERTYPE_VERTEX).compileOk;
183 bool fragmentOk = program.getShaderInfo(SHADERTYPE_FRAGMENT).compileOk;
184 bool linkOk = program.getProgramInfo().linkOk;
185 const char* failReason = DE_NULL;
186
187 if (!vertexOk || !fragmentOk)
188 {
189 failReason = "expected shaders to compile, but failed.";
190 }
191 else if (m_shaderVariants[i].should_link && !linkOk)
192 {
193 failReason = "expected shaders to link, but failed.";
194 }
195 else if (!m_shaderVariants[i].should_link && linkOk)
196 {
197 failReason = "expected shaders to fail linking, but succeeded.";
198 }
199
200 if (failReason != DE_NULL)
201 {
202 log << TestLog::Message << "ERROR: " << failReason << TestLog::EndMessage;
203 result = QP_TEST_RESULT_FAIL;
204 }
205 }
206
207 m_testCtx.setTestResult(result, qpGetTestResultName(result));
208
209 return STOP;
210 }
211
212 protected:
213 GLSLVersion m_glslVersion;
214 const ShaderVariants* m_shaderVariants;
215 unsigned int m_shaderVariantsCount;
216 };
217
218 class ShaderConstantSequenceExpressionCase : public TestCase
219 {
220 public:
ShaderConstantSequenceExpressionCase(Context & context,const char * name,const char * description,GLSLVersion glslVersion)221 ShaderConstantSequenceExpressionCase(Context& context, const char* name, const char* description,
222 GLSLVersion glslVersion)
223 : TestCase(context, name, description), m_glslVersion(glslVersion)
224 {
225 }
226
~ShaderConstantSequenceExpressionCase()227 ~ShaderConstantSequenceExpressionCase()
228 {
229 // empty
230 }
231
iterate()232 IterateResult iterate()
233 {
234 qpTestResult result = QP_TEST_RESULT_PASS;
235
236 static const char vertex_source_template[] = "${VERSION_DECL}\n"
237 "precision mediump float;\n"
238 "const int test = (1, 2);\n"
239 "\n"
240 "void main(void) { gl_Position = vec4(test); }\n";
241
242 static const char fragment_source_template[] = "${VERSION_DECL}\n"
243 "precision mediump float;\n"
244 "\n"
245 "void main(void) { }\n";
246
247 std::map<std::string, std::string> args;
248 args["VERSION_DECL"] = getGLSLVersionDeclaration(m_glslVersion);
249
250 std::string vertex_code = tcu::StringTemplate(vertex_source_template).specialize(args);
251 std::string fragment_code = tcu::StringTemplate(fragment_source_template).specialize(args);
252
253 // Setup program.
254 ShaderProgram program(m_context.getRenderContext(),
255 makeVtxFragSources(vertex_code.c_str(), fragment_code.c_str()));
256
257 // GLSL does not allow the sequence operator in a constant expression
258 // Check that either compilation or linking fails
259 bool vertexOk = program.getShaderInfo(SHADERTYPE_VERTEX).compileOk;
260 bool fragmentOk = program.getShaderInfo(SHADERTYPE_FRAGMENT).compileOk;
261 bool linkOk = program.getProgramInfo().linkOk;
262
263 bool run_test_es = (glslVersionIsES(m_glslVersion) && m_glslVersion > GLSL_VERSION_100_ES);
264 bool run_test_desktop = (m_glslVersion > GLSL_VERSION_420);
265 if (run_test_es || run_test_desktop)
266 {
267 if (vertexOk && fragmentOk && linkOk)
268 result = QP_TEST_RESULT_FAIL;
269 }
270
271 m_testCtx.setTestResult(result, qpGetTestResultName(result));
272
273 return STOP;
274 }
275
276 protected:
277 GLSLVersion m_glslVersion;
278 };
279
280 class ShaderNonPrecisionQualifiersStructCase : public TestCase
281 {
282 public:
ShaderNonPrecisionQualifiersStructCase(Context & context,const char * name,const char * description,GLSLVersion glslVersion)283 ShaderNonPrecisionQualifiersStructCase(Context& context, const char* name, const char* description,
284 GLSLVersion glslVersion)
285 : TestCase(context, name, description), m_glslVersion(glslVersion)
286 {
287 }
288
~ShaderNonPrecisionQualifiersStructCase()289 ~ShaderNonPrecisionQualifiersStructCase()
290 {
291 // empty
292 }
293
iterate()294 IterateResult iterate()
295 {
296 static const char* qualifier_values[] =
297 {
298 // Storage Qualifiers
299 "const",
300 "in",
301 "out",
302 "attribute",
303 "uniform",
304 "varying",
305 "buffer",
306 "shared",
307
308 // Interpolation Qualifiers
309 "smooth in",
310 "flat in",
311 "noperspective in",
312 "smooth out",
313 "flat out",
314 "noperspective out",
315
316 // Invariant Qualifier
317 "invariant",
318
319 // Precise Qualifier
320 "precise",
321
322 // Memory Qualifiers
323 "coherent",
324 "volatile",
325 "restrict",
326 "readonly",
327 "writeonly",
328 };
329 static const unsigned qualifier_count = sizeof(qualifier_values) / sizeof(qualifier_values[0]);
330
331 static const char* layout_values[] =
332 {
333 "(shared)",
334 "(packed)",
335 "(std140)",
336 "(std430)",
337
338 "(row_major)",
339 "(column_major)",
340 };
341 static const unsigned layout_count = sizeof(layout_values) / sizeof(layout_values[0]);
342
343 const std::string layout_str = "layout";
344
345 std::map<std::string, std::string> args;
346 args["VERSION_DECL"] = getGLSLVersionDeclaration(m_glslVersion);
347
348 // Vertex and fragment shaders
349 {
350 // Layout qualifier test
351 args["QUALIFIER"] = layout_str;
352 for (unsigned i = 0; i < layout_count; ++i)
353 {
354 args["LAYOUT_VALUE"] = layout_values[i];
355 if (testVertexFragment(args, layout_str + layout_values[i]))
356 return STOP;
357 }
358
359 // Remaining qualifier tests
360 args["LAYOUT_VALUE"] = "";
361 for (unsigned i = 0; i < qualifier_count; ++i)
362 {
363 args["QUALIFIER"] = qualifier_values[i];
364 if (testVertexFragment(args, qualifier_values[i]))
365 return STOP;
366 }
367 }
368
369 // Compute shader, not available for GLES2 and GLES3
370 if (!glslVersionIsES(m_glslVersion) || m_glslVersion >= GLSL_VERSION_310_ES)
371 {
372 // Layout qualifier test
373 args["QUALIFIER"] = layout_str;
374 for (unsigned i = 0; i < layout_count; ++i)
375 {
376 args["LAYOUT_VALUE"] = layout_values[i];
377 if (testCompute(args, layout_str + layout_values[i]))
378 return STOP;
379 }
380
381 // Remaining qualifier tests
382 args["LAYOUT_VALUE"] = "";
383 for (unsigned i = 0; i < qualifier_count; ++i)
384 {
385 args["QUALIFIER"] = qualifier_values[i];
386 if (testCompute(args, qualifier_values[i]))
387 return STOP;
388 }
389 }
390
391 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, qpGetTestResultName(QP_TEST_RESULT_PASS));
392
393 return STOP;
394 }
395
396 protected:
testVertexFragment(const std::map<std::string,std::string> & args,const std::string & qualifier_name)397 bool testVertexFragment(const std::map<std::string, std::string>& args, const std::string& qualifier_name)
398 {
399 static const char* vertex_source_template = "${VERSION_DECL}\n"
400 "precision mediump float;\n"
401 "struct Base\n"
402 "{\n"
403 " ${QUALIFIER} ${LAYOUT_VALUE} mat4 some_matrix;\n"
404 "};\n"
405 "\n"
406 "void main(void)\n"
407 "{\n"
408 " gl_Position = vec4(1.0f, 0.0f, 0.0f, 1.0f);\n"
409 "}\n";
410
411 static const char* fragment_source_template = "${VERSION_DECL}\n"
412 "precision mediump float;\n"
413 "struct Base\n"
414 "{\n"
415 " ${QUALIFIER} ${LAYOUT_VALUE} mat4 some_matrix;\n"
416 "};\n"
417 "\n"
418 "void main(void) { }\n";
419
420 std::string vertex_code = tcu::StringTemplate(vertex_source_template).specialize(args);
421 std::string fragment_code = tcu::StringTemplate(fragment_source_template).specialize(args);
422 ShaderProgram program(m_context.getRenderContext(), makeVtxFragSources(vertex_code.c_str(), fragment_code.c_str()));
423 if (program.getShaderInfo(SHADERTYPE_VERTEX).compileOk || program.getShaderInfo(SHADERTYPE_FRAGMENT).compileOk)
424 {
425 m_testCtx.getLog() << TestLog::Message << "ERROR: expected shaders not to compile, but failed with \'"
426 << qualifier_name << "\' qualifier." << TestLog::EndMessage;
427 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, qpGetTestResultName(QP_TEST_RESULT_FAIL));
428 return true;
429 }
430 return false;
431 }
432
testCompute(const std::map<std::string,std::string> & args,const std::string & qualifier_name)433 bool testCompute(const std::map<std::string, std::string>& args, const std::string& qualifier_name)
434 {
435 static const char* compute_source_template = "${VERSION_DECL}\n"
436 "precision mediump float;\n"
437 "struct Base\n"
438 "{\n"
439 " ${QUALIFIER} ${LAYOUT_VALUE} mat4 some_matrix;\n"
440 "};\n"
441 "\n"
442 "void main(void) { }\n";
443
444 std::string compute_code = tcu::StringTemplate(compute_source_template).specialize(args);
445 ProgramSources sources;
446 sources.sources[SHADERTYPE_COMPUTE].emplace_back(compute_code);
447 ShaderProgram program(m_context.getRenderContext(), sources);
448 if (program.getShaderInfo(SHADERTYPE_COMPUTE).compileOk)
449 {
450 m_testCtx.getLog() << TestLog::Message << "ERROR: expected compute shader not to compile, but failed with \'"
451 << qualifier_name << "\' qualifier." << TestLog::EndMessage;
452 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, qpGetTestResultName(QP_TEST_RESULT_FAIL));
453 return true;
454 }
455 return false;
456 }
457
458 GLSLVersion m_glslVersion;
459 };
460
ShaderNegativeTests(Context & context,GLSLVersion glslVersion)461 ShaderNegativeTests::ShaderNegativeTests(Context& context, GLSLVersion glslVersion)
462 : TestCaseGroup(context, "negative", "Shader Negative tests"), 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", "Verify non-precision qualifiers in struct members are not allowed.",
484 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 } // deqp
512