1 /*-------------------------------------------------------------------------
2 * OpenGL Conformance Test Suite
3 * -----------------------------
4 *
5 * Copyright (c) 2014 Intel Corporation
6 * Copyright (c) 2016 The Khronos Group Inc.
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 *
20 */ /*!
21 * \file
22 * \brief
23 */ /*-------------------------------------------------------------------*/
24
25 #include "glcShaderIntegerMixTests.hpp"
26 #include "deMath.h"
27 #include "deRandom.hpp"
28 #include "deString.h"
29 #include "deStringUtil.hpp"
30 #include "gluContextInfo.hpp"
31 #include "gluDrawUtil.hpp"
32 #include "gluPixelTransfer.hpp"
33 #include "gluShaderProgram.hpp"
34 #include "glw.h"
35 #include "glwFunctions.hpp"
36 #include "tcuCommandLine.hpp"
37 #include "tcuStringTemplate.hpp"
38 #include "tcuSurface.hpp"
39 #include "tcuTestLog.hpp"
40
41 namespace deqp
42 {
43
44 using tcu::TestLog;
45
46 class ShaderIntegerMixCase : public TestCase
47 {
48 public:
ShaderIntegerMixCase(Context & context,const char * name,const char * description,glu::GLSLVersion glslVersion)49 ShaderIntegerMixCase(Context &context, const char *name, const char *description, glu::GLSLVersion glslVersion)
50 : TestCase(context, name, description)
51 , m_glslVersion(glslVersion)
52 {
53 }
54
~ShaderIntegerMixCase()55 ~ShaderIntegerMixCase()
56 {
57 // empty
58 }
59
iterate()60 IterateResult iterate()
61 {
62 qpTestResult result = test();
63
64 m_testCtx.setTestResult(result, qpGetTestResultName(result));
65
66 return STOP;
67 }
68
69 protected:
70 glu::GLSLVersion m_glslVersion;
71
72 virtual qpTestResult test() = 0;
73 };
74
75 class ShaderIntegerMixDefineCase : public ShaderIntegerMixCase
76 {
77 public:
ShaderIntegerMixDefineCase(Context & context,const char * name,const char * description,glu::GLSLVersion glslVersion)78 ShaderIntegerMixDefineCase(Context &context, const char *name, const char *description,
79 glu::GLSLVersion glslVersion)
80 : ShaderIntegerMixCase(context, name, description, glslVersion)
81 {
82 // empty
83 }
84
~ShaderIntegerMixDefineCase()85 ~ShaderIntegerMixDefineCase()
86 {
87 // empty
88 }
89
90 protected:
test()91 virtual qpTestResult test()
92 {
93 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
94 bool pass = true;
95
96 static const char source_template[] = "${VERSION_DECL}\n"
97 "#extension GL_EXT_shader_integer_mix: require\n"
98 "\n"
99 "#if !defined GL_EXT_shader_integer_mix\n"
100 "# error GL_EXT_shader_integer_mix is not defined\n"
101 "#elif GL_EXT_shader_integer_mix != 1\n"
102 "# error GL_EXT_shader_integer_mix is not equal to 1\n"
103 "#endif\n"
104 "\n"
105 "void main(void) { ${BODY} }\n";
106
107 static const struct
108 {
109 GLenum target;
110 const char *body;
111 } shader_targets[] = {
112 {GL_VERTEX_SHADER, "gl_Position = vec4(0);"},
113 {GL_FRAGMENT_SHADER, ""},
114 };
115
116 const glu::GLSLVersion v = glslVersionIsES(m_glslVersion) ? glu::GLSL_VERSION_300_ES : glu::GLSL_VERSION_330;
117
118 if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_shader_integer_mix"))
119 return QP_TEST_RESULT_NOT_SUPPORTED;
120
121 for (int i = 0; i < DE_LENGTH_OF_ARRAY(shader_targets); i++)
122 {
123 std::map<std::string, std::string> args;
124
125 args["VERSION_DECL"] = glu::getGLSLVersionDeclaration(v);
126 args["BODY"] = shader_targets[i].body;
127
128 std::string code = tcu::StringTemplate(source_template).specialize(args);
129
130 GLuint shader = gl.createShader(shader_targets[i].target);
131 char const *strings[1] = {code.c_str()};
132 gl.shaderSource(shader, 1, strings, 0);
133 gl.compileShader(shader);
134
135 GLint compileSuccess = 0;
136 gl.getShaderiv(shader, GL_COMPILE_STATUS, &compileSuccess);
137 gl.deleteShader(shader);
138
139 if (!compileSuccess)
140 pass = false;
141 }
142
143 return pass ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL;
144 }
145 };
146
147 class ShaderIntegerMixPrototypesCase : public ShaderIntegerMixCase
148 {
149 public:
ShaderIntegerMixPrototypesCase(Context & context,const char * name,const char * description,glu::GLSLVersion glslVersion,bool _use_extension,bool _is_negative_testing)150 ShaderIntegerMixPrototypesCase(Context &context, const char *name, const char *description,
151 glu::GLSLVersion glslVersion, bool _use_extension, bool _is_negative_testing)
152 : ShaderIntegerMixCase(context, name, description, glslVersion)
153 , use_extension(_use_extension)
154 , is_negative_testing(_is_negative_testing)
155 {
156 // empty
157 }
158
~ShaderIntegerMixPrototypesCase()159 ~ShaderIntegerMixPrototypesCase()
160 {
161 // empty
162 }
163
164 protected:
165 bool use_extension;
166 bool is_negative_testing;
167
test()168 virtual qpTestResult test()
169 {
170 TestLog &log = m_testCtx.getLog();
171 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
172 bool pass = true;
173
174 static const char source_template[] = "${VERSION_DECL}\n"
175 "${EXTENSION_ENABLE}\n"
176 "\n"
177 "void main()\n"
178 "{\n"
179 " mix(ivec2(1), ivec2(2), bvec2(true));\n"
180 " mix(ivec3(1), ivec3(2), bvec3(true));\n"
181 " mix(ivec4(1), ivec4(2), bvec4(true));\n"
182 " mix(uvec2(1), uvec2(2), bvec2(true));\n"
183 " mix(uvec3(1), uvec3(2), bvec3(true));\n"
184 " mix(uvec4(1), uvec4(2), bvec4(true));\n"
185 " mix(bvec2(1), bvec2(0), bvec2(true));\n"
186 " mix(bvec3(1), bvec3(0), bvec3(true));\n"
187 " mix(bvec4(1), bvec4(0), bvec4(true));\n"
188 " ${BODY}\n"
189 "}\n";
190
191 static const struct
192 {
193 GLenum target;
194 const char *body;
195 } shader_targets[] = {
196 {GL_VERTEX_SHADER, "gl_Position = vec4(0);"},
197 {GL_FRAGMENT_SHADER, ""},
198 };
199
200 glu::GLSLVersion v;
201 const char *extension_enable;
202
203 if (use_extension)
204 {
205 v = glslVersionIsES(m_glslVersion) ? glu::GLSL_VERSION_300_ES : glu::GLSL_VERSION_330;
206 extension_enable = "#extension GL_EXT_shader_integer_mix: enable";
207
208 if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_shader_integer_mix"))
209 return QP_TEST_RESULT_NOT_SUPPORTED;
210 }
211 else if (is_negative_testing)
212 {
213 v = glslVersionIsES(m_glslVersion) ? glu::GLSL_VERSION_300_ES : glu::GLSL_VERSION_330;
214 extension_enable = "";
215 }
216 else
217 {
218 v = m_glslVersion;
219 extension_enable = "";
220 if (glslVersionIsES(m_glslVersion))
221 {
222 if (m_glslVersion < glu::GLSL_VERSION_310_ES)
223 return QP_TEST_RESULT_NOT_SUPPORTED;
224 }
225 else
226 {
227 if (m_glslVersion < glu::GLSL_VERSION_450)
228 return QP_TEST_RESULT_NOT_SUPPORTED;
229 }
230 }
231
232 for (int i = 0; i < DE_LENGTH_OF_ARRAY(shader_targets); i++)
233 {
234 std::map<std::string, std::string> args;
235
236 args["VERSION_DECL"] = glu::getGLSLVersionDeclaration(v);
237 args["EXTENSION_ENABLE"] = extension_enable;
238 args["BODY"] = shader_targets[i].body;
239
240 std::string code = tcu::StringTemplate(source_template).specialize(args);
241
242 GLuint shader = gl.createShader(shader_targets[i].target);
243 char const *strings[1] = {code.c_str()};
244 gl.shaderSource(shader, 1, strings, 0);
245 gl.compileShader(shader);
246
247 GLint compileSuccess = 0;
248 gl.getShaderiv(shader, GL_COMPILE_STATUS, &compileSuccess);
249
250 if (is_negative_testing)
251 {
252 if (compileSuccess)
253 {
254 TCU_FAIL("The shader compilation was expected to fail, but it was successful.");
255 pass = false;
256 }
257 }
258 else if (!compileSuccess)
259 {
260 GLchar infoLog[1000];
261
262 gl.getShaderInfoLog(shader, sizeof(infoLog), NULL, infoLog);
263 log.writeKernelSource(strings[0]);
264 log.writeCompileInfo("shader", "", false, infoLog);
265
266 pass = false;
267 }
268
269 gl.deleteShader(shader);
270 }
271
272 return pass ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL;
273 }
274 };
275
276 class ShaderIntegerMixRenderCase : public ShaderIntegerMixCase
277 {
278 public:
ShaderIntegerMixRenderCase(Context & context,const char * name,const char * description,glu::GLSLVersion glslVersion,const char * _type)279 ShaderIntegerMixRenderCase(Context &context, const char *name, const char *description,
280 glu::GLSLVersion glslVersion, const char *_type)
281 : ShaderIntegerMixCase(context, name, description, glslVersion)
282 , type(_type)
283 {
284 // empty
285 }
286
~ShaderIntegerMixRenderCase()287 ~ShaderIntegerMixRenderCase()
288 {
289 // empty
290 }
291
292 protected:
293 // Type used for mix() parameters in this test case.
294 const char *type;
295
296 static const unsigned width = 8 * 8;
297 static const unsigned height = 8 * 8;
298
test()299 virtual qpTestResult test()
300 {
301 static const char vs_template[] = "${VERSION_DECL}\n"
302 "${EXTENSION_ENABLE}\n"
303 "\n"
304 "in vec2 vertex;\n"
305 "in ivec4 vs_in_a;\n"
306 "in ivec4 vs_in_b;\n"
307 "in ivec4 vs_in_sel;\n"
308 "\n"
309 "flat out ivec4 fs_in_a;\n"
310 "flat out ivec4 fs_in_b;\n"
311 "flat out ivec4 fs_in_sel;\n"
312 "flat out ivec4 fs_in_result;\n"
313 "\n"
314 "void main()\n"
315 "{\n"
316 " fs_in_a = vs_in_a;\n"
317 " fs_in_b = vs_in_b;\n"
318 " fs_in_sel = vs_in_sel;\n"
319 "\n"
320 " ${TYPE} a = ${TYPE}(vs_in_a);\n"
321 " ${TYPE} b = ${TYPE}(vs_in_b);\n"
322 " bvec4 sel = bvec4(vs_in_sel);\n"
323 " fs_in_result = ivec4(mix(a, b, sel));\n"
324 "\n"
325 " gl_Position = vec4(vertex, 0, 1);\n"
326 " gl_PointSize = 4.;\n"
327 "}\n";
328
329 static const char fs_template[] = "${VERSION_DECL}\n"
330 "${EXTENSION_ENABLE}\n"
331 "\n"
332 "out ivec4 o;\n"
333 "\n"
334 "flat in ivec4 fs_in_a;\n"
335 "flat in ivec4 fs_in_b;\n"
336 "flat in ivec4 fs_in_sel;\n"
337 "flat in ivec4 fs_in_result;\n"
338 "\n"
339 "uniform bool use_vs_data;\n"
340 "\n"
341 "void main()\n"
342 "{\n"
343 " if (use_vs_data)\n"
344 " o = fs_in_result;\n"
345 " else {\n"
346 " ${TYPE} a = ${TYPE}(fs_in_a);\n"
347 " ${TYPE} b = ${TYPE}(fs_in_b);\n"
348 " bvec4 sel = bvec4(fs_in_sel);\n"
349 " o = ivec4(mix(a, b, sel));\n"
350 " }\n"
351 "}\n";
352
353 TestLog &log = m_testCtx.getLog();
354 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
355 bool pass = true;
356 const char *extension_enable;
357 bool is_es = glslVersionIsES(m_glslVersion);
358
359 if ((is_es && (m_glslVersion < glu::GLSL_VERSION_310_ES)) || !is_es)
360 {
361 /* For versions that do not support this feature in Core it must be exposed via an extension. */
362 if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_shader_integer_mix"))
363 {
364 return QP_TEST_RESULT_NOT_SUPPORTED;
365 }
366
367 extension_enable = "#extension GL_EXT_shader_integer_mix: enable";
368 }
369 else
370 {
371 extension_enable = "";
372 }
373
374 /* Generate the specialization of the shader for the specific
375 * type being tested.
376 */
377 std::map<std::string, std::string> args;
378
379 args["VERSION_DECL"] = glu::getGLSLVersionDeclaration(m_glslVersion);
380 args["EXTENSION_ENABLE"] = extension_enable;
381 args["TYPE"] = type;
382
383 std::string vs_code = tcu::StringTemplate(vs_template).specialize(args);
384
385 std::string fs_code = tcu::StringTemplate(fs_template).specialize(args);
386
387 glu::ShaderProgram prog(m_context.getRenderContext(),
388 glu::makeVtxFragSources(vs_code.c_str(), fs_code.c_str()));
389
390 if (!prog.isOk())
391 {
392 log << prog;
393 TCU_FAIL("Compile failed");
394 }
395
396 if (!glslVersionIsES(m_glslVersion))
397 glEnable(GL_PROGRAM_POINT_SIZE);
398
399 /* Generate an integer FBO for rendering.
400 */
401 GLuint fbo;
402 GLuint tex;
403
404 glGenTextures(1, &tex);
405 glBindTexture(GL_TEXTURE_2D, tex);
406 glTexImage2D(GL_TEXTURE_2D, 0 /* level */, GL_RGBA32I, width, height, 0 /* border */, GL_RGBA_INTEGER, GL_INT,
407 NULL /* data */);
408 glBindTexture(GL_TEXTURE_2D, 0);
409
410 glGenFramebuffers(1, &fbo);
411 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
412 glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
413 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0 /* level */);
414
415 GLU_EXPECT_NO_ERROR(gl.getError(), "Creation of rendering FBO failed.");
416
417 if (glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
418 TCU_FAIL("Framebuffer not complete.");
419
420 glViewport(0, 0, width, height);
421
422 /* Fill a VBO with some vertex data.
423 */
424 uint32_t pointIndices[256];
425 float vertex[DE_LENGTH_OF_ARRAY(pointIndices) * 2];
426 int32_t a[DE_LENGTH_OF_ARRAY(pointIndices) * 4];
427 int32_t b[DE_LENGTH_OF_ARRAY(a)];
428 int32_t sel[DE_LENGTH_OF_ARRAY(a)];
429 tcu::IVec4 expected[DE_LENGTH_OF_ARRAY(pointIndices)];
430
431 for (int i = 0; i < DE_LENGTH_OF_ARRAY(pointIndices); i++)
432 {
433 pointIndices[i] = uint16_t(i);
434
435 const int x = (i / 16) * (width / 16) + (4 / 2);
436 const int y = (i % 16) * (height / 16) + (4 / 2);
437
438 vertex[(i * 2) + 0] = float(x) * 2.0f / float(width) - 1.0f;
439 vertex[(i * 2) + 1] = float(y) * 2.0f / float(height) - 1.0f;
440
441 a[(i * 4) + 0] = i;
442 a[(i * 4) + 1] = i * 5;
443 a[(i * 4) + 2] = i * 7;
444 a[(i * 4) + 3] = i * 11;
445
446 b[(i * 4) + 0] = ~a[(i * 4) + 3];
447 b[(i * 4) + 1] = ~a[(i * 4) + 2];
448 b[(i * 4) + 2] = ~a[(i * 4) + 1];
449 b[(i * 4) + 3] = ~a[(i * 4) + 0];
450
451 sel[(i * 4) + 0] = (i >> 0) & 1;
452 sel[(i * 4) + 1] = (i >> 1) & 1;
453 sel[(i * 4) + 2] = (i >> 2) & 1;
454 sel[(i * 4) + 3] = (i >> 3) & 1;
455
456 expected[i] = tcu::IVec4(
457 sel[(i * 4) + 0] ? b[(i * 4) + 0] : a[(i * 4) + 0], sel[(i * 4) + 1] ? b[(i * 4) + 1] : a[(i * 4) + 1],
458 sel[(i * 4) + 2] ? b[(i * 4) + 2] : a[(i * 4) + 2], sel[(i * 4) + 3] ? b[(i * 4) + 3] : a[(i * 4) + 3]);
459 }
460
461 /* Mask off all but the least significant bit for boolean
462 * types.
463 */
464 if (type[0] == 'b')
465 {
466 for (int i = 0; i < DE_LENGTH_OF_ARRAY(a); i++)
467 {
468 a[i] &= 1;
469 b[i] &= 1;
470
471 expected[i / 4][0] &= 1;
472 expected[i / 4][1] &= 1;
473 expected[i / 4][2] &= 1;
474 expected[i / 4][3] &= 1;
475 }
476 }
477
478 glu::VertexArrayBinding vertexArrays[] = {
479 glu::va::Float("vertex", 2, DE_LENGTH_OF_ARRAY(pointIndices), 0, vertex),
480 glu::va::Int32("vs_in_a", 4, DE_LENGTH_OF_ARRAY(pointIndices), 0, a),
481 glu::va::Int32("vs_in_b", 4, DE_LENGTH_OF_ARRAY(pointIndices), 0, b),
482 glu::va::Int32("vs_in_sel", 4, DE_LENGTH_OF_ARRAY(pointIndices), 0, sel)};
483
484 /* Render and verify the results. Rendering happens twice.
485 * The first time, use_vs_data is false, and the mix() result
486 * from the fragment shader is used. The second time,
487 * use_vs_data is true, and the mix() result from the vertex
488 * shader is used.
489 */
490 const GLint loc = gl.getUniformLocation(prog.getProgram(), "use_vs_data");
491 gl.useProgram(prog.getProgram());
492
493 static const GLint clear[] = {1, 2, 3, 4};
494 glClearBufferiv(GL_COLOR, 0, clear);
495
496 gl.uniform1i(loc, 0);
497 glu::draw(m_context.getRenderContext(), prog.getProgram(), DE_LENGTH_OF_ARRAY(vertexArrays), vertexArrays,
498 glu::pr::Points(DE_LENGTH_OF_ARRAY(pointIndices), pointIndices));
499
500 for (int i = 0; i < DE_LENGTH_OF_ARRAY(pointIndices); i++)
501 {
502 const int x = int((vertex[(i * 2) + 0] + 1.0f) * float(width) / 2.0f);
503 const int y = int((vertex[(i * 2) + 1] + 1.0f) * float(height) / 2.0f);
504
505 pass = probe_pixel(log, "Fragment", x, y, expected[i]) && pass;
506 }
507
508 gl.uniform1i(loc, 1);
509 glu::draw(m_context.getRenderContext(), prog.getProgram(), DE_LENGTH_OF_ARRAY(vertexArrays), vertexArrays,
510 glu::pr::Points(DE_LENGTH_OF_ARRAY(pointIndices), pointIndices));
511
512 for (int i = 0; i < DE_LENGTH_OF_ARRAY(pointIndices); i++)
513 {
514 const int x = int((vertex[(i * 2) + 0] + 1.0f) * float(width) / 2.0f);
515 const int y = int((vertex[(i * 2) + 1] + 1.0f) * float(height) / 2.0f);
516
517 pass = probe_pixel(log, "Vertex", x, y, expected[i]) && pass;
518 }
519
520 glDeleteFramebuffers(1, &fbo);
521 glDeleteTextures(1, &tex);
522
523 return pass ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL;
524 }
525
probe_pixel(TestLog & log,const char * stage,int x,int y,const tcu::IVec4 & expected)526 bool probe_pixel(TestLog &log, const char *stage, int x, int y, const tcu::IVec4 &expected)
527 {
528 tcu::IVec4 pixel;
529
530 glReadPixels(x, y, 1, 1, GL_RGBA_INTEGER, GL_INT, &pixel);
531
532 if (expected != pixel)
533 {
534 log << TestLog::Message << stage << " shader failed at pixel (" << x << ", " << y << "). "
535 << "Got " << pixel << ", expected " << expected << ")." << TestLog::EndMessage;
536 return false;
537 }
538
539 return true;
540 }
541 };
542
ShaderIntegerMixTests(Context & context,glu::GLSLVersion glslVersion)543 ShaderIntegerMixTests::ShaderIntegerMixTests(Context &context, glu::GLSLVersion glslVersion)
544 : TestCaseGroup(context, "shader_integer_mix", "Shader Integer Mix tests")
545 , m_glslVersion(glslVersion)
546 {
547 // empty
548 }
549
~ShaderIntegerMixTests()550 ShaderIntegerMixTests::~ShaderIntegerMixTests()
551 {
552 // empty
553 }
554
init(void)555 void ShaderIntegerMixTests::init(void)
556 {
557 addChild(new ShaderIntegerMixDefineCase(m_context, "define", "Verify GL_EXT_shader_integer_mix is defined to 1.",
558 m_glslVersion));
559 addChild(new ShaderIntegerMixPrototypesCase(m_context, "prototypes-extension",
560 "Verify availability of all function signatures with the extension.",
561 m_glslVersion, true, false));
562 addChild(new ShaderIntegerMixPrototypesCase(
563 m_context, "prototypes", "Verify availability of all function signatures with the proper GLSL version.",
564 m_glslVersion, false, false));
565 addChild(new ShaderIntegerMixPrototypesCase(
566 m_context, "prototypes-negative",
567 "Verify compilation fails if the GLSL version does not support shader_integer_mix", m_glslVersion, false,
568 true));
569
570 static const char *types_to_test[] = {"ivec4", "uvec4", "bvec4"};
571
572 for (int i = 0; i < DE_LENGTH_OF_ARRAY(types_to_test); i++)
573 {
574 std::stringstream name;
575
576 name << "mix-" << types_to_test[i];
577
578 std::stringstream description;
579
580 description << "Verify functionality of mix() with " << types_to_test[i] << " parameters.";
581
582 addChild(new ShaderIntegerMixRenderCase(m_context, name.str().c_str(), description.str().c_str(), m_glslVersion,
583 types_to_test[i]));
584 }
585 }
586
587 } // namespace deqp
588