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