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 << "No vertices were generated by tessellator for: "
634 "inner tess levels:"
635 "["
636 << run.base_inner[0] << ", " << run.base_inner[1] << "]"
637 ", outer tess levels:"
638 "["
639 << run.base_outer[0] << ", " << run.base_outer[1] << ", " << run.base_outer[2] << ", "
640 << run.base_outer[3] << "]"
641 ", primitive mode: triangles, vertex spacing: equal."
642 << tcu::TestLog::EndMessage;
643
644 TCU_FAIL("Zero vertices were generated by tessellator for base test pass");
645 }
646
647 if (n_reference_vertices == 0)
648 {
649 m_testCtx.getLog() << tcu::TestLog::Message << "No vertices were generated by tessellator for: "
650 "inner tess levels:"
651 "["
652 << run.reference_inner[0] << ", " << run.reference_inner[1] << "]"
653 ", outer tess levels:"
654 "["
655 << run.reference_outer[0] << ", " << run.reference_outer[1] << ", "
656 << run.reference_outer[2] << ", " << run.reference_outer[3]
657 << "]"
658 ", primitive mode: triangles, vertex spacing: equal."
659 << tcu::TestLog::EndMessage;
660
661 TCU_FAIL("Zero vertices were generated by tessellator for reference test pass");
662 }
663
664 if (n_base_vertices != n_reference_vertices)
665 {
666 m_testCtx.getLog() << tcu::TestLog::Message << "Amount of vertices generated by the tessellator differs"
667 " for the following inner/outer configs: "
668 "inner tess levels:"
669 "["
670 << run.base_inner[0] << ", " << run.base_inner[1] << "]"
671 ", outer tess levels:"
672 "["
673 << run.base_outer[0] << ", " << run.base_outer[1] << ", " << run.base_outer[2] << ", "
674 << run.base_outer[3] << "]"
675 " and inner tess levels:"
676 "["
677 << run.reference_inner[0] << ", " << run.reference_inner[1] << "]"
678 ", outer tess levels:"
679 "["
680 << run.reference_outer[0] << ", " << run.reference_outer[1] << ", "
681 << run.reference_outer[2] << ", " << run.reference_outer[3]
682 << "]"
683 ", primitive mode: triangles, vertex spacing: equal."
684 << tcu::TestLog::EndMessage;
685
686 TCU_FAIL("Amount of vertices generated by tessellator differs between base and references passes");
687 }
688
689 run.n_vertices = n_base_vertices;
690
691 run.base_data = m_utils->getDataGeneratedByTessellator(
692 run.base_inner, false, /* is_point_mode_enabled */
693 TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES, TESSELLATION_SHADER_VERTEX_ORDERING_CCW,
694 TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, run.base_outer);
695 run.reference_data = m_utils->getDataGeneratedByTessellator(
696 run.reference_inner, false, /* is_point_mode_enabled */
697 TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES, TESSELLATION_SHADER_VERTEX_ORDERING_CCW,
698 TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, run.reference_outer);
699
700 /* Store the run data */
701 m_runs.push_back(run);
702 } /* for (all sets) */
703 }
704
705 /** Executes the test.
706 *
707 * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
708 *
709 * Note the function throws exception should an error occur!
710 *
711 * @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again.
712 **/
iterate(void)713 tcu::TestNode::IterateResult TessellationShaderTrianglesIdenticalTriangles::iterate(void)
714 {
715 /* Do not execute if required extensions are not supported. */
716 if (!m_is_tessellation_shader_supported)
717 {
718 throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
719 }
720
721 /* Initialize the test */
722 initTest();
723
724 /* Iterate through all runs */
725
726 for (_runs_const_iterator run_iterator = m_runs.begin(); run_iterator != m_runs.end(); run_iterator++)
727 {
728 const _run& run = *run_iterator;
729
730 /* Make sure the vertex data generated for two passes matches */
731 const glw::GLint n_triangles = run.n_vertices / 3 /* vertices per triangle */;
732
733 for (int n_triangle = 0; n_triangle < n_triangles; ++n_triangle)
734 {
735 const float* triangle_a = (const float*)(&run.base_data[0]) +
736 n_triangle * 3 /* vertices */
737 * 3; /* components */
738 const float* triangle_b = (const float*)(&run.reference_data[0]) +
739 n_triangle * 3 /* vertices */
740 * 3; /* components */
741
742 if (!TessellationShaderUtils::isTriangleDefined(triangle_a, triangle_b))
743 {
744 m_testCtx.getLog() << tcu::TestLog::Message
745 << "The following triangle, generated in the first pass, was not "
746 "generated in the other. "
747 "First pass' configuration: inner tess levels:"
748 "["
749 << run.base_inner[0] << ", " << run.base_inner[1] << "]"
750 ", outer tess levels:"
751 "["
752 << run.base_outer[0] << ", " << run.base_outer[1] << ", " << run.base_outer[2]
753 << ", " << run.base_outer[3] << "]"
754 "; second pass' configuration: inner tess levels:"
755 "["
756 << run.reference_inner[0] << ", " << run.reference_inner[1] << "]"
757 ", outer tess levels:"
758 "["
759 << run.reference_outer[0] << ", " << run.reference_outer[1] << ", "
760 << run.reference_outer[2] << ", " << run.reference_outer[3]
761 << "]"
762 ", primitive mode: triangles, vertex spacing: equal."
763 << tcu::TestLog::EndMessage;
764
765 TCU_FAIL("A triangle from base vertex data set was not found in reference vertex data set.");
766 }
767 } /* for (all vertices) */
768 } /* for (all runs) */
769
770 /* All done */
771 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
772 return STOP;
773 }
774
775 /** Constructor
776 *
777 * @param context Test context
778 **/
TessellationShaderTrianglesInnerTessellationLevelRounding(Context & context,const ExtParameters & extParams)779 TessellationShaderTrianglesInnerTessellationLevelRounding::TessellationShaderTrianglesInnerTessellationLevelRounding(
780 Context& context, const ExtParameters& extParams)
781 : TestCaseBase(context, extParams, "inner_tessellation_level_rounding",
782 "Verifies that inner tessellation level is rounded to 1 or 2,"
783 " when the tessellator is run in triangles primitive mode and "
784 "inner tessellation level is set to 1 and any of the outer "
785 "tessellation levels is greater than one.")
786 , m_vao_id(0)
787 , m_utils(DE_NULL)
788 {
789 /* Left blank on purpose */
790 }
791
792 /** Deinitializes ES objects created for the test. */
deinit()793 void TessellationShaderTrianglesInnerTessellationLevelRounding::deinit()
794 {
795 /* Call base class' deinit() */
796 TestCaseBase::deinit();
797
798 if (!m_is_tessellation_shader_supported)
799 {
800 return;
801 }
802
803 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
804
805 /* Unbind vertex array object */
806 gl.bindVertexArray(0);
807
808 /* Deallocate test variables */
809 if (m_vao_id != 0)
810 {
811 gl.deleteVertexArrays(1, &m_vao_id);
812
813 m_vao_id = 0;
814 }
815
816 /* Deinitialize utils instance */
817 if (m_utils != DE_NULL)
818 {
819 delete m_utils;
820
821 m_utils = DE_NULL;
822 }
823 }
824
825 /** Executes the test.
826 *
827 * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
828 *
829 * Note the function throws exception should an error occur!
830 *
831 * @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again.
832 **/
iterate(void)833 tcu::TestNode::IterateResult TessellationShaderTrianglesInnerTessellationLevelRounding::iterate(void)
834 {
835 /* Do not execute if required extensions are not supported. */
836 if (!m_is_tessellation_shader_supported)
837 {
838 throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
839 }
840
841 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
842
843 /* Initialize vertex array object */
844 gl.genVertexArrays(1, &m_vao_id);
845 GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object");
846
847 gl.bindVertexArray(m_vao_id);
848 GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!");
849
850 /* Initialize and run test iterations. In later part, we will verify the generated data. */
851 runTestIterations();
852
853 /* Iterate through all runs */
854
855 for (_runs_const_iterator run_iterator = m_runs.begin(); run_iterator != m_runs.end(); run_iterator++)
856 {
857 const _run& run = *run_iterator;
858
859 if (run.vertex_spacing == TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD &&
860 de::abs(run.set1_inner[0] - run.set2_inner[0]) > 1e-5f &&
861 de::min(run.set1_inner[0], run.set2_inner[0]) >= 1.0f)
862 {
863 /* In fractional_odd_spacing mode with inner level <f> >= 1.0f, the clamped
864 and rounded integer level <n> is at least 3.
865
866 These results in inner subdivision into at least <n>-2=1 segment and
867 two additional, typically shorter segments.
868
869 The length of these two additional segments relative to the others will
870 decrease monotonically with the value of <n>-<f>, so if different <f> levels
871 were used, we cannot proceed with matching the exact vertex data. */
872
873 continue;
874 }
875
876 /* Make sure the vertex data generated for two passes matches */
877 const glw::GLint n_triangles = run.n_vertices / 3 /* vertices per triangle */;
878
879 for (int n_triangle = 0; n_triangle < n_triangles; ++n_triangle)
880 {
881 const float* triangle_a = (const float*)(&run.set1_data[0]) +
882 n_triangle * 3 /* vertices */
883 * 3; /* components */
884 const float* triangle_b = (const float*)(&run.set2_data[0]) +
885 n_triangle * 3 /* vertices */
886 * 3; /* components */
887
888 if (!TessellationShaderUtils::isTriangleDefined(triangle_a, triangle_b))
889 {
890 std::string vs_mode_string =
891 TessellationShaderUtils::getESTokenForVertexSpacingMode(run.vertex_spacing);
892
893 m_testCtx.getLog() << tcu::TestLog::Message
894 << "The following triangle, generated in the first pass, was not "
895 "generated in the second one. "
896 "First pass' configuration: inner tess levels:"
897 "["
898 << run.set1_inner[0] << ", " << run.set1_inner[1] << "]"
899 ", outer tess levels:"
900 "["
901 << run.set1_outer[0] << ", " << run.set1_outer[1] << ", " << run.set1_outer[2]
902 << ", " << run.set1_outer[3] << "]"
903 "; second pass' configuration: inner tess levels:"
904 "["
905 << run.set2_inner[0] << ", " << run.set2_inner[1] << "]"
906 ", outer tess levels:"
907 "["
908 << run.set2_outer[0] << ", " << run.set2_outer[1] << ", " << run.set2_outer[2]
909 << ", " << run.set2_outer[3] << "]"
910 ", primitive mode: triangles, vertex spacing: "
911 << vs_mode_string << tcu::TestLog::EndMessage;
912
913 TCU_FAIL("A triangle from first pass' data set was not found in second pass' data set.");
914 }
915 } /* for (all vertices) */
916 } /* for (all runs) */
917
918 /* All done */
919 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
920 return STOP;
921 }
922
923 /** Runs all test iterations needed to generate data for later verification. */
runTestIterations()924 void TessellationShaderTrianglesInnerTessellationLevelRounding::runTestIterations()
925 {
926 /* Skip if required extensions are not supported. */
927 if (!m_is_tessellation_shader_supported)
928 {
929 throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
930 }
931
932 /* Initialize Utils instance */
933 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
934
935 m_utils = new TessellationShaderUtils(gl, this);
936
937 /* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value */
938 glw::GLint gl_max_tess_gen_level_value = 0;
939
940 gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value);
941 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() call failed for GL_MAX_TESS_GEN_LEVEL_EXT pname");
942
943 /* Initialize all test runs */
944 const glw::GLint tess_levels[] = { 2, gl_max_tess_gen_level_value / 2, gl_max_tess_gen_level_value };
945 const unsigned int n_tess_levels = sizeof(tess_levels) / sizeof(tess_levels[0]);
946
947 const _tessellation_shader_vertex_spacing vs_modes[] = { TESSELLATION_SHADER_VERTEX_SPACING_EQUAL,
948 TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_EVEN,
949 TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD };
950 const unsigned int n_vs_modes = sizeof(vs_modes) / sizeof(vs_modes[0]);
951
952 for (unsigned int n_vs_mode = 0; n_vs_mode < n_vs_modes; ++n_vs_mode)
953 {
954 _tessellation_shader_vertex_spacing vs_mode = vs_modes[n_vs_mode];
955
956 for (unsigned int n_tess_level = 0; n_tess_level < n_tess_levels; ++n_tess_level)
957 {
958 /* Set up the run descriptor */
959 glw::GLint tess_level = tess_levels[n_tess_level];
960 _run run;
961
962 run.set1_inner[0] = 1.0f;
963 run.set1_inner[1] = 0.0f;
964 run.set2_inner[1] = 0.0f;
965
966 TessellationShaderUtils::getTessellationLevelAfterVertexSpacing(vs_mode, 1.5f, gl_max_tess_gen_level_value,
967 DE_NULL, /* out_clamped */
968 run.set2_inner);
969 run.set1_outer[0] = (glw::GLfloat)tess_level;
970 run.set2_outer[0] = (glw::GLfloat)tess_level;
971 run.set1_outer[1] = (glw::GLfloat)tess_level;
972 run.set2_outer[1] = (glw::GLfloat)tess_level;
973 run.set1_outer[2] = (glw::GLfloat)tess_level;
974 run.set2_outer[2] = (glw::GLfloat)tess_level;
975 run.set1_outer[3] = (glw::GLfloat)tess_level;
976 run.set2_outer[3] = (glw::GLfloat)tess_level;
977
978 run.vertex_spacing = vs_mode;
979
980 /* Retrieve vertex data for both passes */
981 glw::GLint n_set1_vertices = 0;
982 glw::GLint n_set2_vertices = 0;
983
984 n_set1_vertices = m_utils->getAmountOfVerticesGeneratedByTessellator(
985 TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES, run.set1_inner, run.set1_outer, run.vertex_spacing,
986 false); /* is_point_mode_enabled */
987 n_set2_vertices = m_utils->getAmountOfVerticesGeneratedByTessellator(
988 TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES, run.set2_inner, run.set2_outer, run.vertex_spacing,
989 false); /* is_point_mode_enabled */
990
991 if (n_set1_vertices == 0)
992 {
993 std::string vs_mode_string = TessellationShaderUtils::getESTokenForVertexSpacingMode(vs_mode);
994
995 m_testCtx.getLog() << tcu::TestLog::Message << "No vertices were generated by tessellator for: "
996 "inner tess levels:"
997 "["
998 << run.set1_inner[0] << ", " << run.set1_inner[1] << "]"
999 ", outer tess levels:"
1000 "["
1001 << run.set1_outer[0] << ", " << run.set1_outer[1] << ", " << run.set1_outer[2]
1002 << ", " << run.set1_outer[3] << "]"
1003 ", primitive mode: triangles, "
1004 "vertex spacing: "
1005 << vs_mode_string << tcu::TestLog::EndMessage;
1006
1007 TCU_FAIL("Zero vertices were generated by tessellator for first test pass");
1008 }
1009
1010 if (n_set2_vertices == 0)
1011 {
1012 std::string vs_mode_string = TessellationShaderUtils::getESTokenForVertexSpacingMode(vs_mode);
1013
1014 m_testCtx.getLog() << tcu::TestLog::Message << "No vertices were generated by tessellator for: "
1015 "inner tess levels:"
1016 "["
1017 << run.set2_inner[0] << ", " << run.set2_inner[1] << "]"
1018 ", outer tess levels:"
1019 "["
1020 << run.set2_outer[0] << ", " << run.set2_outer[1] << ", " << run.set2_outer[2]
1021 << ", " << run.set2_outer[3] << "]"
1022 ", primitive mode: triangles, "
1023 "vertex spacing: "
1024 << vs_mode_string << tcu::TestLog::EndMessage;
1025
1026 TCU_FAIL("Zero vertices were generated by tessellator for second test pass");
1027 }
1028
1029 if (n_set1_vertices != n_set2_vertices)
1030 {
1031 std::string vs_mode_string = TessellationShaderUtils::getESTokenForVertexSpacingMode(vs_mode);
1032
1033 m_testCtx.getLog() << tcu::TestLog::Message << "Amount of vertices generated by the tessellator differs"
1034 " for the following inner/outer configs: "
1035 "inner tess levels:"
1036 "["
1037 << run.set1_inner[0] << ", " << run.set1_inner[1] << "]"
1038 ", outer tess levels:"
1039 "["
1040 << run.set1_outer[0] << ", " << run.set1_outer[1] << ", " << run.set1_outer[2]
1041 << ", " << run.set1_outer[3] << "]"
1042 " and inner tess levels:"
1043 "["
1044 << run.set2_inner[0] << ", " << run.set2_inner[1] << "]"
1045 ", outer tess levels:"
1046 "["
1047 << run.set2_outer[0] << ", " << run.set2_outer[1] << ", " << run.set2_outer[2]
1048 << ", " << run.set2_outer[3] << "]"
1049 ", primitive mode: triangles, vertex spacing: "
1050 << vs_mode_string << tcu::TestLog::EndMessage;
1051
1052 TCU_FAIL("Amount of vertices generated by tessellator differs between base and references passes");
1053 }
1054
1055 run.n_vertices = n_set1_vertices;
1056
1057 run.set1_data = m_utils->getDataGeneratedByTessellator(run.set1_inner, false, /* is_point_mode_enabled */
1058 TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES,
1059 TESSELLATION_SHADER_VERTEX_ORDERING_CCW,
1060 run.vertex_spacing, run.set1_outer);
1061 run.set2_data = m_utils->getDataGeneratedByTessellator(run.set2_inner, false, /* is_point_mode_enabled */
1062 TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES,
1063 TESSELLATION_SHADER_VERTEX_ORDERING_CCW,
1064 run.vertex_spacing, run.set2_outer);
1065
1066 /* Store the run data */
1067 m_runs.push_back(run);
1068 } /* for (all sets) */
1069 } /* for (all vertex spacing modes) */
1070 }
1071
1072 } /* namespace glcts */
1073