1 /*-------------------------------------------------------------------------
2 * OpenGL Conformance Test Suite
3 * -----------------------------
4 *
5 * Copyright (c) 2014-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 #include "esextcTessellationShaderTriangles.hpp"
25 #include "gluContextInfo.hpp"
26 #include "gluDefs.hpp"
27 #include "glwEnums.hpp"
28 #include "glwFunctions.hpp"
29 #include "tcuTestLog.hpp"
30
31 namespace glcts
32 {
33
34 /** Constructor
35 *
36 * @param context Test context
37 **/
TessellationShaderTrianglesTests(glcts::Context & context,const ExtParameters & extParams)38 TessellationShaderTrianglesTests::TessellationShaderTrianglesTests(glcts::Context &context,
39 const ExtParameters &extParams)
40 : TestCaseGroupBase(context, extParams, "tessellation_shader_triangles_tessellation",
41 "Verifies triangle tessellation functionality")
42 {
43 /* No implementation needed */
44 }
45
46 /**
47 * Initializes test groups for geometry shader tests
48 **/
init(void)49 void TessellationShaderTrianglesTests::init(void)
50 {
51 addChild(new glcts::TessellationShaderTrianglesDegenerateTriangle(m_context, m_extParams));
52 addChild(new glcts::TessellationShaderTrianglesIdenticalTriangles(m_context, m_extParams));
53 addChild(new glcts::TessellationShaderTrianglesInnerTessellationLevelRounding(m_context, m_extParams));
54 }
55
56 /** Constructor
57 *
58 * @param context Test context
59 **/
TessellationShaderTrianglesDegenerateTriangle(Context & context,const ExtParameters & extParams)60 TessellationShaderTrianglesDegenerateTriangle::TessellationShaderTrianglesDegenerateTriangle(
61 Context &context, const ExtParameters &extParams)
62 : TestCaseBase(context, extParams, "degenerate_triangle",
63 "Verifies a degenerate triangle is generated by tessellator "
64 "under a specific configuration of inner/outer tessellation "
65 "levels & vertex spacing modes.")
66 , m_bo_id(0)
67 , m_fs_id(0)
68 , m_tc_id(0)
69 , m_vs_id(0)
70 , m_vao_id(0)
71 {
72 /* Left blank on purpose */
73 }
74
75 /** Deinitializes ES objects created for the test. */
deinit()76 void TessellationShaderTrianglesDegenerateTriangle::deinit()
77 {
78 /* Call base class' deinit() */
79 TestCaseBase::deinit();
80
81 if (!m_is_tessellation_shader_supported)
82 {
83 return;
84 }
85
86 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
87
88 /* Deinitialize TF buffer object bindings */
89 gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* buffer */);
90 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, 0 /* buffer */);
91
92 /* Reset GL_PATCH_VERTICES_EXT value */
93 gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 3);
94
95 /* Unbind vertex array object */
96 gl.bindVertexArray(0);
97
98 /* Free all ES objects we allocated for the test */
99 if (m_bo_id != 0)
100 {
101 gl.deleteBuffers(1, &m_bo_id);
102
103 m_bo_id = 0;
104 }
105
106 if (m_fs_id != 0)
107 {
108 gl.deleteShader(m_fs_id);
109
110 m_fs_id = 0;
111 }
112
113 if (m_tc_id != 0)
114 {
115 gl.deleteShader(m_tc_id);
116
117 m_tc_id = 0;
118 }
119
120 if (m_vs_id != 0)
121 {
122 gl.deleteShader(m_vs_id);
123
124 m_vs_id = 0;
125 }
126
127 if (m_vao_id != 0)
128 {
129 gl.deleteVertexArrays(1, &m_vao_id);
130
131 m_vao_id = 0;
132 }
133
134 /* Deinitialize all test descriptors */
135 for (_tests::iterator it = m_tests.begin(); it != m_tests.end(); ++it)
136 {
137 deinitTestDescriptor(*it);
138 }
139 m_tests.clear();
140 }
141
142 /** Deinitialize all test pass-specific ES objects.
143 *
144 * @param test Descriptor of a test pass to deinitialize.
145 **/
deinitTestDescriptor(_test_descriptor & test)146 void TessellationShaderTrianglesDegenerateTriangle::deinitTestDescriptor(_test_descriptor &test)
147 {
148 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
149
150 if (test.po_id != 0)
151 {
152 gl.deleteProgram(test.po_id);
153
154 test.po_id = 0;
155 }
156
157 if (test.te_id != 0)
158 {
159 gl.deleteShader(test.te_id);
160
161 test.te_id = 0;
162 }
163 }
164
165 /** Initializes ES objects necessary to run the test. */
initTest()166 void TessellationShaderTrianglesDegenerateTriangle::initTest()
167 {
168 /* Skip if required extensions are not supported. */
169 if (!m_is_tessellation_shader_supported)
170 {
171 throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
172 }
173
174 /* Generate all test-wide objects needed for test execution */
175 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
176
177 gl.genVertexArrays(1, &m_vao_id);
178 GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object");
179
180 gl.bindVertexArray(m_vao_id);
181 GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!");
182
183 gl.genBuffers(1, &m_bo_id);
184 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() failed");
185
186 m_fs_id = gl.createShader(GL_FRAGMENT_SHADER);
187 m_tc_id = gl.createShader(m_glExtTokens.TESS_CONTROL_SHADER);
188 m_vs_id = gl.createShader(GL_VERTEX_SHADER);
189 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() failed");
190
191 /* Configure fragment shader body */
192 const char *fs_body = "${VERSION}\n"
193 "\n"
194 "void main()\n"
195 "{\n"
196 "}\n";
197
198 shaderSourceSpecialized(m_fs_id, 1 /* count */, &fs_body);
199 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for fragment shader");
200
201 /* Configure tessellation control shader body */
202 const char *tc_body = "${VERSION}\n"
203 "\n"
204 "${TESSELLATION_SHADER_REQUIRE}\n"
205 "\n"
206 "layout (vertices=3) out;\n"
207 "\n"
208 "void main()\n"
209 "{\n"
210 " gl_out [gl_InvocationID].gl_Position = gl_in[0].gl_Position;\n"
211 "\n"
212 " gl_TessLevelInner[0] = 1.0;\n"
213 " gl_TessLevelOuter[0] = 1.0;\n"
214 " gl_TessLevelOuter[1] = 1.0;\n"
215 " gl_TessLevelOuter[2] = 1.0;\n"
216 "}\n";
217
218 shaderSourceSpecialized(m_tc_id, 1 /* count */, &tc_body);
219 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for tessellation control shader");
220
221 /* Configure vertex shader body */
222 const char *vs_body = "${VERSION}\n"
223 "\n"
224 "void main()\n"
225 "{\n"
226 " gl_Position = vec4(1.0, 0.0, 0.0, 1.0);\n"
227 "}\n";
228
229 shaderSourceSpecialized(m_vs_id, 1 /* count */, &vs_body);
230 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for vertex shader");
231
232 /* Compile all the shaders */
233 const glw::GLuint shaders[] = {m_fs_id, m_tc_id, m_vs_id};
234 const unsigned int n_shaders = sizeof(shaders) / sizeof(shaders[0]);
235
236 for (unsigned int n_shader = 0; n_shader < n_shaders; ++n_shader)
237 {
238 glw::GLuint shader = shaders[n_shader];
239
240 if (shader != 0)
241 {
242 glw::GLint compile_status = GL_FALSE;
243
244 gl.compileShader(shader);
245 GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() failed");
246
247 gl.getShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
248 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() failed");
249
250 if (compile_status != GL_TRUE)
251 {
252 TCU_FAIL("Shader compilation failed");
253 }
254 }
255 } /* for (all shaders) */
256
257 /* Initialize all test passes */
258 _test_descriptor test_equal_spacing;
259 _test_descriptor test_fractional_odd_spacing;
260
261 initTestDescriptor(test_equal_spacing, TESSELLATION_SHADER_VERTEX_SPACING_EQUAL);
262 initTestDescriptor(test_fractional_odd_spacing, TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD);
263
264 m_tests.push_back(test_equal_spacing);
265 m_tests.push_back(test_fractional_odd_spacing);
266
267 /* Set up buffer object storage */
268 gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id);
269 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() failed");
270
271 gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(float) * 3 /* components */ * 3 /* UVW sets */, NULL, /* data */
272 GL_STATIC_DRAW);
273 GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() failed");
274
275 /* Bind the buffer object to indiced TF binding point */
276 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, m_bo_id);
277 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() failed");
278 }
279
280 /** Initializes all ES objects necessary to run a specific test pass.
281 *
282 * @param test Test descriptor to fill with IDs of initialized objects.
283 * @param vertex_spacing Vertex spacing mode to use for the run.
284 **/
initTestDescriptor(_test_descriptor & test,_tessellation_shader_vertex_spacing vertex_spacing)285 void TessellationShaderTrianglesDegenerateTriangle::initTestDescriptor(
286 _test_descriptor &test, _tessellation_shader_vertex_spacing vertex_spacing)
287 {
288 test.vertex_spacing = vertex_spacing;
289
290 /* Set up a program object for the descriptor */
291 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
292
293 test.po_id = gl.createProgram();
294 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() failed");
295
296 /* Set up a pass-specific tessellation evaluation shader object. */
297 test.te_id = gl.createShader(m_glExtTokens.TESS_EVALUATION_SHADER);
298 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() failed");
299
300 /* Configure tessellation evaluation shader body */
301 const char *te_template = "${VERSION}\n"
302 "\n"
303 "${TESSELLATION_SHADER_REQUIRE}\n"
304 "\n"
305 "layout (triangles, VERTEX_SPACING_MODE) in;\n"
306 "\n"
307 "out vec3 result_uvw;\n"
308 "\n"
309 "void main()\n"
310 "{\n"
311 " gl_Position = gl_in[0].gl_Position;\n"
312 " result_uvw = gl_TessCoord;\n"
313 "}\n";
314
315 const char *te_body_raw_ptr = DE_NULL;
316 std::string te_body_string = te_template;
317 std::string vertex_spacing_mode_string;
318 const char *vertex_spacing_token = "VERTEX_SPACING_MODE";
319 std::size_t vertex_spacing_token_index = std::string::npos;
320
321 switch (vertex_spacing)
322 {
323 case TESSELLATION_SHADER_VERTEX_SPACING_EQUAL:
324 {
325 vertex_spacing_mode_string = "equal_spacing";
326
327 break;
328 }
329
330 case TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD:
331 {
332 vertex_spacing_mode_string = "fractional_odd_spacing";
333
334 break;
335 }
336
337 default:
338 {
339 TCU_FAIL("Invalid vertex spacing mode requested");
340 }
341 }
342
343 while ((vertex_spacing_token_index = te_body_string.find(vertex_spacing_token)) != std::string::npos)
344 {
345 te_body_string = te_body_string.replace(vertex_spacing_token_index, strlen(vertex_spacing_token),
346 vertex_spacing_mode_string);
347
348 vertex_spacing_token_index = te_body_string.find(vertex_spacing_token);
349 }
350
351 te_body_raw_ptr = te_body_string.c_str();
352
353 shaderSourceSpecialized(test.te_id, 1 /* count */, &te_body_raw_ptr);
354 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for tessellation evaluation shader");
355
356 /* Compile the tessellation evaluation shader */
357 glw::GLint compile_status = GL_FALSE;
358
359 gl.compileShader(test.te_id);
360 GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() failed for tessellation evaluation shader");
361
362 gl.getShaderiv(test.te_id, GL_COMPILE_STATUS, &compile_status);
363 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() failed for tessellation evaluation shader");
364
365 if (compile_status != GL_TRUE)
366 {
367 TCU_FAIL("Tessellation evaluation shader compilation failed");
368 }
369
370 /* Attach all shader to the program object */
371 gl.attachShader(test.po_id, m_fs_id);
372 gl.attachShader(test.po_id, m_tc_id);
373 gl.attachShader(test.po_id, test.te_id);
374 gl.attachShader(test.po_id, m_vs_id);
375 GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() failed");
376
377 /* Set up XFB */
378 const char *varyings[] = {"result_uvw"};
379 const unsigned int n_varyings = sizeof(varyings) / sizeof(varyings[0]);
380
381 gl.transformFeedbackVaryings(test.po_id, n_varyings, varyings, GL_INTERLEAVED_ATTRIBS);
382 GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() failed");
383
384 /* Link the program object */
385 glw::GLint link_status = GL_FALSE;
386
387 gl.linkProgram(test.po_id);
388 GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() failed");
389
390 gl.getProgramiv(test.po_id, GL_LINK_STATUS, &link_status);
391 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() failed");
392
393 if (link_status != GL_TRUE)
394 {
395 TCU_FAIL("Program linking failed");
396 }
397 }
398
399 /** Executes the test.
400 *
401 * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
402 *
403 * Note the function throws exception should an error occur!
404 *
405 * @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again.
406 **/
iterate(void)407 tcu::TestNode::IterateResult TessellationShaderTrianglesDegenerateTriangle::iterate(void)
408 {
409 /* Do not execute if required extensions are not supported. */
410 if (!m_is_tessellation_shader_supported)
411 {
412 throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
413 }
414
415 /* Initialize ES test objects */
416 initTest();
417
418 /* We only need to use one vertex per so go for it */
419 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
420
421 gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 1);
422 GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteriEXT() failed for GL_PATCH_VERTICES_EXT pname");
423
424 /* Iterate through all tests configured */
425 for (_tests_const_iterator test_iterator = m_tests.begin(); test_iterator != m_tests.end(); test_iterator++)
426 {
427 const _test_descriptor &test = *test_iterator;
428
429 /* Run the iteration */
430 gl.useProgram(test.po_id);
431 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() failed");
432
433 /* Draw the test geometry */
434 gl.beginTransformFeedback(GL_TRIANGLES);
435 GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback(GL_TRIANGLES) failed.");
436
437 gl.drawArrays(m_glExtTokens.PATCHES, 0 /* first */, 1 /* count */);
438 GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() failed");
439
440 gl.endTransformFeedback();
441 GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() failed");
442
443 /* Map the BO with result data into user space */
444 const float *triangle_vertex_data =
445 (const float *)gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* offset */
446 sizeof(float) * 3 /* vec3 */ * 3 /* points */, GL_MAP_READ_BIT);
447
448 GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() call failed");
449
450 /* Make sure the triangle data is correct. Since we cannot rely on any specific order
451 * of the result vertices, raise corresponding flag for each of the expected vertices.
452 */
453 const float epsilon = 1e-5f;
454 bool is_zero_zero_one_present = false;
455 bool is_zero_one_zero_present = false;
456 bool is_one_zero_zero_present = false;
457
458 for (unsigned int n_vertex = 0; n_vertex < 3 /* vertices */; ++n_vertex)
459 {
460 const float *triangle_ptr = triangle_vertex_data + 3 * n_vertex;
461
462 if (de::abs(triangle_ptr[0]) < epsilon && de::abs(triangle_ptr[1]) < epsilon &&
463 de::abs(triangle_ptr[2] - 1.0f) < epsilon)
464 {
465 if (!is_zero_zero_one_present)
466 {
467 is_zero_zero_one_present = true;
468 }
469 else
470 {
471 TCU_FAIL("(0, 0, 1) vertex outputted more than once");
472 }
473 }
474 else if (de::abs(triangle_ptr[0]) < epsilon && de::abs(triangle_ptr[1] - 1.0f) < epsilon &&
475 de::abs(triangle_ptr[2]) < epsilon)
476 {
477 if (!is_zero_one_zero_present)
478 {
479 is_zero_one_zero_present = true;
480 }
481 else
482 {
483 TCU_FAIL("(0, 1, 0) vertex outputted more than once");
484 }
485 }
486 else if (de::abs(triangle_ptr[0] - 1.0f) < epsilon && de::abs(triangle_ptr[1]) < epsilon &&
487 de::abs(triangle_ptr[2]) < epsilon)
488 {
489 if (!is_one_zero_zero_present)
490 {
491 is_one_zero_zero_present = true;
492 }
493 else
494 {
495 TCU_FAIL("(1, 0, 0) vertex outputted more than once");
496 }
497 }
498 else
499 {
500 m_testCtx.getLog() << tcu::TestLog::Message << "Unexpected vertex"
501 << " (" << triangle_vertex_data[0] << ", " << triangle_vertex_data[1] << ", "
502 << triangle_vertex_data[2] << ")"
503 << " encountered for a degenerate triangle." << tcu::TestLog::EndMessage;
504
505 TCU_FAIL("Invalid vertex was generated by the tessellator");
506 }
507 } /* for (all vertices) */
508
509 /* Unmap the BO */
510 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
511 GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed");
512 }
513
514 /* All done */
515 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
516 return STOP;
517 }
518
519 /** Constructor
520 *
521 * @param context Test context
522 **/
TessellationShaderTrianglesIdenticalTriangles(Context & context,const ExtParameters & extParams)523 TessellationShaderTrianglesIdenticalTriangles::TessellationShaderTrianglesIdenticalTriangles(
524 Context &context, const ExtParameters &extParams)
525 : TestCaseBase(context, extParams, "identical_triangles",
526 "Verifies that tessellation coordinates generated by the tessellator "
527 "running in triangles mode do not change if second inner or fourth "
528 "outer tessellation level is changed")
529 , m_vao_id(0)
530 , m_utils(DE_NULL)
531 {
532 /* Left blank on purpose */
533 }
534
535 /** Deinitializes ES objects created for the test. */
deinit()536 void TessellationShaderTrianglesIdenticalTriangles::deinit()
537 {
538 /* Call base class' deinit() */
539 TestCaseBase::deinit();
540
541 if (!m_is_tessellation_shader_supported)
542 {
543 return;
544 }
545
546 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
547
548 /* Unbind vertex array object */
549 gl.bindVertexArray(0);
550
551 /* Deallocate test variables */
552 if (m_vao_id != 0)
553 {
554 gl.deleteVertexArrays(1, &m_vao_id);
555
556 m_vao_id = 0;
557 }
558
559 /* Deinitialize utils instance */
560 if (m_utils != DE_NULL)
561 {
562 delete m_utils;
563
564 m_utils = DE_NULL;
565 }
566 }
567
568 /** Initializes ES objects necessary to run the test. */
initTest()569 void TessellationShaderTrianglesIdenticalTriangles::initTest()
570 {
571 /* Skip if required extensions are not supported. */
572 if (!m_is_tessellation_shader_supported)
573 {
574 throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
575 }
576
577 /* Initialize Utils instance */
578 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
579
580 m_utils = new TessellationShaderUtils(gl, this);
581
582 /* Initialize vertex array object */
583 gl.genVertexArrays(1, &m_vao_id);
584 GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object");
585
586 gl.bindVertexArray(m_vao_id);
587 GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!");
588
589 /* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value */
590 glw::GLint gl_max_tess_gen_level_value = 0;
591
592 gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value);
593 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() call failed for GL_MAX_TESS_GEN_LEVEL_EXT pname");
594
595 /* Initialize all test runs */
596 _tessellation_level_set_filter filter =
597 (_tessellation_level_set_filter)((int)TESSELLATION_LEVEL_SET_FILTER_ALL_COMBINATIONS |
598 (int)TESSELLATION_LEVEL_SET_FILTER_EXCLUDE_NEGATIVE_BASE_VALUE);
599
600 _tessellation_levels_set levels_sets = TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode(
601 TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES, gl_max_tess_gen_level_value, filter);
602
603 for (_tessellation_levels_set_const_iterator set_iterator = levels_sets.begin(); set_iterator != levels_sets.end();
604 set_iterator++)
605 {
606 _run run;
607 const _tessellation_levels &set = *set_iterator;
608
609 memcpy(run.base_inner, set.inner, sizeof(run.base_inner));
610 memcpy(run.base_outer, set.outer, sizeof(run.base_outer));
611
612 run.reference_inner[0] = run.base_inner[0];
613 run.reference_inner[1] = run.base_inner[1] * 0.25f;
614
615 run.reference_outer[0] = run.base_outer[0];
616 run.reference_outer[1] = run.base_outer[1];
617 run.reference_outer[2] = run.base_outer[2];
618 run.reference_outer[3] = run.base_outer[3] * 0.25f;
619
620 /* Retrieve vertex data for both passes */
621 glw::GLint n_base_vertices = 0;
622 glw::GLint n_reference_vertices = 0;
623
624 n_base_vertices = m_utils->getAmountOfVerticesGeneratedByTessellator(
625 TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES, run.base_inner, run.base_outer,
626 TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, false);
627 n_reference_vertices = m_utils->getAmountOfVerticesGeneratedByTessellator(
628 TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES, run.reference_inner, run.reference_outer,
629 TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, false); /* is_point_mode_enabled */
630
631 if (n_base_vertices == 0)
632 {
633 m_testCtx.getLog() << tcu::TestLog::Message
634 << "No vertices were generated by tessellator for: "
635 "inner tess levels:"
636 "["
637 << run.base_inner[0] << ", " << run.base_inner[1]
638 << "]"
639 ", outer tess levels:"
640 "["
641 << run.base_outer[0] << ", " << run.base_outer[1] << ", " << run.base_outer[2] << ", "
642 << run.base_outer[3]
643 << "]"
644 ", primitive mode: triangles, vertex spacing: equal."
645 << tcu::TestLog::EndMessage;
646
647 TCU_FAIL("Zero vertices were generated by tessellator for base test pass");
648 }
649
650 if (n_reference_vertices == 0)
651 {
652 m_testCtx.getLog() << tcu::TestLog::Message
653 << "No vertices were generated by tessellator for: "
654 "inner tess levels:"
655 "["
656 << run.reference_inner[0] << ", " << run.reference_inner[1]
657 << "]"
658 ", outer tess levels:"
659 "["
660 << run.reference_outer[0] << ", " << run.reference_outer[1] << ", "
661 << run.reference_outer[2] << ", " << run.reference_outer[3]
662 << "]"
663 ", primitive mode: triangles, vertex spacing: equal."
664 << tcu::TestLog::EndMessage;
665
666 TCU_FAIL("Zero vertices were generated by tessellator for reference test pass");
667 }
668
669 if (n_base_vertices != n_reference_vertices)
670 {
671 m_testCtx.getLog() << tcu::TestLog::Message
672 << "Amount of vertices generated by the tessellator differs"
673 " for the following inner/outer configs: "
674 "inner tess levels:"
675 "["
676 << run.base_inner[0] << ", " << run.base_inner[1]
677 << "]"
678 ", outer tess levels:"
679 "["
680 << run.base_outer[0] << ", " << run.base_outer[1] << ", " << run.base_outer[2] << ", "
681 << run.base_outer[3]
682 << "]"
683 " and inner tess levels:"
684 "["
685 << run.reference_inner[0] << ", " << run.reference_inner[1]
686 << "]"
687 ", outer tess levels:"
688 "["
689 << run.reference_outer[0] << ", " << run.reference_outer[1] << ", "
690 << run.reference_outer[2] << ", " << run.reference_outer[3]
691 << "]"
692 ", primitive mode: triangles, vertex spacing: equal."
693 << tcu::TestLog::EndMessage;
694
695 TCU_FAIL("Amount of vertices generated by tessellator differs between base and references passes");
696 }
697
698 run.n_vertices = n_base_vertices;
699
700 run.base_data = m_utils->getDataGeneratedByTessellator(
701 run.base_inner, false, /* is_point_mode_enabled */
702 TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES, TESSELLATION_SHADER_VERTEX_ORDERING_CCW,
703 TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, run.base_outer);
704 run.reference_data = m_utils->getDataGeneratedByTessellator(
705 run.reference_inner, false, /* is_point_mode_enabled */
706 TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES, TESSELLATION_SHADER_VERTEX_ORDERING_CCW,
707 TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, run.reference_outer);
708
709 /* Store the run data */
710 m_runs.push_back(run);
711 } /* for (all sets) */
712 }
713
714 /** Executes the test.
715 *
716 * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
717 *
718 * Note the function throws exception should an error occur!
719 *
720 * @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again.
721 **/
iterate(void)722 tcu::TestNode::IterateResult TessellationShaderTrianglesIdenticalTriangles::iterate(void)
723 {
724 /* Do not execute if required extensions are not supported. */
725 if (!m_is_tessellation_shader_supported)
726 {
727 throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
728 }
729
730 /* Initialize the test */
731 initTest();
732
733 /* Iterate through all runs */
734
735 for (_runs_const_iterator run_iterator = m_runs.begin(); run_iterator != m_runs.end(); run_iterator++)
736 {
737 const _run &run = *run_iterator;
738
739 /* Make sure the vertex data generated for two passes matches */
740 const glw::GLint n_triangles = run.n_vertices / 3 /* vertices per triangle */;
741
742 for (int n_triangle = 0; n_triangle < n_triangles; ++n_triangle)
743 {
744 const float *triangle_a = (const float *)(&run.base_data[0]) + n_triangle * 3 /* vertices */
745 * 3; /* components */
746 const float *triangle_b = (const float *)(&run.reference_data[0]) + n_triangle * 3 /* vertices */
747 * 3; /* components */
748
749 if (!TessellationShaderUtils::isTriangleDefined(triangle_a, triangle_b))
750 {
751 m_testCtx.getLog() << tcu::TestLog::Message
752 << "The following triangle, generated in the first pass, was not "
753 "generated in the other. "
754 "First pass' configuration: inner tess levels:"
755 "["
756 << run.base_inner[0] << ", " << run.base_inner[1]
757 << "]"
758 ", outer tess levels:"
759 "["
760 << run.base_outer[0] << ", " << run.base_outer[1] << ", " << run.base_outer[2]
761 << ", " << run.base_outer[3]
762 << "]"
763 "; second pass' configuration: inner tess levels:"
764 "["
765 << run.reference_inner[0] << ", " << run.reference_inner[1]
766 << "]"
767 ", outer tess levels:"
768 "["
769 << run.reference_outer[0] << ", " << run.reference_outer[1] << ", "
770 << run.reference_outer[2] << ", " << run.reference_outer[3]
771 << "]"
772 ", primitive mode: triangles, vertex spacing: equal."
773 << tcu::TestLog::EndMessage;
774
775 TCU_FAIL("A triangle from base vertex data set was not found in reference vertex data set.");
776 }
777 } /* for (all vertices) */
778 } /* for (all runs) */
779
780 /* All done */
781 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
782 return STOP;
783 }
784
785 /** Constructor
786 *
787 * @param context Test context
788 **/
TessellationShaderTrianglesInnerTessellationLevelRounding(Context & context,const ExtParameters & extParams)789 TessellationShaderTrianglesInnerTessellationLevelRounding::TessellationShaderTrianglesInnerTessellationLevelRounding(
790 Context &context, const ExtParameters &extParams)
791 : TestCaseBase(context, extParams, "inner_tessellation_level_rounding",
792 "Verifies that inner tessellation level is rounded to 1 or 2,"
793 " when the tessellator is run in triangles primitive mode and "
794 "inner tessellation level is set to 1 and any of the outer "
795 "tessellation levels is greater than one.")
796 , m_vao_id(0)
797 , m_utils(DE_NULL)
798 {
799 /* Left blank on purpose */
800 }
801
802 /** Deinitializes ES objects created for the test. */
deinit()803 void TessellationShaderTrianglesInnerTessellationLevelRounding::deinit()
804 {
805 /* Call base class' deinit() */
806 TestCaseBase::deinit();
807
808 if (!m_is_tessellation_shader_supported)
809 {
810 return;
811 }
812
813 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
814
815 /* Unbind vertex array object */
816 gl.bindVertexArray(0);
817
818 /* Deallocate test variables */
819 if (m_vao_id != 0)
820 {
821 gl.deleteVertexArrays(1, &m_vao_id);
822
823 m_vao_id = 0;
824 }
825
826 /* Deinitialize utils instance */
827 if (m_utils != DE_NULL)
828 {
829 delete m_utils;
830
831 m_utils = DE_NULL;
832 }
833 }
834
835 /** Executes the test.
836 *
837 * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
838 *
839 * Note the function throws exception should an error occur!
840 *
841 * @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again.
842 **/
iterate(void)843 tcu::TestNode::IterateResult TessellationShaderTrianglesInnerTessellationLevelRounding::iterate(void)
844 {
845 /* Do not execute if required extensions are not supported. */
846 if (!m_is_tessellation_shader_supported)
847 {
848 throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
849 }
850
851 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
852
853 /* Initialize vertex array object */
854 gl.genVertexArrays(1, &m_vao_id);
855 GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object");
856
857 gl.bindVertexArray(m_vao_id);
858 GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!");
859
860 /* Initialize and run test iterations. In later part, we will verify the generated data. */
861 runTestIterations();
862
863 /* Iterate through all runs */
864
865 for (_runs_const_iterator run_iterator = m_runs.begin(); run_iterator != m_runs.end(); run_iterator++)
866 {
867 const _run &run = *run_iterator;
868
869 if (run.vertex_spacing == TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD &&
870 de::abs(run.set1_inner[0] - run.set2_inner[0]) > 1e-5f &&
871 de::min(run.set1_inner[0], run.set2_inner[0]) >= 1.0f)
872 {
873 /* In fractional_odd_spacing mode with inner level <f> >= 1.0f, the clamped
874 and rounded integer level <n> is at least 3.
875
876 These results in inner subdivision into at least <n>-2=1 segment and
877 two additional, typically shorter segments.
878
879 The length of these two additional segments relative to the others will
880 decrease monotonically with the value of <n>-<f>, so if different <f> levels
881 were used, we cannot proceed with matching the exact vertex data. */
882
883 continue;
884 }
885
886 /* Make sure the vertex data generated for two passes matches */
887 const glw::GLint n_triangles = run.n_vertices / 3 /* vertices per triangle */;
888
889 for (int n_triangle = 0; n_triangle < n_triangles; ++n_triangle)
890 {
891 const float *triangle_a = (const float *)(&run.set1_data[0]) + n_triangle * 3 /* vertices */
892 * 3; /* components */
893 const float *triangle_b = (const float *)(&run.set2_data[0]) + n_triangle * 3 /* vertices */
894 * 3; /* components */
895
896 if (!TessellationShaderUtils::isTriangleDefined(triangle_a, triangle_b))
897 {
898 std::string vs_mode_string =
899 TessellationShaderUtils::getESTokenForVertexSpacingMode(run.vertex_spacing);
900
901 m_testCtx.getLog() << tcu::TestLog::Message
902 << "The following triangle, generated in the first pass, was not "
903 "generated in the second one. "
904 "First pass' configuration: inner tess levels:"
905 "["
906 << run.set1_inner[0] << ", " << run.set1_inner[1]
907 << "]"
908 ", outer tess levels:"
909 "["
910 << run.set1_outer[0] << ", " << run.set1_outer[1] << ", " << run.set1_outer[2]
911 << ", " << run.set1_outer[3]
912 << "]"
913 "; second pass' configuration: inner tess levels:"
914 "["
915 << run.set2_inner[0] << ", " << run.set2_inner[1]
916 << "]"
917 ", outer tess levels:"
918 "["
919 << run.set2_outer[0] << ", " << run.set2_outer[1] << ", " << run.set2_outer[2]
920 << ", " << run.set2_outer[3]
921 << "]"
922 ", primitive mode: triangles, vertex spacing: "
923 << vs_mode_string << tcu::TestLog::EndMessage;
924
925 TCU_FAIL("A triangle from first pass' data set was not found in second pass' data set.");
926 }
927 } /* for (all vertices) */
928 } /* for (all runs) */
929
930 /* All done */
931 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
932 return STOP;
933 }
934
935 /** Runs all test iterations needed to generate data for later verification. */
runTestIterations()936 void TessellationShaderTrianglesInnerTessellationLevelRounding::runTestIterations()
937 {
938 /* Skip if required extensions are not supported. */
939 if (!m_is_tessellation_shader_supported)
940 {
941 throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
942 }
943
944 /* Initialize Utils instance */
945 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
946
947 m_utils = new TessellationShaderUtils(gl, this);
948
949 /* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value */
950 glw::GLint gl_max_tess_gen_level_value = 0;
951
952 gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value);
953 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() call failed for GL_MAX_TESS_GEN_LEVEL_EXT pname");
954
955 /* Initialize all test runs */
956 const glw::GLint tess_levels[] = {2, gl_max_tess_gen_level_value / 2, gl_max_tess_gen_level_value};
957 const unsigned int n_tess_levels = sizeof(tess_levels) / sizeof(tess_levels[0]);
958
959 const _tessellation_shader_vertex_spacing vs_modes[] = {TESSELLATION_SHADER_VERTEX_SPACING_EQUAL,
960 TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_EVEN,
961 TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD};
962 const unsigned int n_vs_modes = sizeof(vs_modes) / sizeof(vs_modes[0]);
963
964 for (unsigned int n_vs_mode = 0; n_vs_mode < n_vs_modes; ++n_vs_mode)
965 {
966 _tessellation_shader_vertex_spacing vs_mode = vs_modes[n_vs_mode];
967
968 for (unsigned int n_tess_level = 0; n_tess_level < n_tess_levels; ++n_tess_level)
969 {
970 /* Set up the run descriptor */
971 glw::GLint tess_level = tess_levels[n_tess_level];
972 _run run;
973
974 run.set1_inner[0] = 1.0f;
975 run.set1_inner[1] = 0.0f;
976 run.set2_inner[1] = 0.0f;
977
978 TessellationShaderUtils::getTessellationLevelAfterVertexSpacing(vs_mode, 1.5f, gl_max_tess_gen_level_value,
979 DE_NULL, /* out_clamped */
980 run.set2_inner);
981 run.set1_outer[0] = (glw::GLfloat)tess_level;
982 run.set2_outer[0] = (glw::GLfloat)tess_level;
983 run.set1_outer[1] = (glw::GLfloat)tess_level;
984 run.set2_outer[1] = (glw::GLfloat)tess_level;
985 run.set1_outer[2] = (glw::GLfloat)tess_level;
986 run.set2_outer[2] = (glw::GLfloat)tess_level;
987 run.set1_outer[3] = (glw::GLfloat)tess_level;
988 run.set2_outer[3] = (glw::GLfloat)tess_level;
989
990 run.vertex_spacing = vs_mode;
991
992 /* Retrieve vertex data for both passes */
993 glw::GLint n_set1_vertices = 0;
994 glw::GLint n_set2_vertices = 0;
995
996 n_set1_vertices = m_utils->getAmountOfVerticesGeneratedByTessellator(
997 TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES, run.set1_inner, run.set1_outer, run.vertex_spacing,
998 false); /* is_point_mode_enabled */
999 n_set2_vertices = m_utils->getAmountOfVerticesGeneratedByTessellator(
1000 TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES, run.set2_inner, run.set2_outer, run.vertex_spacing,
1001 false); /* is_point_mode_enabled */
1002
1003 if (n_set1_vertices == 0)
1004 {
1005 std::string vs_mode_string = TessellationShaderUtils::getESTokenForVertexSpacingMode(vs_mode);
1006
1007 m_testCtx.getLog() << tcu::TestLog::Message
1008 << "No vertices were generated by tessellator for: "
1009 "inner tess levels:"
1010 "["
1011 << run.set1_inner[0] << ", " << run.set1_inner[1]
1012 << "]"
1013 ", outer tess levels:"
1014 "["
1015 << run.set1_outer[0] << ", " << run.set1_outer[1] << ", " << run.set1_outer[2]
1016 << ", " << run.set1_outer[3]
1017 << "]"
1018 ", primitive mode: triangles, "
1019 "vertex spacing: "
1020 << vs_mode_string << tcu::TestLog::EndMessage;
1021
1022 TCU_FAIL("Zero vertices were generated by tessellator for first test pass");
1023 }
1024
1025 if (n_set2_vertices == 0)
1026 {
1027 std::string vs_mode_string = TessellationShaderUtils::getESTokenForVertexSpacingMode(vs_mode);
1028
1029 m_testCtx.getLog() << tcu::TestLog::Message
1030 << "No vertices were generated by tessellator for: "
1031 "inner tess levels:"
1032 "["
1033 << run.set2_inner[0] << ", " << run.set2_inner[1]
1034 << "]"
1035 ", outer tess levels:"
1036 "["
1037 << run.set2_outer[0] << ", " << run.set2_outer[1] << ", " << run.set2_outer[2]
1038 << ", " << run.set2_outer[3]
1039 << "]"
1040 ", primitive mode: triangles, "
1041 "vertex spacing: "
1042 << vs_mode_string << tcu::TestLog::EndMessage;
1043
1044 TCU_FAIL("Zero vertices were generated by tessellator for second test pass");
1045 }
1046
1047 if (n_set1_vertices != n_set2_vertices)
1048 {
1049 std::string vs_mode_string = TessellationShaderUtils::getESTokenForVertexSpacingMode(vs_mode);
1050
1051 m_testCtx.getLog() << tcu::TestLog::Message
1052 << "Amount of vertices generated by the tessellator differs"
1053 " for the following inner/outer configs: "
1054 "inner tess levels:"
1055 "["
1056 << run.set1_inner[0] << ", " << run.set1_inner[1]
1057 << "]"
1058 ", outer tess levels:"
1059 "["
1060 << run.set1_outer[0] << ", " << run.set1_outer[1] << ", " << run.set1_outer[2]
1061 << ", " << run.set1_outer[3]
1062 << "]"
1063 " and inner tess levels:"
1064 "["
1065 << run.set2_inner[0] << ", " << run.set2_inner[1]
1066 << "]"
1067 ", outer tess levels:"
1068 "["
1069 << run.set2_outer[0] << ", " << run.set2_outer[1] << ", " << run.set2_outer[2]
1070 << ", " << run.set2_outer[3]
1071 << "]"
1072 ", primitive mode: triangles, vertex spacing: "
1073 << vs_mode_string << tcu::TestLog::EndMessage;
1074
1075 TCU_FAIL("Amount of vertices generated by tessellator differs between base and references passes");
1076 }
1077
1078 run.n_vertices = n_set1_vertices;
1079
1080 run.set1_data = m_utils->getDataGeneratedByTessellator(run.set1_inner, false, /* is_point_mode_enabled */
1081 TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES,
1082 TESSELLATION_SHADER_VERTEX_ORDERING_CCW,
1083 run.vertex_spacing, run.set1_outer);
1084 run.set2_data = m_utils->getDataGeneratedByTessellator(run.set2_inner, false, /* is_point_mode_enabled */
1085 TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES,
1086 TESSELLATION_SHADER_VERTEX_ORDERING_CCW,
1087 run.vertex_spacing, run.set2_outer);
1088
1089 /* Store the run data */
1090 m_runs.push_back(run);
1091 } /* for (all sets) */
1092 } /* for (all vertex spacing modes) */
1093 }
1094
1095 } /* namespace glcts */
1096