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 "esextcTessellationShaderInvariance.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 /* Defines a single vertex in tessellation space */
35 typedef struct _vertex
36 {
37 float u;
38 float v;
39 float w;
40
_vertexglcts::_vertex41 _vertex()
42 {
43 u = 0.0f;
44 v = 0.0f;
45 w = 0.0f;
46 }
47 } _vertex;
48
49 /** Constructor
50 *
51 * @param context Test context
52 **/
TessellationShaderInvarianceTests(glcts::Context & context,const ExtParameters & extParams)53 TessellationShaderInvarianceTests::TessellationShaderInvarianceTests(glcts::Context &context,
54 const ExtParameters &extParams)
55 : TestCaseGroupBase(context, extParams, "tessellation_invariance",
56 "Verifies the implementation conforms to invariance rules.")
57 {
58 /* No implementation needed */
59 }
60
61 /**
62 * Initializes test groups for geometry shader tests
63 **/
init(void)64 void TessellationShaderInvarianceTests::init(void)
65 {
66 addChild(new glcts::TessellationShaderInvarianceRule1Test(m_context, m_extParams));
67 addChild(new glcts::TessellationShaderInvarianceRule2Test(m_context, m_extParams));
68 addChild(new glcts::TessellationShaderInvarianceRule3Test(m_context, m_extParams));
69 addChild(new glcts::TessellationShaderInvarianceRule4Test(m_context, m_extParams));
70 addChild(new glcts::TessellationShaderInvarianceRule5Test(m_context, m_extParams));
71 addChild(new glcts::TessellationShaderInvarianceRule6Test(m_context, m_extParams));
72 addChild(new glcts::TessellationShaderInvarianceRule7Test(m_context, m_extParams));
73 }
74
75 /** Constructor
76 *
77 * @param context Test context
78 * @param name Test name
79 * @param description Test description
80 **/
TessellationShaderInvarianceBaseTest(Context & context,const ExtParameters & extParams,const char * name,const char * description)81 TessellationShaderInvarianceBaseTest::TessellationShaderInvarianceBaseTest(Context &context,
82 const ExtParameters &extParams,
83 const char *name, const char *description)
84 : TestCaseBase(context, extParams, name, description)
85 , m_utils_ptr(DE_NULL)
86 , m_bo_id(0)
87 , m_qo_tfpw_id(0)
88 , m_vao_id(0)
89 {
90 /* Left blank on purpose */
91 }
92
93 /** Deinitializes ES objects created for the test. */
deinit()94 void TessellationShaderInvarianceBaseTest::deinit()
95 {
96 /* Call base class' deinit() */
97 TestCaseBase::deinit();
98
99 if (!m_is_tessellation_shader_supported)
100 {
101 return;
102 }
103
104 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
105
106 /* Revert buffer object bindings */
107 gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* buffer */);
108 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, 0 /* buffer */);
109
110 /* Disable GL_RASTERIZER_DISCARD mode */
111 gl.disable(GL_RASTERIZER_DISCARD);
112
113 /* Reset GL_PATCH_VERTICES_EXT to default value */
114 gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 3);
115
116 /* Unbind vertex array object */
117 gl.bindVertexArray(0);
118
119 /* Deinitialize all ES objects that were created for test purposes */
120 if (m_bo_id != 0)
121 {
122 gl.deleteBuffers(1, &m_bo_id);
123
124 m_bo_id = 0;
125 }
126
127 for (_programs_iterator it = m_programs.begin(); it != m_programs.end(); ++it)
128 {
129 _test_program &program = *it;
130
131 if (program.po_id != 0)
132 {
133 gl.deleteProgram(program.po_id);
134 }
135 }
136 m_programs.clear();
137
138 if (m_qo_tfpw_id != 0)
139 {
140 gl.deleteQueries(1, &m_qo_tfpw_id);
141
142 m_qo_tfpw_id = 0;
143 }
144
145 if (m_vao_id != 0)
146 {
147 gl.deleteVertexArrays(1, &m_vao_id);
148
149 m_vao_id = 0;
150 }
151
152 /* Deinitialize TS utils instance */
153 if (m_utils_ptr != NULL)
154 {
155 delete m_utils_ptr;
156
157 m_utils_ptr = NULL;
158 }
159 }
160
161 /** Executes a single-counted GL_PATCHES_EXT draw call.
162 *
163 * Throws TestError exception if an error occurs.
164 *
165 * @param n_iteration Not used.
166 *
167 **/
executeDrawCall(unsigned int n_iteration)168 void TessellationShaderInvarianceBaseTest::executeDrawCall(unsigned int n_iteration)
169 {
170 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
171
172 DE_UNREF(n_iteration);
173
174 gl.drawArrays(m_glExtTokens.PATCHES, 0 /* first */, getDrawCallCountArgument());
175 GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed");
176 }
177
178 /** Returns a value that should be used for the draw call's "count" argument.
179 *
180 * @param Always 1
181 **/
getDrawCallCountArgument()182 unsigned int TessellationShaderInvarianceBaseTest::getDrawCallCountArgument()
183 {
184 return 1;
185 }
186
187 /** Returns source code for fragment shader stage which does
188 * not do anything.
189 *
190 * @param n_iteration Not used.
191 *
192 * @return Requested string.
193 **/
getFSCode(unsigned int n_iteration)194 std::string TessellationShaderInvarianceBaseTest::getFSCode(unsigned int n_iteration)
195 {
196 DE_UNREF(n_iteration);
197
198 std::string result = "${VERSION}\n"
199 "\n"
200 "void main()\n"
201 "{\n"
202 "}\n";
203
204 return result;
205 }
206
207 /** Retrieves name of a vec2 uniform that stores inner tesselaton level information,
208 * later assigned to gl_TessLevelInner in tessellation evaluation shader.
209 *
210 * @return Requested name.
211 **/
getInnerTessLevelUniformName()212 const char *TessellationShaderInvarianceBaseTest::getInnerTessLevelUniformName()
213 {
214 static const char *result = "inner_tess_level";
215
216 return result;
217 }
218
219 /** Retrieves name of a vec4 uniform that stores outer tesselation level information,
220 * later assigned to gl_TessLevelOuter in tessellation evaluation shader.
221 *
222 * @return Requested name.
223 **/
getOuterTessLevelUniformName()224 const char *TessellationShaderInvarianceBaseTest::getOuterTessLevelUniformName()
225 {
226 static const char *result = "outer_tess_level";
227
228 return result;
229 }
230
231 /** Returns generic tessellation control shader code, which sends 4 output patch
232 * to tessellation evaluation shader stage and uses the very first input patch
233 * vertex only.
234 *
235 * @return Tessellation control source code.
236 */
getTCCode(unsigned int n_iteration)237 std::string TessellationShaderInvarianceBaseTest::getTCCode(unsigned int n_iteration)
238 {
239 DE_UNREF(n_iteration);
240
241 /* In order to support all three primitive types, our generic tessellation
242 * control shader will pass 4 vertices to TE stage */
243 return TessellationShaderUtils::getGenericTCCode(4, /* n_patch_vertices */
244 false);
245 }
246
247 /** Retrieves XFB properties for the test pass.
248 *
249 * @param n_iteration Not used.
250 * @param out_n_names Deref will be used to store amount of strings @param *out_n_names
251 * offers.
252 * @param out_names Deref will be used to store pointer to an array of strings holding
253 * names of varyings that should be captured via transform feedback.
254 * Must not be NULL.
255 *
256 **/
getXFBProperties(unsigned int n_iteration,unsigned int * out_n_names,const char *** out_names)257 void TessellationShaderInvarianceBaseTest::getXFBProperties(unsigned int n_iteration, unsigned int *out_n_names,
258 const char ***out_names)
259 {
260 static const char *names[] = {"result_uvw"};
261
262 DE_UNREF(n_iteration);
263
264 *out_n_names = 1;
265 *out_names = names;
266 }
267
268 /** Returns vertex shader source code. The shader sets gl_Position to
269 * vec4(1, 2, 3, 0).
270 *
271 * @return Vertex shader source code.
272 **/
getVSCode(unsigned int n_iteration)273 std::string TessellationShaderInvarianceBaseTest::getVSCode(unsigned int n_iteration)
274 {
275 DE_UNREF(n_iteration);
276
277 std::string result = "${VERSION}\n"
278 "\n"
279 "void main()\n"
280 "{\n"
281 " gl_Position = vec4(1.0, 2.0, 3.0, 0.0);\n"
282 "}\n";
283
284 return result;
285 }
286
287 /** Initializes ES objects required to execute the test.
288 *
289 * Throws TestError exception if an error occurs.
290 *
291 **/
initTest()292 void TessellationShaderInvarianceBaseTest::initTest()
293 {
294 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
295 glw::GLuint shared_fs_id = 0;
296 glw::GLuint shared_tc_id = 0;
297 glw::GLuint shared_te_id = 0;
298 glw::GLuint shared_vs_id = 0;
299
300 gl.genVertexArrays(1, &m_vao_id);
301 GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object");
302
303 gl.bindVertexArray(m_vao_id);
304 GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!");
305
306 /* Initialize GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN query object */
307 gl.genQueries(1, &m_qo_tfpw_id);
308 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenQueries() call failed");
309
310 /* Initialize tessellation shader utils */
311 m_utils_ptr = new TessellationShaderUtils(gl, this);
312
313 /* Initialize a buffer object we will use to store XFB data.
314 * Note: we intentionally skip a glBufferData() call here,
315 * the actual buffer storage size is iteration-specific.
316 **/
317 gl.genBuffers(1, &m_bo_id);
318 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed");
319
320 gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id);
321 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed");
322
323 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* index */
324 m_bo_id);
325 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() call failed");
326
327 /* Iterate through all iterations */
328 const unsigned int n_iterations = getAmountOfIterations();
329 m_programs.reserve(n_iterations);
330
331 const glw::GLenum SHADER_TYPE_FRAGMENT = GL_FRAGMENT_SHADER;
332 const glw::GLenum SHADER_TYPE_TESSELLATION_CONTROL = m_glExtTokens.TESS_CONTROL_SHADER;
333 const glw::GLenum SHADER_TYPE_TESSELLATION_EVALUATION = m_glExtTokens.TESS_EVALUATION_SHADER;
334 const glw::GLenum SHADER_TYPE_VERTEX = GL_VERTEX_SHADER;
335
336 for (unsigned int n_iteration = 0; n_iteration < n_iterations; ++n_iteration)
337 {
338 _test_program program;
339
340 /* Create an iteration-specific program object */
341 program.po_id = gl.createProgram();
342
343 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed.");
344
345 /* Query the implementation on which shader types should be compiled on
346 * a per-iteration basis, and which can be initialized only once */
347 static const glw::GLenum shader_types[] = {SHADER_TYPE_FRAGMENT, SHADER_TYPE_TESSELLATION_CONTROL,
348 SHADER_TYPE_TESSELLATION_EVALUATION, SHADER_TYPE_VERTEX};
349 static const unsigned int n_shader_types = sizeof(shader_types) / sizeof(shader_types[0]);
350
351 for (unsigned int n_shader_type = 0; n_shader_type < n_shader_types; ++n_shader_type)
352 {
353 std::string shader_body;
354 const char *shader_body_ptr = DE_NULL;
355 glw::GLuint shader_id = 0;
356 glw::GLenum shader_type = shader_types[n_shader_type];
357 glw::GLenum shader_type_es = (glw::GLenum)shader_type;
358
359 // Check whether the test should use a separate program objects for each iteration.
360 bool is_shader_iteration_specific = false;
361 if (shader_type == SHADER_TYPE_TESSELLATION_EVALUATION)
362 {
363 is_shader_iteration_specific = true;
364 }
365 else if ((shader_type != SHADER_TYPE_FRAGMENT) && (shader_type != SHADER_TYPE_TESSELLATION_CONTROL) &&
366 (shader_type != SHADER_TYPE_VERTEX))
367 {
368 TCU_FAIL("Unrecognized shader type");
369 }
370
371 /* We need to initialize the shader object if:
372 *
373 * - its body differs between iterations;
374 * - its body is shared by all iterations AND this is the first iteration
375 */
376 bool has_shader_been_generated = false;
377
378 if ((!is_shader_iteration_specific && n_iteration == 0) || is_shader_iteration_specific)
379 {
380 /* Create the shader object */
381 has_shader_been_generated = true;
382 shader_id = gl.createShader(shader_type_es);
383 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed");
384
385 /* Assign shader body to the object */
386 if (shader_type == SHADER_TYPE_FRAGMENT)
387 {
388 shader_body = getFSCode(n_iteration);
389 }
390 else if (shader_type == SHADER_TYPE_TESSELLATION_CONTROL)
391 {
392 shader_body = getTCCode(n_iteration);
393 }
394 else if (shader_type == SHADER_TYPE_TESSELLATION_EVALUATION)
395 {
396 shader_body = getTECode(n_iteration);
397 }
398 else if (shader_type == SHADER_TYPE_VERTEX)
399 {
400 shader_body = getVSCode(n_iteration);
401 }
402 else
403 {
404 TCU_FAIL("Unrecognized shader type");
405 }
406
407 shader_body_ptr = shader_body.c_str();
408
409 shaderSourceSpecialized(shader_id, 1, &shader_body_ptr);
410 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed");
411
412 /* Compile the shader object */
413 m_utils_ptr->compileShaders(1, /* n_shaders */
414 &shader_id, true); /* should_succeed */
415
416 /* If this is a shader object that will be shared by all iterations, cache it
417 * in a dedicated variable */
418 if (!is_shader_iteration_specific)
419 {
420 if (shader_type == SHADER_TYPE_FRAGMENT)
421 {
422 shared_fs_id = shader_id;
423 }
424 else if (shader_type == SHADER_TYPE_TESSELLATION_CONTROL)
425 {
426 shared_tc_id = shader_id;
427 }
428 else if (shader_type == SHADER_TYPE_TESSELLATION_EVALUATION)
429 {
430 shared_te_id = shader_id;
431 }
432 else if (shader_type == SHADER_TYPE_VERTEX)
433 {
434 shared_vs_id = shader_id;
435 }
436 else
437 {
438 TCU_FAIL("Unrecognized shader type");
439 }
440 } /* if (!is_shader_iteration_specific) */
441 } /* if (shader object needs to be initialized) */
442 else
443 {
444 shader_id = (shader_type == SHADER_TYPE_FRAGMENT) ? shared_fs_id :
445 (shader_type == SHADER_TYPE_TESSELLATION_CONTROL) ? shared_tc_id :
446 (shader_type == SHADER_TYPE_TESSELLATION_EVALUATION) ? shared_te_id :
447 shared_vs_id;
448 }
449
450 /* Attach the shader object to iteration-specific program object */
451 gl.attachShader(program.po_id, shader_id);
452
453 GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call failed.");
454
455 /* Now that the object has been attached, we can flag it for deletion */
456 if (has_shader_been_generated)
457 {
458 gl.deleteShader(shader_id);
459 GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteShader() call failed");
460 }
461 } /* for (all shader types) */
462
463 /* Set up transform feed-back */
464 unsigned int n_xfb_names = 0;
465 const char **xfb_names = NULL;
466
467 getXFBProperties(n_iteration, &n_xfb_names, &xfb_names);
468
469 gl.transformFeedbackVaryings(program.po_id, n_xfb_names, xfb_names, GL_INTERLEAVED_ATTRIBS);
470 GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() call failed.");
471
472 /* Try to link the program object */
473 glw::GLint link_status = GL_FALSE;
474
475 gl.linkProgram(program.po_id);
476 GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed");
477
478 gl.getProgramiv(program.po_id, GL_LINK_STATUS, &link_status);
479 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed");
480
481 if (link_status != GL_TRUE)
482 {
483 TCU_FAIL("Program linking failed");
484 }
485
486 /* Retrieve inner/outer tess level uniform locations */
487 program.inner_tess_level_uniform_location =
488 gl.getUniformLocation(program.po_id, getInnerTessLevelUniformName());
489 program.outer_tess_level_uniform_location =
490 gl.getUniformLocation(program.po_id, getOuterTessLevelUniformName());
491
492 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetUniformLocation() call(s) failed");
493
494 /* Store the program object */
495 m_programs.push_back(program);
496 } /* for (all iterations) */
497 }
498
499 /** Executes the test.
500 *
501 * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
502 *
503 * Note the function throws exception should an error occur!
504 *
505 * @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again.
506 **/
iterate(void)507 tcu::TestNode::IterateResult TessellationShaderInvarianceBaseTest::iterate(void)
508 {
509 /* Do not execute if required extensions are not supported. */
510 if (!m_is_tessellation_shader_supported)
511 {
512 throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
513 }
514
515 /* Initialize all objects needed to run the test */
516 initTest();
517
518 /* Do a general set-up */
519 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
520
521 gl.enable(GL_RASTERIZER_DISCARD);
522 GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable(GL_RASTERIZER_DISCARD) failed.");
523
524 gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 1);
525 GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteriEXT() failed for GL_PATCH_VERTICES_EXT pname");
526
527 /* There are two types of verification supported by this base test implementation:
528 *
529 * - iteration-specific (verifyResultDataForIteration() )
530 * - global (verifyResultData() )
531 *
532 * It is up to test implementation to decide which of the two (or perhaps both)
533 * entry-points it should overload and use for validating the result data.
534 */
535 const unsigned int n_iterations = getAmountOfIterations();
536 char **iteration_data = new char *[n_iterations];
537
538 /* Execute the test */
539 for (unsigned int n_iteration = 0; n_iteration < n_iterations; ++n_iteration)
540 {
541 _test_program &program = m_programs[n_iteration];
542
543 /* Retrieve iteration properties for current iteration */
544 unsigned int bo_size = 0;
545 float inner_tess_levels[2] = {0};
546 bool is_point_mode = false;
547 float outer_tess_levels[4] = {0};
548 _tessellation_primitive_mode primitive_mode = TESSELLATION_SHADER_PRIMITIVE_MODE_UNKNOWN;
549 _tessellation_shader_vertex_ordering vertex_ordering = TESSELLATION_SHADER_VERTEX_ORDERING_UNKNOWN;
550
551 getIterationProperties(n_iteration, inner_tess_levels, outer_tess_levels, &is_point_mode, &primitive_mode,
552 &vertex_ordering, &bo_size);
553
554 DE_ASSERT(bo_size != 0);
555
556 /* Activate iteration-specific program */
557 gl.useProgram(program.po_id);
558 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() failed.");
559
560 /* Set up buffer object storage */
561 {
562 char *zero_bo_data = new char[bo_size];
563
564 memset(zero_bo_data, 0, bo_size);
565
566 gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, bo_size, zero_bo_data, GL_STATIC_DRAW);
567 GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() failed");
568
569 delete[] zero_bo_data;
570 zero_bo_data = NULL;
571 }
572
573 /* Allocate space for iteration-specific data */
574 iteration_data[n_iteration] = new char[bo_size];
575
576 /* Configure inner/outer tessellation levels as requested for the iteration */
577 gl.uniform2fv(program.inner_tess_level_uniform_location, 1, /* count */
578 inner_tess_levels);
579 GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform2fv() call failed");
580
581 gl.uniform4fv(program.outer_tess_level_uniform_location, 1, /* count */
582 outer_tess_levels);
583 GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform4fv() call failed");
584
585 /* Launch the TFPW query */
586 gl.beginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, m_qo_tfpw_id);
587 GLU_EXPECT_NO_ERROR(gl.getError(),
588 "glBeginQuery() for GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN target failed.");
589
590 /* Prepare for TF */
591 glw::GLenum tf_mode = TessellationShaderUtils::getTFModeForPrimitiveMode(primitive_mode, is_point_mode);
592
593 gl.beginTransformFeedback(tf_mode);
594 GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() call failed");
595 {
596 /* Execute the draw call */
597 executeDrawCall(n_iteration);
598
599 GLU_EXPECT_NO_ERROR(gl.getError(), "Draw call failed");
600 }
601 gl.endTransformFeedback();
602 GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() call failed");
603
604 gl.endQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
605 GLU_EXPECT_NO_ERROR(gl.getError(), "glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN) call failed");
606
607 /* Make sure that we had sufficient amount of space in a buffer object we used to
608 * capture XFB data.
609 **/
610 glw::GLuint n_tf_primitives_written = 0;
611 glw::GLuint used_tf_bo_size = 0;
612
613 gl.getQueryObjectuiv(m_qo_tfpw_id, GL_QUERY_RESULT, &n_tf_primitives_written);
614 GLU_EXPECT_NO_ERROR(gl.getError(),
615 "Could not retrieve GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN query object result");
616
617 if (is_point_mode)
618 {
619 used_tf_bo_size = static_cast<glw::GLuint>(n_tf_primitives_written * sizeof(float) * 3 /* components */);
620 }
621 else if (primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES)
622 {
623 used_tf_bo_size = static_cast<glw::GLuint>(n_tf_primitives_written * sizeof(float) * 2 /* vertices */ *
624 3 /* components */);
625 }
626 else
627 {
628 used_tf_bo_size = static_cast<glw::GLuint>(n_tf_primitives_written * sizeof(float) * 3 /* vertices */ *
629 3 /* components */);
630 }
631
632 if (used_tf_bo_size != bo_size)
633 {
634 m_testCtx.getLog() << tcu::TestLog::Message << "Expected " << bo_size
635 << " to be filled with tessellation data, "
636 "only "
637 << used_tf_bo_size << "was used." << tcu::TestLog::EndMessage;
638
639 TCU_FAIL("Amount of primitives generated during TF does not match amount of primitives that were expected"
640 " to be generated by the tessellator");
641 }
642
643 /* Map the buffer object we earlier bound to GL_TRANSFORM_FEEDBACK_BUFFER
644 * target into process space. */
645 const void *xfb_data = gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* offset */
646 bo_size, GL_MAP_READ_BIT);
647
648 GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() call failed");
649
650 memcpy(iteration_data[n_iteration], xfb_data, bo_size);
651
652 /* Unmap the buffer object */
653 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
654 GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed");
655
656 /* Ask the test implementation to verify the results */
657 verifyResultDataForIteration(n_iteration, iteration_data[n_iteration]);
658 } /* for (all iterations) */
659
660 /* Now that we've executed all iterations, we can call a global verification
661 * entry-point */
662 verifyResultData((const void **)iteration_data);
663
664 /* At this point we're safe to release space allocated for data coming from
665 * all the iterations */
666 for (unsigned int n_iteration = 0; n_iteration < n_iterations; ++n_iteration)
667 {
668 char *iter_data = (char *)iteration_data[n_iteration];
669 delete[] iter_data;
670
671 iteration_data[n_iteration] = DE_NULL;
672 } /* for (all iterations) */
673
674 delete[] iteration_data;
675 iteration_data = DE_NULL;
676
677 /* All done */
678 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
679 return STOP;
680 }
681
682 /* Does nothing (stub implementation)
683 *
684 * @param n_iteration Not used.
685 * @param data Not used.
686 *
687 **/
verifyResultDataForIteration(unsigned int n_iteration,const void * data)688 void TessellationShaderInvarianceBaseTest::verifyResultDataForIteration(unsigned int n_iteration, const void *data)
689 {
690 DE_UNREF(n_iteration && data);
691
692 /* Do nothing - this is just a stub. */
693 }
694
695 /* Does nothing (stub implementation)
696 *
697 * @param all_iterations_data Not used.
698 *
699 **/
verifyResultData(const void ** all_iterations_data)700 void TessellationShaderInvarianceBaseTest::verifyResultData(const void **all_iterations_data)
701 {
702 DE_UNREF(all_iterations_data);
703
704 /* Do nothing - this is just a stub. */
705 }
706
707 /** Constructor.
708 *
709 * @param context Rendering context.
710 *
711 **/
TessellationShaderInvarianceRule1Test(Context & context,const ExtParameters & extParams)712 TessellationShaderInvarianceRule1Test::TessellationShaderInvarianceRule1Test(Context &context,
713 const ExtParameters &extParams)
714 : TessellationShaderInvarianceBaseTest(context, extParams, "invariance_rule1",
715 "Verifies conformance with first invariance rule")
716 {
717 /* Left blank intentionally */
718 }
719
720 /** Destructor. */
~TessellationShaderInvarianceRule1Test()721 TessellationShaderInvarianceRule1Test::~TessellationShaderInvarianceRule1Test()
722 {
723 /* Left blank intentionally */
724 }
725
726 /** Retrieves amount of iterations the base test implementation should run before
727 * calling global verification routine.
728 *
729 * @return Always 6.
730 **/
getAmountOfIterations()731 unsigned int TessellationShaderInvarianceRule1Test::getAmountOfIterations()
732 {
733 return 6;
734 }
735
736 /** Returns a value that should be used for the draw call's "count" argument.
737 *
738 * @param Always 3
739 **/
getDrawCallCountArgument()740 unsigned int TessellationShaderInvarianceRule1Test::getDrawCallCountArgument()
741 {
742 return 3;
743 }
744
745 /** Retrieves iteration-specific tessellation properties.
746 *
747 * @param n_iteration Iteration index to retrieve the properties for.
748 * @param out_inner_tess_levels Deref will be used to store iteration-specific inner
749 * tessellation level values. Must not be NULL.
750 * @param out_outer_tess_levels Deref will be used to store iteration-specific outer
751 * tessellation level values. Must not be NULL.
752 * @param out_point_mode Deref will be used to store iteration-specific flag
753 * telling whether point mode should be enabled for given pass.
754 * Must not be NULL.
755 * @param out_primitive_mode Deref will be used to store iteration-specific primitive
756 * mode. Must not be NULL.
757 * @param out_vertex_ordering Deref will be used to store iteration-specific vertex ordering.
758 * Must not be NULL.
759 * @param out_result_buffer_size Deref will be used to store amount of bytes XFB buffer object
760 * storage should offer for the draw call to succeed. Must not
761 * be NULL.
762 **/
getIterationProperties(unsigned int n_iteration,float * out_inner_tess_levels,float * out_outer_tess_levels,bool * out_point_mode,_tessellation_primitive_mode * out_primitive_mode,_tessellation_shader_vertex_ordering * out_vertex_ordering,unsigned int * out_result_buffer_size)763 void TessellationShaderInvarianceRule1Test::getIterationProperties(
764 unsigned int n_iteration, float *out_inner_tess_levels, float *out_outer_tess_levels, bool *out_point_mode,
765 _tessellation_primitive_mode *out_primitive_mode, _tessellation_shader_vertex_ordering *out_vertex_ordering,
766 unsigned int *out_result_buffer_size)
767 {
768 *out_vertex_ordering = TESSELLATION_SHADER_VERTEX_ORDERING_CCW;
769
770 switch (n_iteration)
771 {
772 case 0:
773 case 5:
774 {
775 /* Triangles (point mode) */
776 out_inner_tess_levels[0] = 1.0f;
777 out_outer_tess_levels[0] = 1.0f;
778 out_outer_tess_levels[1] = 1.0f;
779 out_outer_tess_levels[2] = 1.0f;
780
781 *out_point_mode = true;
782 *out_primitive_mode = TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES;
783
784 break;
785 }
786
787 case 1:
788 case 3:
789 {
790 /* Lines */
791 out_outer_tess_levels[0] = 1.0f;
792 out_outer_tess_levels[1] = 1.0f;
793
794 *out_point_mode = false;
795 *out_primitive_mode = TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES;
796
797 break;
798 }
799
800 case 2:
801 case 4:
802 {
803 /* Triangles */
804 out_inner_tess_levels[0] = 1.0f;
805 out_outer_tess_levels[0] = 1.0f;
806 out_outer_tess_levels[1] = 1.0f;
807 out_outer_tess_levels[2] = 1.0f;
808
809 *out_point_mode = false;
810 *out_primitive_mode = TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES;
811
812 break;
813 }
814
815 default:
816 {
817 TCU_FAIL("Unrecognzied iteration index");
818 }
819 }
820
821 *out_result_buffer_size = m_utils_ptr->getAmountOfVerticesGeneratedByTessellator(
822 *out_primitive_mode, out_inner_tess_levels, out_outer_tess_levels, TESSELLATION_SHADER_VERTEX_SPACING_EQUAL,
823 *out_point_mode);
824
825 *out_result_buffer_size = static_cast<unsigned int>(*out_result_buffer_size * getDrawCallCountArgument() *
826 3 /* components */ * sizeof(float));
827
828 DE_ASSERT(*out_result_buffer_size != 0);
829 }
830
831 /** Retrieves iteration-specific tessellation evaluation shader code.
832 *
833 * @param n_iteration Iteration index, for which the source code is being obtained.
834 *
835 * @return Requested source code.
836 **/
getTECode(unsigned int n_iteration)837 std::string TessellationShaderInvarianceRule1Test::getTECode(unsigned int n_iteration)
838 {
839 unsigned int bo_size = 0;
840 float inner_tess_levels[2] = {0};
841 float outer_tess_levels[4] = {0};
842 bool point_mode = false;
843 _tessellation_primitive_mode primitive_mode = TESSELLATION_SHADER_PRIMITIVE_MODE_UNKNOWN;
844 _tessellation_shader_vertex_ordering vertex_ordering = TESSELLATION_SHADER_VERTEX_ORDERING_UNKNOWN;
845
846 getIterationProperties(n_iteration, inner_tess_levels, outer_tess_levels, &point_mode, &primitive_mode,
847 &vertex_ordering, &bo_size);
848
849 return TessellationShaderUtils::getGenericTECode(TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, primitive_mode,
850 vertex_ordering, point_mode);
851 }
852
853 /** Verifies result data. Accesses data generated by all iterations.
854 *
855 * Throws TestError exception if an error occurs.
856 *
857 * @param all_iterations_data An array of pointers to buffers, holding gl_TessCoord
858 * data generated by subsequent iterations.
859 **/
verifyResultData(const void ** all_iterations_data)860 void TessellationShaderInvarianceRule1Test::verifyResultData(const void **all_iterations_data)
861 {
862 const float *lines_vertex_data_1 = (const float *)all_iterations_data[1];
863 const float *lines_vertex_data_2 = (const float *)all_iterations_data[3];
864 const float *point_vertex_data_1 = (const float *)all_iterations_data[0];
865 const float *point_vertex_data_2 = (const float *)all_iterations_data[5];
866 const float *tris_vertex_data_1 = (const float *)all_iterations_data[2];
867 const float *tris_vertex_data_2 = (const float *)all_iterations_data[4];
868
869 const unsigned int n_line_vertices = 2 /* vertices per line segment */ * getDrawCallCountArgument(); /* lines */
870 const unsigned int n_point_vertices = 1 /* vertices per point */ * getDrawCallCountArgument(); /* points */
871 const unsigned int n_tri_vertices = 3 /* vertices per triangle */ * getDrawCallCountArgument(); /* triangles */
872 const unsigned int vertex_size = sizeof(float) * 3; /* components */
873
874 /* Make sure the data sets match, given different draw call ordering */
875 for (int n_type = 0; n_type < 3 /* lines, points, tris */; ++n_type)
876 {
877 const float *data1_ptr = DE_NULL;
878 const float *data2_ptr = DE_NULL;
879 std::string data_type_string;
880 unsigned int n_vertices = 0;
881
882 switch (n_type)
883 {
884 case 0:
885 {
886 data1_ptr = lines_vertex_data_1;
887 data2_ptr = lines_vertex_data_2;
888 data_type_string = "Line";
889 n_vertices = n_line_vertices;
890
891 break;
892 }
893
894 case 1:
895 {
896 data1_ptr = point_vertex_data_1;
897 data2_ptr = point_vertex_data_2;
898 data_type_string = "Point";
899 n_vertices = n_point_vertices;
900
901 break;
902 }
903
904 case 2:
905 {
906 data1_ptr = tris_vertex_data_1;
907 data2_ptr = tris_vertex_data_2;
908 data_type_string = "Triangle";
909 n_vertices = n_tri_vertices;
910
911 break;
912 }
913
914 default:
915 {
916 TCU_FAIL("Internal error: type index was not recognized");
917 }
918 } /* switch (n_type) */
919
920 /* Make sure the buffer storage in both cases has been modified */
921 {
922 unsigned int zero_bo_size = vertex_size * n_vertices;
923 char *zero_bo_data = new char[vertex_size * n_vertices];
924
925 memset(zero_bo_data, 0, zero_bo_size);
926
927 if (memcmp(data1_ptr, zero_bo_data, zero_bo_size) == 0 ||
928 memcmp(data2_ptr, zero_bo_data, zero_bo_size) == 0)
929 {
930 TCU_FAIL("One of the draw calls has not outputted any data to XFB buffer object storage");
931 }
932
933 delete[] zero_bo_data;
934 zero_bo_data = NULL;
935 }
936
937 /* Compare the data */
938 if (memcmp(data1_ptr, data2_ptr, vertex_size * n_vertices) != 0)
939 {
940 std::stringstream logMessage;
941
942 logMessage << data_type_string << " data rendered in pass 1: (";
943
944 for (unsigned int n_vertex = 0; n_vertex < n_vertices; ++n_vertex)
945 {
946 logMessage << data1_ptr[n_vertex];
947
948 if (n_vertex != (n_vertices - 1))
949 {
950 logMessage << ", ";
951 }
952 else
953 {
954 logMessage << ") ";
955 }
956 } /* for (all vertices) */
957
958 logMessage << "and in pass 2: (";
959
960 for (unsigned int n_vertex = 0; n_vertex < n_vertices; ++n_vertex)
961 {
962 logMessage << data2_ptr[n_vertex];
963
964 if (n_vertex != (n_vertices - 1))
965 {
966 logMessage << ", ";
967 }
968 else
969 {
970 logMessage << ") ";
971 }
972 } /* for (all vertices) */
973
974 logMessage << "do not match";
975
976 m_testCtx.getLog() << tcu::TestLog::Message << logMessage.str().c_str() << tcu::TestLog::EndMessage;
977
978 TCU_FAIL("Data mismatch");
979 } /* if (data mismatch) */
980 } /* for (all primitive types) */
981 }
982
983 /** Constructor.
984 *
985 * @param context Rendering context.
986 *
987 **/
TessellationShaderInvarianceRule2Test(Context & context,const ExtParameters & extParams)988 TessellationShaderInvarianceRule2Test::TessellationShaderInvarianceRule2Test(Context &context,
989 const ExtParameters &extParams)
990 : TessellationShaderInvarianceBaseTest(context, extParams, "invariance_rule2",
991 "Verifies conformance with second invariance rule")
992 {
993 memset(m_n_tessellated_vertices, 0, sizeof(m_n_tessellated_vertices));
994 }
995
996 /** Destructor. */
~TessellationShaderInvarianceRule2Test()997 TessellationShaderInvarianceRule2Test::~TessellationShaderInvarianceRule2Test()
998 {
999 /* Left blank intentionally */
1000 }
1001
1002 /** Retrieves amount of iterations the base test implementation should run before
1003 * calling global verification routine.
1004 *
1005 * @return Always 4.
1006 **/
getAmountOfIterations()1007 unsigned int TessellationShaderInvarianceRule2Test::getAmountOfIterations()
1008 {
1009 return 4;
1010 }
1011
1012 /** Retrieves iteration-specific tessellation properties.
1013 *
1014 * @param n_iteration Iteration index to retrieve the properties for.
1015 * @param out_inner_tess_levels Deref will be used to store iteration-specific inner
1016 * tessellation level values. Must not be NULL.
1017 * @param out_outer_tess_levels Deref will be used to store iteration-specific outer
1018 * tessellation level values. Must not be NULL.
1019 * @param out_point_mode Deref will be used to store iteration-specific flag
1020 * telling whether point mode should be enabled for given pass.
1021 * Must not be NULL.
1022 * @param out_primitive_mode Deref will be used to store iteration-specific primitive
1023 * mode. Must not be NULL.
1024 * @param out_vertex_ordering Deref will be used to store iteration-specific vertex
1025 * ordering. Must not be NULL.
1026 * @param out_result_buffer_size Deref will be used to store amount of bytes XFB buffer object
1027 * storage should offer for the draw call to succeed. Can
1028 * be NULL.
1029 **/
getIterationProperties(unsigned int n_iteration,float * out_inner_tess_levels,float * out_outer_tess_levels,bool * out_point_mode,_tessellation_primitive_mode * out_primitive_mode,_tessellation_shader_vertex_ordering * out_vertex_ordering,unsigned int * out_result_buffer_size)1030 void TessellationShaderInvarianceRule2Test::getIterationProperties(
1031 unsigned int n_iteration, float *out_inner_tess_levels, float *out_outer_tess_levels, bool *out_point_mode,
1032 _tessellation_primitive_mode *out_primitive_mode, _tessellation_shader_vertex_ordering *out_vertex_ordering,
1033 unsigned int *out_result_buffer_size)
1034 {
1035 *out_vertex_ordering = TESSELLATION_SHADER_VERTEX_ORDERING_CCW;
1036
1037 switch (n_iteration)
1038 {
1039 case 0:
1040 case 1:
1041 {
1042 /* Triangles */
1043 out_outer_tess_levels[0] = 2.0f;
1044 out_outer_tess_levels[1] = 3.0f;
1045 out_outer_tess_levels[2] = 4.0f;
1046
1047 if (n_iteration == 0)
1048 {
1049 out_inner_tess_levels[0] = 4.0f;
1050 out_inner_tess_levels[1] = 5.0f;
1051 }
1052 else
1053 {
1054 out_inner_tess_levels[0] = 3.0f;
1055 out_inner_tess_levels[1] = 4.0f;
1056 }
1057
1058 *out_point_mode = false;
1059 *out_primitive_mode = TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES;
1060
1061 break;
1062 }
1063
1064 case 2:
1065 case 3:
1066 {
1067 /* Quads */
1068 out_outer_tess_levels[0] = 2.0f;
1069 out_outer_tess_levels[1] = 3.0f;
1070 out_outer_tess_levels[2] = 4.0f;
1071 out_outer_tess_levels[3] = 5.0f;
1072
1073 if (n_iteration == 2)
1074 {
1075 out_inner_tess_levels[0] = 2.0f;
1076 out_inner_tess_levels[1] = 3.0f;
1077 }
1078 else
1079 {
1080 out_inner_tess_levels[0] = 4.0f;
1081 out_inner_tess_levels[1] = 5.0f;
1082 }
1083
1084 *out_point_mode = false;
1085 *out_primitive_mode = TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS;
1086
1087 break;
1088 }
1089
1090 default:
1091 {
1092 TCU_FAIL("Unrecognized iteration index");
1093 }
1094 }
1095
1096 if (out_result_buffer_size != DE_NULL)
1097 {
1098 *out_result_buffer_size = m_utils_ptr->getAmountOfVerticesGeneratedByTessellator(
1099 *out_primitive_mode, out_inner_tess_levels, out_outer_tess_levels, TESSELLATION_SHADER_VERTEX_SPACING_EQUAL,
1100 *out_point_mode);
1101
1102 m_n_tessellated_vertices[n_iteration] = *out_result_buffer_size;
1103 *out_result_buffer_size =
1104 static_cast<unsigned int>(*out_result_buffer_size * 3 /* components */ * sizeof(float));
1105
1106 DE_ASSERT(*out_result_buffer_size != 0);
1107 }
1108 }
1109
1110 /** Retrieves iteration-specific tessellation evaluation shader code.
1111 *
1112 * @param n_iteration Iteration index, for which the source code is being obtained.
1113 *
1114 * @return Requested source code.
1115 **/
getTECode(unsigned int n_iteration)1116 std::string TessellationShaderInvarianceRule2Test::getTECode(unsigned int n_iteration)
1117 {
1118 unsigned int bo_size = 0;
1119 float inner_tess_levels[2] = {0};
1120 float outer_tess_levels[4] = {0};
1121 bool point_mode = false;
1122 _tessellation_primitive_mode primitive_mode = TESSELLATION_SHADER_PRIMITIVE_MODE_UNKNOWN;
1123 _tessellation_shader_vertex_ordering vertex_ordering = TESSELLATION_SHADER_VERTEX_ORDERING_UNKNOWN;
1124
1125 getIterationProperties(n_iteration, inner_tess_levels, outer_tess_levels, &point_mode, &primitive_mode,
1126 &vertex_ordering, &bo_size);
1127
1128 return TessellationShaderUtils::getGenericTECode(TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, primitive_mode,
1129 vertex_ordering, point_mode);
1130 }
1131
1132 /** Verifies result data. Accesses data generated by all iterations.
1133 *
1134 * Throws TestError exception if an error occurs.
1135 *
1136 * @param all_iterations_data An array of pointers to buffers, holding gl_TessCoord
1137 * data generated by subsequent iterations.
1138 **/
verifyResultData(const void ** all_iterations_data)1139 void TessellationShaderInvarianceRule2Test::verifyResultData(const void **all_iterations_data)
1140 {
1141 /* Iterate through one tessellated set of vertices for a given primitive type
1142 * and identify outer vertices. Make sure exactly the same vertices can be
1143 * found in the other set of vertices, generated with different input tessellation
1144 * level.
1145 */
1146 for (int n_primitive_type = 0; n_primitive_type < 2; /* triangles / quads */
1147 ++n_primitive_type)
1148 {
1149 const float *data1_ptr = (const float *)all_iterations_data[n_primitive_type * 2 + 0];
1150 const float *data2_ptr = (const float *)all_iterations_data[n_primitive_type * 2 + 1];
1151 _tessellation_primitive_mode primitive_mode = (n_primitive_type == 0) ?
1152 TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES :
1153 TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS;
1154 std::vector<_vertex> outer_vertices;
1155
1156 /* Iterate through all data1 vertices.. */
1157 for (unsigned int n_vertex = 0; n_vertex < m_n_tessellated_vertices[n_primitive_type * 2]; ++n_vertex)
1158 {
1159 /* Check if any of the components is equal to 0 or 1. If so, this could
1160 * be an edge vertex.
1161 */
1162 const float *vertex_ptr = data1_ptr + n_vertex * 3; /* components */
1163
1164 if (TessellationShaderUtils::isOuterEdgeVertex(primitive_mode, vertex_ptr))
1165 {
1166 /* Only add the vertex if it has not been added already to the vector */
1167 bool has_already_been_added = false;
1168
1169 for (std::vector<_vertex>::const_iterator vertex_iterator = outer_vertices.begin();
1170 vertex_iterator != outer_vertices.end(); vertex_iterator++)
1171 {
1172 if (vertex_iterator->u == vertex_ptr[0] && vertex_iterator->v == vertex_ptr[1] &&
1173 vertex_iterator->w == vertex_ptr[2])
1174 {
1175 has_already_been_added = true;
1176
1177 break;
1178 }
1179 } /* for (all outer vertices stored so far) */
1180
1181 if (!has_already_been_added)
1182 {
1183 _vertex vertex;
1184
1185 vertex.u = vertex_ptr[0];
1186 vertex.v = vertex_ptr[1];
1187 vertex.w = vertex_ptr[2];
1188
1189 outer_vertices.push_back(vertex);
1190 }
1191 } /* if (input vertex is located on outer edge) */
1192 } /* for (all input vertices) */
1193
1194 DE_ASSERT(outer_vertices.size() != 0);
1195
1196 /* Now that we know where outer vertices are, make sure they are present in the other data set */
1197 for (std::vector<_vertex>::const_iterator ref_vertex_iterator = outer_vertices.begin();
1198 ref_vertex_iterator != outer_vertices.end(); ref_vertex_iterator++)
1199 {
1200 bool has_been_found = false;
1201 const _vertex &ref_vertex = *ref_vertex_iterator;
1202
1203 for (unsigned int n_vertex = 0; n_vertex < m_n_tessellated_vertices[n_primitive_type * 2 + 1]; ++n_vertex)
1204 {
1205 const float *vertex_ptr = data2_ptr + n_vertex * 3; /* components */
1206
1207 if (vertex_ptr[0] == ref_vertex.u && vertex_ptr[1] == ref_vertex.v && vertex_ptr[2] == ref_vertex.w)
1208 {
1209 has_been_found = true;
1210
1211 break;
1212 }
1213 } /* for (all vertices in the other data set) */
1214
1215 if (!has_been_found)
1216 {
1217 float cmp_inner_tess_levels[2];
1218 float cmp_outer_tess_levels[4];
1219 bool cmp_point_mode;
1220 _tessellation_primitive_mode cmp_primitive_mode;
1221 _tessellation_shader_vertex_ordering cmp_vertex_ordering;
1222 std::string primitive_type = (n_primitive_type == 0) ? "triangles" : "quads";
1223 float ref_inner_tess_levels[2];
1224 float ref_outer_tess_levels[4];
1225 bool ref_point_mode;
1226 _tessellation_primitive_mode ref_primitive_mode;
1227 _tessellation_shader_vertex_ordering ref_vertex_ordering;
1228
1229 getIterationProperties(n_primitive_type * 2, ref_inner_tess_levels, ref_outer_tess_levels,
1230 &ref_point_mode, &ref_primitive_mode, &ref_vertex_ordering, NULL);
1231 getIterationProperties(n_primitive_type * 2 + 1, cmp_inner_tess_levels, cmp_outer_tess_levels,
1232 &cmp_point_mode, &cmp_primitive_mode, &cmp_vertex_ordering, NULL);
1233
1234 m_testCtx.getLog() << tcu::TestLog::Message << "Outer vertex"
1235 << " (" << ref_vertex.u << ", " << ref_vertex.v << ", " << ref_vertex.w << ")"
1236 << " was not found in tessellated data coordinate set generated"
1237 << " for primitive type: " << primitive_type.c_str()
1238 << ". Reference inner tessellation level:"
1239 << " (" << ref_inner_tess_levels[0] << ", " << ref_inner_tess_levels[1]
1240 << "), reference outer tessellation level:"
1241 << " (" << ref_outer_tess_levels[0] << ", " << ref_outer_tess_levels[1] << ", "
1242 << ref_outer_tess_levels[2] << ", " << ref_outer_tess_levels[3]
1243 << "), test inner tessellation level:"
1244 << " (" << cmp_inner_tess_levels[0] << ", " << cmp_inner_tess_levels[1]
1245 << "), reference outer tessellation level:"
1246 << " (" << cmp_outer_tess_levels[0] << ", " << cmp_outer_tess_levels[1] << ", "
1247 << cmp_outer_tess_levels[2] << ", " << cmp_outer_tess_levels[3] << ")."
1248 << tcu::TestLog::EndMessage;
1249
1250 TCU_FAIL("Outer edge vertex was not found in tessellated coordinate set generated for "
1251 "the same outer tessellation levels and vertex spacing, but different inner "
1252 "tessellation levels");
1253 } /* if (outer edge vertex was not found in the other set) */
1254 } /* for (all outer edge vertices) */
1255 } /* for (both primitive types) */
1256 }
1257
1258 /** Constructor.
1259 *
1260 * @param context Rendering context.
1261 *
1262 **/
TessellationShaderInvarianceRule3Test(Context & context,const ExtParameters & extParams)1263 TessellationShaderInvarianceRule3Test::TessellationShaderInvarianceRule3Test(Context &context,
1264 const ExtParameters &extParams)
1265 : TessellationShaderInvarianceBaseTest(context, extParams, "invariance_rule3",
1266 "Verifies conformance with third invariance rule")
1267 {
1268 }
1269
1270 /** Destructor. */
~TessellationShaderInvarianceRule3Test()1271 TessellationShaderInvarianceRule3Test::~TessellationShaderInvarianceRule3Test()
1272 {
1273 /* Left blank intentionally */
1274 }
1275
1276 /** Retrieves amount of iterations the base test implementation should run before
1277 * calling global verification routine.
1278 *
1279 * @return A value that depends on initTestIterations() behavior.
1280 **/
getAmountOfIterations()1281 unsigned int TessellationShaderInvarianceRule3Test::getAmountOfIterations()
1282 {
1283 if (m_test_iterations.size() == 0)
1284 {
1285 initTestIterations();
1286 }
1287
1288 return (unsigned int)m_test_iterations.size();
1289 }
1290
1291 /** Retrieves iteration-specific tessellation properties.
1292 *
1293 * @param n_iteration Iteration index to retrieve the properties for.
1294 * @param out_inner_tess_levels Deref will be used to store iteration-specific inner
1295 * tessellation level values. Must not be NULL.
1296 * @param out_outer_tess_levels Deref will be used to store iteration-specific outer
1297 * tessellation level values. Must not be NULL.
1298 * @param out_point_mode Deref will be used to store iteration-specific flag
1299 * telling whether point mode should be enabled for given pass.
1300 * Must not be NULL.
1301 * @param out_primitive_mode Deref will be used to store iteration-specific primitive
1302 * mode. Must not be NULL.
1303 * @param out_vertex_ordering Deref will be used to store iteration-specific vertex
1304 * ordering. Must not be NULL.
1305 * @param out_result_buffer_size Deref will be used to store amount of bytes XFB buffer object
1306 * storage should offer for the draw call to succeed. Can
1307 * be NULL.
1308 **/
getIterationProperties(unsigned int n_iteration,float * out_inner_tess_levels,float * out_outer_tess_levels,bool * out_point_mode,_tessellation_primitive_mode * out_primitive_mode,_tessellation_shader_vertex_ordering * out_vertex_ordering,unsigned int * out_result_buffer_size)1309 void TessellationShaderInvarianceRule3Test::getIterationProperties(
1310 unsigned int n_iteration, float *out_inner_tess_levels, float *out_outer_tess_levels, bool *out_point_mode,
1311 _tessellation_primitive_mode *out_primitive_mode, _tessellation_shader_vertex_ordering *out_vertex_ordering,
1312 unsigned int *out_result_buffer_size)
1313 {
1314 DE_ASSERT(m_test_iterations.size() > n_iteration);
1315
1316 _test_iteration &test_iteration = m_test_iterations[n_iteration];
1317
1318 memcpy(out_inner_tess_levels, test_iteration.inner_tess_levels, sizeof(test_iteration.inner_tess_levels));
1319 memcpy(out_outer_tess_levels, test_iteration.outer_tess_levels, sizeof(test_iteration.outer_tess_levels));
1320
1321 *out_point_mode = false;
1322 *out_primitive_mode = test_iteration.primitive_mode;
1323 *out_vertex_ordering = TESSELLATION_SHADER_VERTEX_ORDERING_CCW;
1324
1325 if (out_result_buffer_size != DE_NULL)
1326 {
1327 *out_result_buffer_size = m_utils_ptr->getAmountOfVerticesGeneratedByTessellator(
1328 *out_primitive_mode, out_inner_tess_levels, out_outer_tess_levels, test_iteration.vertex_spacing,
1329 *out_point_mode);
1330 test_iteration.n_vertices = *out_result_buffer_size;
1331 *out_result_buffer_size =
1332 static_cast<unsigned int>(*out_result_buffer_size * 3 /* components */ * sizeof(float));
1333
1334 DE_ASSERT(*out_result_buffer_size != 0);
1335 }
1336 }
1337
1338 /** Retrieves iteration-specific tessellation evaluation shader code.
1339 *
1340 * @param n_iteration Iteration index, for which the source code is being obtained.
1341 *
1342 * @return Requested source code.
1343 **/
getTECode(unsigned int n_iteration)1344 std::string TessellationShaderInvarianceRule3Test::getTECode(unsigned int n_iteration)
1345 {
1346 DE_ASSERT(m_test_iterations.size() > n_iteration);
1347
1348 const _test_iteration &test_iteration = m_test_iterations[n_iteration];
1349
1350 return TessellationShaderUtils::getGenericTECode(test_iteration.vertex_spacing, test_iteration.primitive_mode,
1351 TESSELLATION_SHADER_VERTEX_ORDERING_CCW, false); /* point mode */
1352 }
1353
1354 /** Initializes test iterations for the test. The following modes and inner/outer tess level
1355 * configurations are used to form the test set:
1356 *
1357 * - Inner/outer tessellation level combinations as returned by
1358 * TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode()
1359 * - All primitive modes;
1360 * - All vertex spacing modes;
1361 *
1362 * All permutations are used to generate the test set.
1363 **/
initTestIterations()1364 void TessellationShaderInvarianceRule3Test::initTestIterations()
1365 {
1366 DE_ASSERT(m_test_iterations.size() == 0);
1367
1368 /* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value */
1369 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1370 glw::GLint gl_max_tess_gen_level_value = 0;
1371
1372 gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value);
1373 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_GEN_LEVEL_EXT pname");
1374
1375 /* Iterate through all primitive and vertex spacing modes */
1376 _tessellation_primitive_mode primitive_modes[] = {TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES,
1377 TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS,
1378 TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES};
1379 _tessellation_shader_vertex_spacing vs_modes[] = {TESSELLATION_SHADER_VERTEX_SPACING_EQUAL,
1380 TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_EVEN,
1381 TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD};
1382
1383 const unsigned int n_primitive_modes = sizeof(primitive_modes) / sizeof(primitive_modes[0]);
1384 const unsigned int n_vs_modes = sizeof(vs_modes) / sizeof(vs_modes[0]);
1385
1386 for (unsigned int n_primitive_mode = 0; n_primitive_mode < n_primitive_modes; ++n_primitive_mode)
1387 {
1388 _tessellation_primitive_mode primitive_mode = primitive_modes[n_primitive_mode];
1389
1390 for (unsigned int n_vs_mode = 0; n_vs_mode < n_vs_modes; ++n_vs_mode)
1391 {
1392 _tessellation_shader_vertex_spacing vs_mode = vs_modes[n_vs_mode];
1393
1394 /* Retrieve inner/outer tessellation level combinations we want the tests to be run for */
1395 _tessellation_levels_set levels_set;
1396
1397 levels_set = TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode(
1398 primitive_mode, gl_max_tess_gen_level_value,
1399 TESSELLATION_LEVEL_SET_FILTER_ALL_LEVELS_USE_THE_SAME_VALUE);
1400
1401 /* Iterate through all configurations */
1402 for (_tessellation_levels_set_const_iterator levels_iterator = levels_set.begin();
1403 levels_iterator != levels_set.end(); levels_iterator++)
1404 {
1405 const _tessellation_levels &levels = *levels_iterator;
1406
1407 /* Create a test descriptor for all the parameters we now have */
1408 _test_iteration test;
1409
1410 memcpy(test.inner_tess_levels, levels.inner, sizeof(test.inner_tess_levels));
1411 memcpy(test.outer_tess_levels, levels.outer, sizeof(test.outer_tess_levels));
1412
1413 test.primitive_mode = primitive_mode;
1414 test.vertex_spacing = vs_mode;
1415
1416 m_test_iterations.push_back(test);
1417 } /* for (all inner/outer tessellation levels) */
1418 } /* for (all vertex spacing modes) */
1419 } /* for (all primitive modes) */
1420 }
1421
1422 /** Verifies result data on per-iteration basis.
1423 *
1424 * Throws TestError exception if an error occurs.
1425 *
1426 * @param n_iteration Index of iteration the check should be performed for.
1427 * @param data Points to array of vec3s storing the vertices as
1428 * generated by tessellation
1429 **/
verifyResultDataForIteration(unsigned int n_iteration,const void * data)1430 void TessellationShaderInvarianceRule3Test::verifyResultDataForIteration(unsigned int n_iteration, const void *data)
1431 {
1432 DE_ASSERT(m_test_iterations.size() > n_iteration);
1433
1434 const glw::GLfloat *data_float = (const glw::GLfloat *)data;
1435 const _test_iteration &test_iteration = m_test_iterations[n_iteration];
1436
1437 /* Iterate through all generated vertices.. */
1438 for (unsigned int n_vertex = 0; n_vertex < test_iteration.n_vertices; ++n_vertex)
1439 {
1440 _vertex expected_vertex;
1441 const glw::GLfloat *vertex_data = data_float + 3 /* components */ * n_vertex;
1442
1443 expected_vertex.u = -1.0f;
1444 expected_vertex.v = -1.0f;
1445 expected_vertex.w = -1.0f;
1446
1447 /* Make sure that for each vertex, the following language from the extension
1448 * spec is followed:
1449 */
1450 switch (test_iteration.primitive_mode)
1451 {
1452 case TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES:
1453 {
1454 /* For isoline tessellation, if it generates vertices at (0,x) and (1,x)
1455 * where <x> is not zero, it will also generate vertices at exactly (0,1-x)
1456 * and (1,1-x), respectively.
1457 */
1458 if (vertex_data[0] == 0.0f && vertex_data[1] != 0.0f)
1459 {
1460 expected_vertex.u = vertex_data[0];
1461 expected_vertex.v = 1.0f - vertex_data[1];
1462 expected_vertex.w = -1.0f;
1463 }
1464 else if (vertex_data[0] == 1.0f && vertex_data[1] != 0.0f)
1465 {
1466 expected_vertex.u = vertex_data[0];
1467 expected_vertex.v = 1.0f - vertex_data[1];
1468 expected_vertex.w = -1.0f;
1469 }
1470
1471 break;
1472 } /* case TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES: */
1473
1474 case TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS:
1475 {
1476 /* For quad tessellation, if the subdivision generates a vertex with
1477 * coordinates of (x,0) or (0,x), it will also generate a vertex with
1478 * coordinates of exactly (1-x,0) or (0,1-x), respectively.
1479 */
1480 if (vertex_data[0] != 0.0f && vertex_data[1] == 0.0f)
1481 {
1482 expected_vertex.u = 1.0f - vertex_data[0];
1483 expected_vertex.v = vertex_data[1];
1484 expected_vertex.w = -1.0f;
1485 }
1486 else if (vertex_data[0] == 0.0f && vertex_data[1] != 0.0f)
1487 {
1488 expected_vertex.u = vertex_data[0];
1489 expected_vertex.v = 1.0f - vertex_data[1];
1490 expected_vertex.w = -1.0f;
1491 }
1492
1493 break;
1494 } /* case TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS: */
1495
1496 case TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES:
1497 {
1498 /* For triangle tessellation, if the subdivision generates a vertex with
1499 * tessellation coordinates of the form (0,x,1-x), (x,0,1-x), or (x,1-x,0),
1500 * it will also generate a vertex with coordinates of exactly (0,1-x,x),
1501 * (1-x,0,x), or (1-x,x,0), respectively.
1502 */
1503 if (vertex_data[0] == 0.0f && vertex_data[1] != 0.0f && vertex_data[2] == (1.0f - vertex_data[1]))
1504 {
1505 expected_vertex.u = vertex_data[0];
1506 expected_vertex.v = vertex_data[2];
1507 expected_vertex.w = vertex_data[1];
1508 }
1509 else if (vertex_data[0] != 0.0f && vertex_data[1] == 0.0f && vertex_data[2] == (1.0f - vertex_data[0]))
1510 {
1511 expected_vertex.u = vertex_data[2];
1512 expected_vertex.v = vertex_data[1];
1513 expected_vertex.w = vertex_data[0];
1514 }
1515 else if (vertex_data[0] != 0.0f && vertex_data[1] == (1.0f - vertex_data[0]) && vertex_data[2] == 0.0f)
1516 {
1517 expected_vertex.u = vertex_data[1];
1518 expected_vertex.v = vertex_data[0];
1519 expected_vertex.w = vertex_data[2];
1520 }
1521
1522 break;
1523 } /* case TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES: */
1524
1525 default:
1526 {
1527 TCU_FAIL("Primitive mode unrecognized");
1528 }
1529 } /* switch (test_iteration.primitive_mode) */
1530
1531 /* If any of the "expected vertex"'s components is no longer negative,
1532 * make sure the vertex can be found in the result data */
1533 if (expected_vertex.u >= 0.0f || expected_vertex.v >= 0.0f || expected_vertex.w >= 0.0f)
1534 {
1535 bool has_been_found = false;
1536
1537 for (unsigned int n_find_vertex = 0; n_find_vertex < test_iteration.n_vertices; ++n_find_vertex)
1538 {
1539 const glw::GLfloat *current_vertex_data = data_float + 3 /* components */ * n_find_vertex;
1540
1541 const glw::GLfloat epsilon = 1e-4f;
1542 glw::GLfloat absDelta[3] = {de::abs(current_vertex_data[0] - expected_vertex.u),
1543 de::abs(current_vertex_data[1] - expected_vertex.v),
1544 de::abs(current_vertex_data[2] - expected_vertex.w)};
1545
1546 if (absDelta[0] < epsilon && absDelta[1] < epsilon &&
1547 ((expected_vertex.w < 0.0f) || (expected_vertex.w >= 0.0f && absDelta[2] < epsilon)))
1548 {
1549 has_been_found = true;
1550
1551 break;
1552 } /* if (the vertex data matches the expected vertex data) */
1553 } /* for (all generated vertices)*/
1554
1555 if (!has_been_found)
1556 {
1557 TCU_FAIL("Expected symmetrical vertex data was not generated by the tessellator.");
1558 }
1559 } /* if (any of the components of expected_vertex is no longer negative) */
1560 } /* for (all generated vertices) */
1561 }
1562
1563 /** Constructor.
1564 *
1565 * @param context Rendering context.
1566 *
1567 **/
TessellationShaderInvarianceRule4Test(Context & context,const ExtParameters & extParams)1568 TessellationShaderInvarianceRule4Test::TessellationShaderInvarianceRule4Test(Context &context,
1569 const ExtParameters &extParams)
1570 : TessellationShaderInvarianceBaseTest(context, extParams, "invariance_rule4",
1571 "Verifies conformance with fourth invariance rule")
1572 {
1573 }
1574
1575 /** Destructor. */
~TessellationShaderInvarianceRule4Test()1576 TessellationShaderInvarianceRule4Test::~TessellationShaderInvarianceRule4Test()
1577 {
1578 /* Left blank intentionally */
1579 }
1580
1581 /** Retrieves amount of iterations the base test implementation should run before
1582 * calling global verification routine.
1583 *
1584 * @return A value that depends on initTestIterations() behavior.
1585 **/
getAmountOfIterations()1586 unsigned int TessellationShaderInvarianceRule4Test::getAmountOfIterations()
1587 {
1588 if (m_test_iterations.size() == 0)
1589 {
1590 initTestIterations();
1591 }
1592
1593 return (unsigned int)m_test_iterations.size();
1594 }
1595
1596 /** Retrieves iteration-specific tessellation properties.
1597 *
1598 * @param n_iteration Iteration index to retrieve the properties for.
1599 * @param out_inner_tess_levels Deref will be used to store iteration-specific inner
1600 * tessellation level values. Must not be NULL.
1601 * @param out_outer_tess_levels Deref will be used to store iteration-specific outer
1602 * tessellation level values. Must not be NULL.
1603 * @param out_point_mode Deref will be used to store iteration-specific flag
1604 * telling whether point mode should be enabled for given pass.
1605 * Must not be NULL.
1606 * @param out_primitive_mode Deref will be used to store iteration-specific primitive
1607 * mode. Must not be NULL.
1608 * @param out_vertex_ordering Deref will be used to store iteration-specific vertex
1609 * ordering. Must not be NULL.
1610 * @param out_result_buffer_size Deref will be used to store amount of bytes XFB buffer object
1611 * storage should offer for the draw call to succeed. Can
1612 * be NULL.
1613 **/
getIterationProperties(unsigned int n_iteration,float * out_inner_tess_levels,float * out_outer_tess_levels,bool * out_point_mode,_tessellation_primitive_mode * out_primitive_mode,_tessellation_shader_vertex_ordering * out_vertex_ordering,unsigned int * out_result_buffer_size)1614 void TessellationShaderInvarianceRule4Test::getIterationProperties(
1615 unsigned int n_iteration, float *out_inner_tess_levels, float *out_outer_tess_levels, bool *out_point_mode,
1616 _tessellation_primitive_mode *out_primitive_mode, _tessellation_shader_vertex_ordering *out_vertex_ordering,
1617 unsigned int *out_result_buffer_size)
1618 {
1619 DE_ASSERT(m_test_iterations.size() > n_iteration);
1620
1621 _test_iteration &test_iteration = m_test_iterations[n_iteration];
1622
1623 memcpy(out_inner_tess_levels, test_iteration.inner_tess_levels, sizeof(test_iteration.inner_tess_levels));
1624 memcpy(out_outer_tess_levels, test_iteration.outer_tess_levels, sizeof(test_iteration.outer_tess_levels));
1625
1626 *out_point_mode = false;
1627 *out_primitive_mode = test_iteration.primitive_mode;
1628 *out_vertex_ordering = TESSELLATION_SHADER_VERTEX_ORDERING_CCW;
1629
1630 if (out_result_buffer_size != DE_NULL)
1631 {
1632 *out_result_buffer_size = m_utils_ptr->getAmountOfVerticesGeneratedByTessellator(
1633 *out_primitive_mode, out_inner_tess_levels, out_outer_tess_levels, test_iteration.vertex_spacing,
1634 *out_point_mode);
1635 test_iteration.n_vertices = *out_result_buffer_size;
1636 *out_result_buffer_size =
1637 static_cast<unsigned int>(*out_result_buffer_size * 3 /* components */ * sizeof(float));
1638
1639 DE_ASSERT(*out_result_buffer_size != 0);
1640 }
1641 }
1642
1643 /** Retrieves iteration-specific tessellation evaluation shader code.
1644 *
1645 * @param n_iteration Iteration index, for which the source code is being obtained.
1646 *
1647 * @return Requested source code.
1648 **/
getTECode(unsigned int n_iteration)1649 std::string TessellationShaderInvarianceRule4Test::getTECode(unsigned int n_iteration)
1650 {
1651 DE_ASSERT(m_test_iterations.size() > n_iteration);
1652
1653 const _test_iteration &test_iteration = m_test_iterations[n_iteration];
1654
1655 return TessellationShaderUtils::getGenericTECode(test_iteration.vertex_spacing, test_iteration.primitive_mode,
1656 TESSELLATION_SHADER_VERTEX_ORDERING_CCW, false); /* point mode */
1657 }
1658
1659 /** Initializes test iterations for the test. The following modes and inner/outer tess level
1660 * configurations are used to form the test set:
1661 *
1662 * - Inner/outer tessellation level combinations as returned by
1663 * TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode()
1664 * - 'Quads' and 'Triangles' primitive modes;
1665 * - All vertex spacing modes;
1666 *
1667 * All permutations are used to generate the test set.
1668 **/
initTestIterations()1669 void TessellationShaderInvarianceRule4Test::initTestIterations()
1670 {
1671 DE_ASSERT(m_test_iterations.size() == 0);
1672
1673 /* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value */
1674 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1675 glw::GLint gl_max_tess_gen_level_value = 0;
1676
1677 gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value);
1678 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_GEN_LEVEL_EXT pname");
1679
1680 /* Iterate through all primitive and vertex spacing modes relevant to the test */
1681 _tessellation_primitive_mode primitive_modes[] = {TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS,
1682 TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES};
1683 _tessellation_shader_vertex_spacing vs_modes[] = {TESSELLATION_SHADER_VERTEX_SPACING_EQUAL,
1684 TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_EVEN,
1685 TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD};
1686
1687 const unsigned int n_primitive_modes = sizeof(primitive_modes) / sizeof(primitive_modes[0]);
1688 const unsigned int n_vs_modes = sizeof(vs_modes) / sizeof(vs_modes[0]);
1689
1690 for (unsigned int n_primitive_mode = 0; n_primitive_mode < n_primitive_modes; ++n_primitive_mode)
1691 {
1692 _tessellation_primitive_mode primitive_mode = primitive_modes[n_primitive_mode];
1693
1694 for (unsigned int n_vs_mode = 0; n_vs_mode < n_vs_modes; ++n_vs_mode)
1695 {
1696 _tessellation_shader_vertex_spacing vs_mode = vs_modes[n_vs_mode];
1697
1698 /* Retrieve inner/outer tessellation level combinations we want the tests to be run for */
1699 _tessellation_levels_set levels;
1700
1701 levels = TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode(
1702 primitive_mode, gl_max_tess_gen_level_value,
1703 TESSELLATION_LEVEL_SET_FILTER_ALL_LEVELS_USE_THE_SAME_VALUE);
1704
1705 /* Iterate through all configurations */
1706 for (_tessellation_levels_set_const_iterator levels_iterator = levels.begin();
1707 levels_iterator != levels.end(); levels_iterator++)
1708 {
1709 const _tessellation_levels ¤t_levels = *levels_iterator;
1710
1711 /* Create a test descriptor for all the parameters we now have.
1712 *
1713 * The set we're operating on uses different outer tessellation level values, so we
1714 * need to make sure the levels are set to the same FP values in order for the test
1715 * to succeed. */
1716 _test_iteration test;
1717
1718 memcpy(test.inner_tess_levels, current_levels.inner, sizeof(test.inner_tess_levels));
1719
1720 for (int n = 0; n < 4 /* outer tess levels */; ++n)
1721 {
1722 test.outer_tess_levels[n] = current_levels.outer[0];
1723 }
1724
1725 test.primitive_mode = primitive_mode;
1726 test.vertex_spacing = vs_mode;
1727
1728 m_test_iterations.push_back(test);
1729 } /* for (all inner/outer tessellation levels) */
1730 } /* for (all vertex spacing modes) */
1731 } /* for (all primitive modes) */
1732 }
1733
1734 /** Verifies user-provided vertex data can be found in the provided vertex data array.
1735 *
1736 * @param vertex_data Vertex data array the requested vertex data are to be found in.
1737 * @param n_vertices Amount of vertices declared in @param vertex_data;
1738 * @param vertex_data_seeked Vertex data to be found in @param vertex_data;
1739 * @param n_vertex_data_seeked_components Amount of components to take into account.
1740 *
1741 * @return true if the vertex data was found, false otherwise.
1742 **/
isVertexDefined(const float * vertex_data,unsigned int n_vertices,const float * vertex_data_seeked,unsigned int n_vertex_data_seeked_components)1743 bool TessellationShaderInvarianceRule4Test::isVertexDefined(const float *vertex_data, unsigned int n_vertices,
1744 const float *vertex_data_seeked,
1745 unsigned int n_vertex_data_seeked_components)
1746 {
1747 bool result = false;
1748
1749 DE_ASSERT(n_vertex_data_seeked_components >= 2);
1750
1751 for (unsigned int n_vertex = 0; n_vertex < n_vertices; ++n_vertex)
1752 {
1753 const float *current_vertex_data = vertex_data + 3 /* components */ * n_vertex;
1754
1755 if ((vertex_data_seeked[0] == current_vertex_data[0]) && (vertex_data_seeked[1] == current_vertex_data[1]) &&
1756 ((n_vertex_data_seeked_components < 3) ||
1757 (n_vertex_data_seeked_components >= 3 && (vertex_data_seeked[2] == current_vertex_data[2]))))
1758 {
1759 result = true;
1760
1761 break;
1762 } /* if (components match) */
1763 } /* for (all vertices) */
1764
1765 return result;
1766 }
1767
1768 /** Verifies result data on per-iteration basis.
1769 *
1770 * Throws TestError exception if an error occurs.
1771 *
1772 * @param n_iteration Index of iteration the check should be performed for.
1773 * @param data Points to array of vec3s storing the vertices as
1774 * generated by tessellation
1775 **/
verifyResultDataForIteration(unsigned int n_iteration,const void * data)1776 void TessellationShaderInvarianceRule4Test::verifyResultDataForIteration(unsigned int n_iteration, const void *data)
1777 {
1778 DE_ASSERT(m_test_iterations.size() > n_iteration);
1779
1780 const glw::GLfloat *data_float = (const glw::GLfloat *)data;
1781 const _test_iteration &test_iteration = m_test_iterations[n_iteration];
1782
1783 /* Iterate through all generated vertices.. */
1784 for (unsigned int n_vertex = 0; n_vertex < test_iteration.n_vertices; ++n_vertex)
1785 {
1786 std::vector<_vertex> expected_vertices;
1787 const glw::GLfloat *vertex_data = data_float + 3 /* components */ * n_vertex;
1788
1789 /* Make sure that for each vertex, the following language from the extension
1790 * spec is followed:
1791 */
1792 switch (test_iteration.primitive_mode)
1793 {
1794 case TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS:
1795 {
1796 /* For quad tessellation, if vertices at (x,0) and (1-x,0) are generated
1797 * when subdividing the v==0 edge, vertices must be generated at (0,x) and
1798 * (0,1-x) when subdividing an otherwise identical u==0 edge.
1799 */
1800 if (vertex_data[0] != 0.0f && vertex_data[1] == 0.0f)
1801 {
1802 const float paired_vertex_data[] = {1.0f - vertex_data[0], vertex_data[1]};
1803
1804 if (isVertexDefined(data_float, test_iteration.n_vertices, paired_vertex_data, 2)) /* components */
1805 {
1806 _vertex expected_vertex;
1807
1808 /* First expected vertex */
1809 expected_vertex.u = vertex_data[1];
1810 expected_vertex.v = vertex_data[0];
1811 expected_vertex.w = -1.0f;
1812
1813 expected_vertices.push_back(expected_vertex);
1814
1815 /* The other expected vertex */
1816 expected_vertex.u = vertex_data[1];
1817 expected_vertex.v = 1.0f - vertex_data[0];
1818
1819 expected_vertices.push_back(expected_vertex);
1820 } /* if (the other required vertex is defined) */
1821 } /* if (the first required vertex is defined) */
1822
1823 break;
1824 } /* case TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS: */
1825
1826 case TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES:
1827 {
1828 /* For triangular tessellation, if vertices at (x,1-x,0) and (1-x,x,0) are
1829 * generated when subdividing the w==0 edge, vertices must be generated at
1830 * (x,0,1-x) and (1-x,0,x) when subdividing an otherwise identical v==0
1831 * edge.
1832 */
1833 if (vertex_data[0] != 0.0f && vertex_data[1] == (1.0f - vertex_data[0]) && vertex_data[2] == 0)
1834 {
1835 const float paired_vertex_data[] = {vertex_data[1], vertex_data[0], vertex_data[2]};
1836
1837 if (isVertexDefined(data_float, test_iteration.n_vertices, paired_vertex_data, 3)) /* components */
1838 {
1839 _vertex expected_vertex;
1840
1841 /* First expected vertex */
1842 expected_vertex.u = vertex_data[0];
1843 expected_vertex.v = vertex_data[2];
1844 expected_vertex.w = vertex_data[1];
1845
1846 expected_vertices.push_back(expected_vertex);
1847
1848 /* The other expected vertex */
1849 expected_vertex.u = vertex_data[1];
1850 expected_vertex.v = vertex_data[2];
1851 expected_vertex.w = vertex_data[0];
1852
1853 expected_vertices.push_back(expected_vertex);
1854 } /* if (the other required vertex is defined) */
1855 } /* if (the firsst required vertex is defined) */
1856
1857 break;
1858 } /* case TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES: */
1859
1860 default:
1861 {
1862 TCU_FAIL("Primitive mode unrecognized");
1863 }
1864 } /* switch (test_iteration.primitive_mode) */
1865
1866 /* Iterate through all expected vertices */
1867 for (std::vector<_vertex>::const_iterator expected_vertex_iterator = expected_vertices.begin();
1868 expected_vertex_iterator != expected_vertices.end(); expected_vertex_iterator++)
1869 {
1870 const _vertex &expected_vertex = *expected_vertex_iterator;
1871 const float expected_vertex_raw[] = {expected_vertex.u, expected_vertex.v, expected_vertex.w};
1872 bool has_been_found = false;
1873
1874 has_been_found = isVertexDefined(data_float, test_iteration.n_vertices, expected_vertex_raw,
1875 (expected_vertex.w < 0) ? 2 : 3);
1876
1877 if (!has_been_found)
1878 {
1879 std::stringstream expected_vertex_sstream;
1880
1881 expected_vertex_sstream << expected_vertex.u << ", " << expected_vertex.v;
1882
1883 if (expected_vertex.w >= 0.0f)
1884 {
1885 expected_vertex_sstream << ", " << expected_vertex.w;
1886 }
1887
1888 m_testCtx.getLog() << tcu::TestLog::Message << "For primitive mode:"
1889 << "["
1890 << TessellationShaderUtils::getESTokenForPrimitiveMode(test_iteration.primitive_mode)
1891 << "]"
1892 << "and vertex spacing mode:"
1893 << "["
1894 << TessellationShaderUtils::getESTokenForVertexSpacingMode(
1895 test_iteration.vertex_spacing)
1896 << "]"
1897 << " and inner tessellation levels:[" << test_iteration.inner_tess_levels[0] << ", "
1898 << test_iteration.inner_tess_levels[1] << ") "
1899 << " and outer tessellation levels:[" << test_iteration.outer_tess_levels[0] << ", "
1900 << test_iteration.outer_tess_levels[1] << ", " << test_iteration.outer_tess_levels[2]
1901 << ", " << test_iteration.outer_tess_levels[3] << ") "
1902 << " the following vertex was expected:[" << expected_vertex_sstream.str().c_str()
1903 << "] but was not found in the tessellated cooordinate data set"
1904 << tcu::TestLog::EndMessage;
1905
1906 TCU_FAIL("Expected symmetrical vertex data was not generated by the tessellator.");
1907 } /* if (the expected vertex data was not found) */
1908 } /* for (all expected vertices) */
1909 } /* for (all generated vertices) */
1910 }
1911
1912 /** Constructor.
1913 *
1914 * @param context Rendering context.
1915 *
1916 **/
TessellationShaderInvarianceRule5Test(Context & context,const ExtParameters & extParams)1917 TessellationShaderInvarianceRule5Test::TessellationShaderInvarianceRule5Test(Context &context,
1918 const ExtParameters &extParams)
1919 : TessellationShaderInvarianceBaseTest(context, extParams, "invariance_rule5",
1920 "Verifies conformance with fifth invariance rule")
1921 {
1922 }
1923
1924 /** Destructor. */
~TessellationShaderInvarianceRule5Test()1925 TessellationShaderInvarianceRule5Test::~TessellationShaderInvarianceRule5Test()
1926 {
1927 /* Left blank intentionally */
1928 }
1929
1930 /** Retrieves amount of iterations the base test implementation should run before
1931 * calling global verification routine.
1932 *
1933 * @return A value that depends on initTestIterations() behavior.
1934 **/
getAmountOfIterations()1935 unsigned int TessellationShaderInvarianceRule5Test::getAmountOfIterations()
1936 {
1937 if (m_test_quads_iterations.size() == 0 || m_test_triangles_iterations.size() == 0)
1938 {
1939 initTestIterations();
1940 }
1941
1942 return (unsigned int)(m_test_quads_iterations.size() + m_test_triangles_iterations.size());
1943 }
1944
1945 /** Retrieves _test_iteration instance specific for user-specified iteration index.
1946 *
1947 * @param n_iteration Iteration index to retrieve _test_iteration instance for.
1948 *
1949 * @return Iteration-specific _test_iteration instance.
1950 *
1951 **/
getTestForIteration(unsigned int n_iteration)1952 TessellationShaderInvarianceRule5Test::_test_iteration &TessellationShaderInvarianceRule5Test::getTestForIteration(
1953 unsigned int n_iteration)
1954 {
1955 unsigned int n_triangles_tests = (unsigned int)m_test_triangles_iterations.size();
1956 _test_iteration &test_iteration = (n_iteration < n_triangles_tests) ?
1957 m_test_triangles_iterations[n_iteration] :
1958 m_test_quads_iterations[n_iteration - n_triangles_tests];
1959
1960 return test_iteration;
1961 }
1962
1963 /** Retrieves iteration-specific tessellation properties.
1964 *
1965 * @param n_iteration Iteration index to retrieve the properties for.
1966 * @param out_inner_tess_levels Deref will be used to store iteration-specific inner
1967 * tessellation level values. Must not be NULL.
1968 * @param out_outer_tess_levels Deref will be used to store iteration-specific outer
1969 * tessellation level values. Must not be NULL.
1970 * @param out_point_mode Deref will be used to store iteration-specific flag
1971 * telling whether point mode should be enabled for given pass.
1972 * Must not be NULL.
1973 * @param out_primitive_mode Deref will be used to store iteration-specific primitive
1974 * mode. Must not be NULL.
1975 * @param out_vertex_ordering Deref will be used to store iteration-specific vertex
1976 * ordering. Must not be NULL.
1977 * @param out_result_buffer_size Deref will be used to store amount of bytes XFB buffer object
1978 * storage should offer for the draw call to succeed. Can
1979 * be NULL.
1980 **/
getIterationProperties(unsigned int n_iteration,float * out_inner_tess_levels,float * out_outer_tess_levels,bool * out_point_mode,_tessellation_primitive_mode * out_primitive_mode,_tessellation_shader_vertex_ordering * out_vertex_ordering,unsigned int * out_result_buffer_size)1981 void TessellationShaderInvarianceRule5Test::getIterationProperties(
1982 unsigned int n_iteration, float *out_inner_tess_levels, float *out_outer_tess_levels, bool *out_point_mode,
1983 _tessellation_primitive_mode *out_primitive_mode, _tessellation_shader_vertex_ordering *out_vertex_ordering,
1984 unsigned int *out_result_buffer_size)
1985 {
1986 DE_ASSERT(m_test_triangles_iterations.size() + m_test_quads_iterations.size() > n_iteration);
1987
1988 _test_iteration &test_iteration = getTestForIteration(n_iteration);
1989
1990 memcpy(out_inner_tess_levels, test_iteration.inner_tess_levels, sizeof(test_iteration.inner_tess_levels));
1991 memcpy(out_outer_tess_levels, test_iteration.outer_tess_levels, sizeof(test_iteration.outer_tess_levels));
1992
1993 *out_point_mode = false;
1994 *out_primitive_mode = test_iteration.primitive_mode;
1995 *out_vertex_ordering = test_iteration.vertex_ordering;
1996
1997 if (out_result_buffer_size != DE_NULL)
1998 {
1999 *out_result_buffer_size = m_utils_ptr->getAmountOfVerticesGeneratedByTessellator(
2000 *out_primitive_mode, out_inner_tess_levels, out_outer_tess_levels, TESSELLATION_SHADER_VERTEX_SPACING_EQUAL,
2001 *out_point_mode);
2002 test_iteration.n_vertices = *out_result_buffer_size;
2003 *out_result_buffer_size =
2004 static_cast<unsigned int>(*out_result_buffer_size * 3 /* components */ * sizeof(float));
2005
2006 DE_ASSERT(*out_result_buffer_size != 0);
2007 }
2008 }
2009
2010 /** Retrieves iteration-specific tessellation evaluation shader code.
2011 *
2012 * @param n_iteration Iteration index, for which the source code is being obtained.
2013 *
2014 * @return Requested source code.
2015 **/
getTECode(unsigned int n_iteration)2016 std::string TessellationShaderInvarianceRule5Test::getTECode(unsigned int n_iteration)
2017 {
2018 DE_ASSERT(m_test_triangles_iterations.size() + m_test_quads_iterations.size() > n_iteration);
2019
2020 const _test_iteration &test_iteration = getTestForIteration(n_iteration);
2021
2022 return TessellationShaderUtils::getGenericTECode(TESSELLATION_SHADER_VERTEX_SPACING_EQUAL,
2023 test_iteration.primitive_mode, test_iteration.vertex_ordering,
2024 false); /* point mode */
2025 }
2026
2027 /** Initializes test iterations for the test. The following modes and inner/outer tess level
2028 * configurations are used to form the test set:
2029 *
2030 * - Last inner/outer tessellation level combination as returned by
2031 * TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode()
2032 * - All primitive modes;
2033 * - All vertex spacing modes;
2034 *
2035 * All permutations are used to generate the test set.
2036 **/
initTestIterations()2037 void TessellationShaderInvarianceRule5Test::initTestIterations()
2038 {
2039 DE_ASSERT(m_test_quads_iterations.size() == 0 && m_test_triangles_iterations.size() == 0);
2040
2041 /* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value */
2042 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
2043 glw::GLint gl_max_tess_gen_level_value = 0;
2044
2045 gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value);
2046 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_GEN_LEVEL_EXT pname");
2047
2048 /* Iterate through all primitive and vertex spacing modes relevant to the test */
2049 _tessellation_primitive_mode primitive_modes[] = {TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS,
2050 TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES};
2051 _tessellation_shader_vertex_ordering vo_modes[] = {
2052 TESSELLATION_SHADER_VERTEX_ORDERING_CCW,
2053 TESSELLATION_SHADER_VERTEX_ORDERING_CW,
2054 };
2055
2056 const unsigned int n_primitive_modes = sizeof(primitive_modes) / sizeof(primitive_modes[0]);
2057 const unsigned int n_vo_modes = sizeof(vo_modes) / sizeof(vo_modes[0]);
2058
2059 for (unsigned int n_primitive_mode = 0; n_primitive_mode < n_primitive_modes; ++n_primitive_mode)
2060 {
2061 _tessellation_primitive_mode primitive_mode = primitive_modes[n_primitive_mode];
2062
2063 for (unsigned int n_vo_mode = 0; n_vo_mode < n_vo_modes; ++n_vo_mode)
2064 {
2065 _tessellation_shader_vertex_ordering vertex_ordering = vo_modes[n_vo_mode];
2066
2067 /* Retrieve inner/outer tessellation level combinations we want the tests to be run for */
2068 _tessellation_levels_set levels_set;
2069
2070 levels_set = TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode(
2071 primitive_mode, gl_max_tess_gen_level_value,
2072 TESSELLATION_LEVEL_SET_FILTER_ALL_LEVELS_USE_THE_SAME_VALUE);
2073
2074 /* Only use the last inner/outer level configuration, as reported by the utils function. */
2075 const _tessellation_levels &levels = levels_set[levels_set.size() - 1];
2076
2077 /* Create a test descriptor for all the parameters we now have */
2078 _test_iteration test;
2079
2080 memcpy(test.inner_tess_levels, levels.inner, sizeof(test.inner_tess_levels));
2081 memcpy(test.outer_tess_levels, levels.outer, sizeof(test.outer_tess_levels));
2082
2083 test.primitive_mode = primitive_mode;
2084 test.vertex_ordering = vertex_ordering;
2085
2086 if (primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES)
2087 {
2088 m_test_triangles_iterations.push_back(test);
2089 }
2090 else
2091 {
2092 m_test_quads_iterations.push_back(test);
2093 }
2094 } /* for (all vertex spacing modes) */
2095 } /* for (all primitive modes) */
2096 }
2097
2098 /** Verifies user-provided vertex data can be found in the provided vertex data array.
2099 *
2100 * @param vertex_data Vertex data array the requested vertex data are to be found in.
2101 * @param n_vertices Amount of vertices declared in @param vertex_data;
2102 * @param vertex_data_seeked Vertex data to be found in @param vertex_data;
2103 * @param n_vertex_data_seeked_components Amount of components to take into account.
2104 *
2105 * @return true if the vertex data was found, false otherwise.
2106 **/
isVertexDefined(const float * vertex_data,unsigned int n_vertices,const float * vertex_data_seeked,unsigned int n_vertex_data_seeked_components)2107 bool TessellationShaderInvarianceRule5Test::isVertexDefined(const float *vertex_data, unsigned int n_vertices,
2108 const float *vertex_data_seeked,
2109 unsigned int n_vertex_data_seeked_components)
2110 {
2111 const float epsilon = 1e-5f;
2112 bool result = false;
2113
2114 DE_ASSERT(n_vertex_data_seeked_components >= 2);
2115
2116 for (unsigned int n_vertex = 0; n_vertex < n_vertices; ++n_vertex)
2117 {
2118 const float *current_vertex_data = vertex_data + 3 /* components */ * n_vertex;
2119
2120 if (de::abs(vertex_data_seeked[0] - current_vertex_data[0]) < epsilon &&
2121 de::abs(vertex_data_seeked[1] - current_vertex_data[1]) < epsilon &&
2122 ((n_vertex_data_seeked_components < 3) ||
2123 (n_vertex_data_seeked_components >= 3 &&
2124 de::abs(vertex_data_seeked[2] - current_vertex_data[2]) < epsilon)))
2125 {
2126 result = true;
2127
2128 break;
2129 } /* if (components match) */
2130 } /* for (all vertices) */
2131
2132 return result;
2133 }
2134
2135 /** Verifies result data. Accesses data generated by all iterations.
2136 *
2137 * Throws TestError exception if an error occurs.
2138 *
2139 * @param all_iterations_data An array of pointers to buffers, holding gl_TessCoord
2140 * data generated by subsequent iterations.
2141 **/
verifyResultData(const void ** all_iterations_data)2142 void TessellationShaderInvarianceRule5Test::verifyResultData(const void **all_iterations_data)
2143 {
2144 /* Run two separate iterations:
2145 *
2146 * a) triangles
2147 * b) quads
2148 */
2149 for (unsigned int n_iteration = 0; n_iteration < 2 /* quads, triangles */; ++n_iteration)
2150 {
2151 const unsigned int n_base_iteration = (n_iteration == 0) ? 0 : (unsigned int)m_test_triangles_iterations.size();
2152 const unsigned int set_size = (n_iteration == 0) ? (unsigned int)m_test_triangles_iterations.size() :
2153 (unsigned int)m_test_quads_iterations.size();
2154 const _test_iterations &test_iterations =
2155 (n_iteration == 0) ? m_test_triangles_iterations : m_test_quads_iterations;
2156
2157 DE_ASSERT(test_iterations.size() != 0);
2158
2159 /* For each iteration, verify that all vertices generated for all three vertex spacing modes.
2160 * are exactly the same (but in different order) */
2161 const float *base_vertex_data = (const float *)all_iterations_data[n_base_iteration + 0];
2162
2163 for (unsigned int n_set = 1; n_set < set_size; ++n_set)
2164 {
2165 const float *set_vertex_data = (const float *)all_iterations_data[n_base_iteration + n_set];
2166
2167 /* Amount of vertices should not differ between sets */
2168 DE_ASSERT(test_iterations[0].n_vertices == test_iterations[n_set].n_vertices);
2169
2170 /* Run through all vertices in base set and make sure they can be found in currently
2171 * processed set */
2172 for (unsigned int n_base_vertex = 0; n_base_vertex < test_iterations[0].n_vertices; ++n_base_vertex)
2173 {
2174 const float *base_vertex = base_vertex_data + 3 /* components */ * n_base_vertex;
2175
2176 if (!isVertexDefined(set_vertex_data, test_iterations[n_set].n_vertices, base_vertex,
2177 3)) /* components */
2178 {
2179 const char *primitive_mode = (n_iteration == 0) ? "triangles" : "quads";
2180
2181 m_testCtx.getLog() << tcu::TestLog::Message << "For primitive mode [" << primitive_mode << "] "
2182 << "a vertex with tessellation coordinates:[" << base_vertex[0] << ", "
2183 << base_vertex[1] << ", " << base_vertex[2] << ") "
2184 << "could not have been found for both vertex orderings."
2185 << tcu::TestLog::EndMessage;
2186
2187 TCU_FAIL("Implementation does not follow Rule 5.");
2188 }
2189 } /* for (all base set's vertices) */
2190 } /* for (all sets) */
2191 } /* for (both primitive types) */
2192 }
2193
2194 /** Constructor.
2195 *
2196 * @param context Rendering context.
2197 *
2198 **/
TessellationShaderInvarianceRule6Test(Context & context,const ExtParameters & extParams)2199 TessellationShaderInvarianceRule6Test::TessellationShaderInvarianceRule6Test(Context &context,
2200 const ExtParameters &extParams)
2201 : TessellationShaderInvarianceBaseTest(context, extParams, "invariance_rule6",
2202 "Verifies conformance with sixth invariance rule")
2203 {
2204 }
2205
2206 /** Destructor. */
~TessellationShaderInvarianceRule6Test()2207 TessellationShaderInvarianceRule6Test::~TessellationShaderInvarianceRule6Test()
2208 {
2209 /* Left blank intentionally */
2210 }
2211
2212 /** Retrieves amount of iterations the base test implementation should run before
2213 * calling global verification routine.
2214 *
2215 * @return A value that depends on initTestIterations() behavior.
2216 **/
getAmountOfIterations()2217 unsigned int TessellationShaderInvarianceRule6Test::getAmountOfIterations()
2218 {
2219 if (m_test_quads_iterations.size() == 0 || m_test_triangles_iterations.size() == 0)
2220 {
2221 initTestIterations();
2222 }
2223
2224 return (unsigned int)(m_test_quads_iterations.size() + m_test_triangles_iterations.size());
2225 }
2226
2227 /** Retrieves _test_iteration instance specific for user-specified iteration index.
2228 *
2229 * @param n_iteration Iteration index to retrieve _test_iteration instance for.
2230 *
2231 * @return Iteration-specific _test_iteration instance.
2232 *
2233 **/
getTestForIteration(unsigned int n_iteration)2234 TessellationShaderInvarianceRule6Test::_test_iteration &TessellationShaderInvarianceRule6Test::getTestForIteration(
2235 unsigned int n_iteration)
2236 {
2237 unsigned int n_triangles_tests = (unsigned int)m_test_triangles_iterations.size();
2238 _test_iteration &test_iteration = (n_iteration < n_triangles_tests) ?
2239 m_test_triangles_iterations[n_iteration] :
2240 m_test_quads_iterations[n_iteration - n_triangles_tests];
2241
2242 return test_iteration;
2243 }
2244
2245 /** Retrieves iteration-specific tessellation properties.
2246 *
2247 * @param n_iteration Iteration index to retrieve the properties for.
2248 * @param out_inner_tess_levels Deref will be used to store iteration-specific inner
2249 * tessellation level values. Must not be NULL.
2250 * @param out_outer_tess_levels Deref will be used to store iteration-specific outer
2251 * tessellation level values. Must not be NULL.
2252 * @param out_point_mode Deref will be used to store iteration-specific flag
2253 * telling whether point mode should be enabled for given pass.
2254 * Must not be NULL.
2255 * @param out_primitive_mode Deref will be used to store iteration-specific primitive
2256 * mode. Must not be NULL.
2257 * @param out_vertex_ordering Deref will be used to store iteration-specific vertex
2258 * ordering. Must not be NULL.
2259 * @param out_result_buffer_size Deref will be used to store amount of bytes XFB buffer object
2260 * storage should offer for the draw call to succeed. Can
2261 * be NULL.
2262 **/
getIterationProperties(unsigned int n_iteration,float * out_inner_tess_levels,float * out_outer_tess_levels,bool * out_point_mode,_tessellation_primitive_mode * out_primitive_mode,_tessellation_shader_vertex_ordering * out_vertex_ordering,unsigned int * out_result_buffer_size)2263 void TessellationShaderInvarianceRule6Test::getIterationProperties(
2264 unsigned int n_iteration, float *out_inner_tess_levels, float *out_outer_tess_levels, bool *out_point_mode,
2265 _tessellation_primitive_mode *out_primitive_mode, _tessellation_shader_vertex_ordering *out_vertex_ordering,
2266 unsigned int *out_result_buffer_size)
2267 {
2268 DE_ASSERT(m_test_triangles_iterations.size() + m_test_quads_iterations.size() > n_iteration);
2269
2270 _test_iteration &test_iteration = getTestForIteration(n_iteration);
2271
2272 memcpy(out_inner_tess_levels, test_iteration.inner_tess_levels, sizeof(test_iteration.inner_tess_levels));
2273 memcpy(out_outer_tess_levels, test_iteration.outer_tess_levels, sizeof(test_iteration.outer_tess_levels));
2274
2275 *out_point_mode = false;
2276 *out_primitive_mode = test_iteration.primitive_mode;
2277 *out_vertex_ordering = test_iteration.vertex_ordering;
2278
2279 if (out_result_buffer_size != DE_NULL)
2280 {
2281 *out_result_buffer_size = m_utils_ptr->getAmountOfVerticesGeneratedByTessellator(
2282 *out_primitive_mode, out_inner_tess_levels, out_outer_tess_levels, TESSELLATION_SHADER_VERTEX_SPACING_EQUAL,
2283 *out_point_mode);
2284 test_iteration.n_vertices = *out_result_buffer_size;
2285 *out_result_buffer_size =
2286 static_cast<unsigned int>(*out_result_buffer_size * 3 /* components */ * sizeof(float));
2287
2288 DE_ASSERT(*out_result_buffer_size != 0);
2289 }
2290 }
2291
2292 /** Retrieves iteration-specific tessellation evaluation shader code.
2293 *
2294 * @param n_iteration Iteration index, for which the source code is being obtained.
2295 *
2296 * @return Requested source code.
2297 **/
getTECode(unsigned int n_iteration)2298 std::string TessellationShaderInvarianceRule6Test::getTECode(unsigned int n_iteration)
2299 {
2300 DE_ASSERT(m_test_triangles_iterations.size() + m_test_quads_iterations.size() > n_iteration);
2301
2302 const _test_iteration &test_iteration = getTestForIteration(n_iteration);
2303
2304 return TessellationShaderUtils::getGenericTECode(TESSELLATION_SHADER_VERTEX_SPACING_EQUAL,
2305 test_iteration.primitive_mode, test_iteration.vertex_ordering,
2306 false); /* point mode */
2307 }
2308
2309 /** Initializes test iterations for the test. The following modes and inner/outer tess level
2310 * configurations are used to form the test set:
2311 *
2312 * - Tessellation level combinations as returned by
2313 * TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode() (however, the inner
2314 * tessellation level values are all set to values corresponding to last item returned for
2315 * the set)
2316 * - All primitive modes;
2317 * - All vertex ordering modes;
2318 *
2319 * All permutations are used to generate the test set.
2320 **/
initTestIterations()2321 void TessellationShaderInvarianceRule6Test::initTestIterations()
2322 {
2323 DE_ASSERT(m_test_quads_iterations.size() == 0 && m_test_triangles_iterations.size() == 0);
2324
2325 /* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value */
2326 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
2327 glw::GLint gl_max_tess_gen_level_value = 0;
2328
2329 gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value);
2330 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_GEN_LEVEL_EXT pname");
2331
2332 /* Iterate through all primitive and vertex spacing modes relevant to the test */
2333 _tessellation_primitive_mode primitive_modes[] = {TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES,
2334 TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS};
2335 _tessellation_shader_vertex_ordering vertex_ordering_modes[] = {TESSELLATION_SHADER_VERTEX_ORDERING_CCW,
2336 TESSELLATION_SHADER_VERTEX_ORDERING_CW};
2337
2338 const unsigned int n_primitive_modes = sizeof(primitive_modes) / sizeof(primitive_modes[0]);
2339 const unsigned int n_vo_modes = sizeof(vertex_ordering_modes) / sizeof(vertex_ordering_modes[0]);
2340
2341 for (unsigned int n_primitive_mode = 0; n_primitive_mode < n_primitive_modes; ++n_primitive_mode)
2342 {
2343 _tessellation_primitive_mode primitive_mode = primitive_modes[n_primitive_mode];
2344
2345 for (unsigned int n_vo_mode = 0; n_vo_mode < n_vo_modes; ++n_vo_mode)
2346 {
2347 _tessellation_shader_vertex_ordering vertex_ordering = vertex_ordering_modes[n_vo_mode];
2348
2349 /* Retrieve inner/outer tessellation level combinations we want the tests to be run for.
2350 * Since each level set we will be provided by getTessellationLevelSetForPrimitiveMode()
2351 * is unique and does not repeat, we'll just make sure the inner level values are set to
2352 * the same set of values, so that the conditions the test must meet are actually met.
2353 */
2354 float *inner_levels_to_use = DE_NULL;
2355 _tessellation_levels_set levels_set;
2356 unsigned int n_levels_sets = 0;
2357
2358 levels_set = TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode(
2359 primitive_mode, gl_max_tess_gen_level_value,
2360 TESSELLATION_LEVEL_SET_FILTER_ALL_LEVELS_USE_THE_SAME_VALUE);
2361
2362 n_levels_sets = (unsigned int)levels_set.size();
2363 inner_levels_to_use = levels_set[n_levels_sets - 1].inner;
2364
2365 for (unsigned int n_levels_set = 0; n_levels_set < n_levels_sets - 1; n_levels_set++)
2366 {
2367 /* Make sure the Utils function was not changed and that inner level values
2368 * are actually unique across the whole set */
2369 DE_ASSERT(levels_set[n_levels_set].inner[0] != levels_set[n_levels_sets - 1].inner[0] &&
2370 levels_set[n_levels_set].inner[1] != levels_set[n_levels_sets - 1].inner[1]);
2371
2372 /* Force the last set's inner values to all level combinations we'll be using */
2373 memcpy(levels_set[n_levels_set].inner, inner_levels_to_use, sizeof(levels_set[n_levels_set].inner));
2374 } /* for (all sets retrieved from Utils function */
2375
2376 for (_tessellation_levels_set_const_iterator set_iterator = levels_set.begin();
2377 set_iterator != levels_set.end(); set_iterator++)
2378 {
2379 const _tessellation_levels &levels = *set_iterator;
2380
2381 /* Create a test descriptor for all the parameters we now have */
2382 _test_iteration test;
2383
2384 memcpy(test.inner_tess_levels, levels.inner, sizeof(test.inner_tess_levels));
2385 memcpy(test.outer_tess_levels, levels.outer, sizeof(test.outer_tess_levels));
2386
2387 test.primitive_mode = primitive_mode;
2388 test.vertex_ordering = vertex_ordering;
2389
2390 if (primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES)
2391 {
2392 m_test_triangles_iterations.push_back(test);
2393 }
2394 else
2395 {
2396 m_test_quads_iterations.push_back(test);
2397 }
2398 } /* for (all level sets) */
2399 } /* for (all vertex ordering modes) */
2400 } /* for (all primitive modes) */
2401 }
2402
2403 /** Verifies result data. Accesses data generated by all iterations.
2404 *
2405 * Throws TestError exception if an error occurs.
2406 *
2407 * @param all_iterations_data An array of pointers to buffers, holding gl_TessCoord
2408 * data generated by subsequent iterations.
2409 **/
verifyResultData(const void ** all_iterations_data)2410 void TessellationShaderInvarianceRule6Test::verifyResultData(const void **all_iterations_data)
2411 {
2412 /* Run two separate iterations:
2413 *
2414 * a) triangles
2415 * b) quads
2416 */
2417
2418 for (unsigned int n_iteration = 0; n_iteration < 2 /* quads, triangles */; ++n_iteration)
2419 {
2420 const unsigned int n_base_iteration = (n_iteration == 0) ? 0 : (unsigned int)m_test_triangles_iterations.size();
2421
2422 const unsigned int n_sets = (n_iteration == 0) ? (unsigned int)m_test_triangles_iterations.size() :
2423 (unsigned int)m_test_quads_iterations.size();
2424
2425 _tessellation_primitive_mode primitive_mode = (n_iteration == 0) ?
2426 TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES :
2427 TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS;
2428
2429 const _test_iterations &test_iterations =
2430 (n_iteration == 0) ? m_test_triangles_iterations : m_test_quads_iterations;
2431
2432 const unsigned int n_triangles_in_base_set = test_iterations[0].n_vertices / 3 /* vertices per triangle */;
2433
2434 DE_ASSERT(test_iterations.size() != 0);
2435
2436 /* For each iteration, verify that all vertices generated for all three vertex spacing modes.
2437 * are exactly the same (but in different order) */
2438 const _test_iteration &base_test = test_iterations[0];
2439 const float *base_vertex_data = (const float *)all_iterations_data[n_base_iteration + 0];
2440
2441 for (unsigned int n_set = 1; n_set < n_sets; ++n_set)
2442 {
2443 const _test_iteration &set_test = test_iterations[n_set];
2444 const float *set_vertex_data = (const float *)all_iterations_data[n_base_iteration + n_set];
2445
2446 /* We're operating on triangles so make sure the amount of vertices we're dealing with is
2447 * divisible by 3 */
2448 DE_ASSERT((test_iterations[n_set].n_vertices % 3) == 0);
2449
2450 const unsigned int n_triangles_in_curr_set = test_iterations[n_set].n_vertices / 3;
2451
2452 /* Take base triangles and make sure they can be found in iteration-specific set.
2453 * Now, thing to keep in mind here is that we must not assume any specific vertex
2454 * and triangle order which is why the slow search. */
2455 for (unsigned int n_base_triangle = 0; n_base_triangle < n_triangles_in_base_set; ++n_base_triangle)
2456 {
2457 /* Extract base triangle data first */
2458 const float *base_triangle_vertex1 = base_vertex_data + n_base_triangle *
2459 3 * /* vertices per triangle */
2460 3; /* components */
2461 const float *base_triangle_vertex2 = base_triangle_vertex1 + 3; /* components */
2462 const float *base_triangle_vertex3 = base_triangle_vertex2 + 3; /* components */
2463
2464 /* Only interior triangles should be left intact. Is this an interior triangle? */
2465 if (!TessellationShaderUtils::isOuterEdgeVertex(primitive_mode, base_triangle_vertex1) &&
2466 !TessellationShaderUtils::isOuterEdgeVertex(primitive_mode, base_triangle_vertex2) &&
2467 !TessellationShaderUtils::isOuterEdgeVertex(primitive_mode, base_triangle_vertex3))
2468 {
2469 /* Iterate through all triangles in considered set */
2470 bool has_base_set_triangle_been_found = false;
2471
2472 for (unsigned int n_curr_set_triangle = 0; n_curr_set_triangle < n_triangles_in_curr_set;
2473 ++n_curr_set_triangle)
2474 {
2475 const float *curr_triangle = set_vertex_data + n_curr_set_triangle *
2476 3 * /* vertices per triangle */
2477 3; /* components */
2478
2479 if (TessellationShaderUtils::isTriangleDefined(base_triangle_vertex1, curr_triangle))
2480 {
2481 has_base_set_triangle_been_found = true;
2482
2483 break;
2484 }
2485 } /* for (all triangles in currently processed set) */
2486
2487 if (!has_base_set_triangle_been_found)
2488 {
2489 std::string primitive_mode_str =
2490 TessellationShaderUtils::getESTokenForPrimitiveMode(base_test.primitive_mode);
2491
2492 m_testCtx.getLog()
2493 << tcu::TestLog::Message << "For primitive mode [" << primitive_mode_str << "]"
2494 << ", base inner tessellation levels:"
2495 << "[" << base_test.inner_tess_levels[0] << ", " << base_test.inner_tess_levels[1] << "]"
2496 << ", base outer tessellation levels:"
2497 << "[" << base_test.outer_tess_levels[0] << ", " << base_test.outer_tess_levels[1] << ", "
2498 << base_test.outer_tess_levels[2] << ", " << base_test.outer_tess_levels[3] << "]"
2499 << ", reference inner tessellation levels:"
2500 << "[" << set_test.inner_tess_levels[0] << ", " << set_test.inner_tess_levels[1] << "]"
2501 << ", reference outer tessellation levels:"
2502 << "[" << set_test.outer_tess_levels[0] << ", " << set_test.outer_tess_levels[1] << ", "
2503 << set_test.outer_tess_levels[2] << ", " << set_test.outer_tess_levels[3] << "]"
2504 << ", the following triangle formed during base tessellation run was not found in "
2505 "reference run:"
2506 << "[" << base_triangle_vertex1[0] << ", " << base_triangle_vertex1[1] << ", "
2507 << base_triangle_vertex1[2] << "]x"
2508 << "[" << base_triangle_vertex2[0] << ", " << base_triangle_vertex2[1] << ", "
2509 << base_triangle_vertex2[2] << "]x"
2510 << "[" << base_triangle_vertex3[0] << ", " << base_triangle_vertex3[1] << ", "
2511 << base_triangle_vertex3[2]
2512
2513 << tcu::TestLog::EndMessage;
2514
2515 TCU_FAIL("Implementation does not appear to be rule 6-conformant");
2516 } /* if (triangle created during base run was not found in reference run) */
2517 } /* if (base triangle is interior) */
2518 } /* for (all base set's vertices) */
2519 } /* for (all sets) */
2520 } /* for (both primitive types) */
2521 }
2522
2523 /** Constructor.
2524 *
2525 * @param context Rendering context.
2526 *
2527 **/
TessellationShaderInvarianceRule7Test(Context & context,const ExtParameters & extParams)2528 TessellationShaderInvarianceRule7Test::TessellationShaderInvarianceRule7Test(Context &context,
2529 const ExtParameters &extParams)
2530 : TessellationShaderInvarianceBaseTest(context, extParams, "invariance_rule7",
2531 "Verifies conformance with seventh invariance rule")
2532 {
2533 }
2534
2535 /** Destructor. */
~TessellationShaderInvarianceRule7Test()2536 TessellationShaderInvarianceRule7Test::~TessellationShaderInvarianceRule7Test()
2537 {
2538 /* Left blank intentionally */
2539 }
2540
2541 /** Retrieves amount of iterations the base test implementation should run before
2542 * calling global verification routine.
2543 *
2544 * @return A value that depends on initTestIterations() behavior.
2545 **/
getAmountOfIterations()2546 unsigned int TessellationShaderInvarianceRule7Test::getAmountOfIterations()
2547 {
2548 if (m_test_quads_iterations.size() == 0 || m_test_triangles_iterations.size() == 0)
2549 {
2550 initTestIterations();
2551 }
2552
2553 return (unsigned int)(m_test_quads_iterations.size() + m_test_triangles_iterations.size());
2554 }
2555
2556 /** Retrieves index of a test iteration that was initialized with user-provided
2557 * properties.
2558 *
2559 * @param is_triangles_iteration true if the seeked test iteration should have
2560 * been run for 'triangles' primitive mode', false
2561 * if 'quads' primitive mode run is seeked.
2562 * @param inner_tess_levels Two FP values describing inner tessellation level
2563 * values the seeked run should have used.
2564 * @param outer_tess_levels Four FP values describing outer tessellation level
2565 * values the seeked run should have used.
2566 * @param vertex_ordering Vertex ordering mode the seeked run should have used.
2567 * @param n_modified_outer_tess_level Tells which outer tessellation level should be
2568 * excluded from checking.
2569 *
2570 * @return 0xFFFFFFFF if no test iteration was run for user-provided properties,
2571 * actual index otherwise.
2572 *
2573 **/
getTestIterationIndex(bool is_triangles_iteration,const float * inner_tess_levels,const float * outer_tess_levels,_tessellation_shader_vertex_ordering vertex_ordering,unsigned int n_modified_outer_tess_level)2574 unsigned int TessellationShaderInvarianceRule7Test::getTestIterationIndex(
2575 bool is_triangles_iteration, const float *inner_tess_levels, const float *outer_tess_levels,
2576 _tessellation_shader_vertex_ordering vertex_ordering, unsigned int n_modified_outer_tess_level)
2577 {
2578 const float epsilon = 1e-5f;
2579 unsigned int result = 0xFFFFFFFF;
2580 const _test_iterations &test_iterations =
2581 (is_triangles_iteration) ? m_test_triangles_iterations : m_test_quads_iterations;
2582 const unsigned int n_test_iterations = (unsigned int)test_iterations.size();
2583
2584 for (unsigned int n_test_iteration = 0; n_test_iteration < n_test_iterations; ++n_test_iteration)
2585 {
2586 _test_iteration test_iteration = test_iterations[n_test_iteration];
2587
2588 if (de::abs(test_iteration.inner_tess_levels[0] - inner_tess_levels[0]) < epsilon &&
2589 de::abs(test_iteration.inner_tess_levels[1] - inner_tess_levels[1]) < epsilon &&
2590 test_iteration.vertex_ordering == vertex_ordering &&
2591 test_iteration.n_modified_outer_tess_level == n_modified_outer_tess_level)
2592 {
2593 /* Only compare outer tessellation levels that have not been modified */
2594 if (((n_modified_outer_tess_level == 0) ||
2595 (n_modified_outer_tess_level != 0 &&
2596 de::abs(test_iteration.outer_tess_levels[0] - outer_tess_levels[0]) < epsilon)) &&
2597 ((n_modified_outer_tess_level == 1) ||
2598 (n_modified_outer_tess_level != 1 &&
2599 de::abs(test_iteration.outer_tess_levels[1] - outer_tess_levels[1]) < epsilon)) &&
2600 ((n_modified_outer_tess_level == 2) ||
2601 (n_modified_outer_tess_level != 2 &&
2602 de::abs(test_iteration.outer_tess_levels[2] - outer_tess_levels[2]) < epsilon)) &&
2603 ((n_modified_outer_tess_level == 3) ||
2604 (n_modified_outer_tess_level != 3 &&
2605 de::abs(test_iteration.outer_tess_levels[3] - outer_tess_levels[3]) < epsilon)))
2606 {
2607 result = n_test_iteration;
2608
2609 break;
2610 }
2611 }
2612 } /* for (all test iterations) */
2613
2614 return result;
2615 }
2616
2617 /** Retrieves _test_iteration instance specific for user-specified iteration index.
2618 *
2619 * @param n_iteration Iteration index to retrieve _test_iteration instance for.
2620 *
2621 * @return Iteration-specific _test_iteration instance.
2622 *
2623 **/
getTestForIteration(unsigned int n_iteration)2624 TessellationShaderInvarianceRule7Test::_test_iteration &TessellationShaderInvarianceRule7Test::getTestForIteration(
2625 unsigned int n_iteration)
2626 {
2627 unsigned int n_triangles_tests = (unsigned int)m_test_triangles_iterations.size();
2628 _test_iteration &test_iteration = (n_iteration < n_triangles_tests) ?
2629 m_test_triangles_iterations[n_iteration] :
2630 m_test_quads_iterations[n_iteration - n_triangles_tests];
2631
2632 return test_iteration;
2633 }
2634
2635 /** Retrieves iteration-specific tessellation properties.
2636 *
2637 * @param n_iteration Iteration index to retrieve the properties for.
2638 * @param out_inner_tess_levels Deref will be used to store iteration-specific inner
2639 * tessellation level values. Must not be NULL.
2640 * @param out_outer_tess_levels Deref will be used to store iteration-specific outer
2641 * tessellation level values. Must not be NULL.
2642 * @param out_point_mode Deref will be used to store iteration-specific flag
2643 * telling whether point mode should be enabled for given pass.
2644 * Must not be NULL.
2645 * @param out_primitive_mode Deref will be used to store iteration-specific primitive
2646 * mode. Must not be NULL.
2647 * @param out_vertex_ordering Deref will be used to store iteration-specific vertex
2648 * ordering. Must not be NULL.
2649 * @param out_result_buffer_size Deref will be used to store amount of bytes XFB buffer object
2650 * storage should offer for the draw call to succeed. Can
2651 * be NULL.
2652 **/
getIterationProperties(unsigned int n_iteration,float * out_inner_tess_levels,float * out_outer_tess_levels,bool * out_point_mode,_tessellation_primitive_mode * out_primitive_mode,_tessellation_shader_vertex_ordering * out_vertex_ordering,unsigned int * out_result_buffer_size)2653 void TessellationShaderInvarianceRule7Test::getIterationProperties(
2654 unsigned int n_iteration, float *out_inner_tess_levels, float *out_outer_tess_levels, bool *out_point_mode,
2655 _tessellation_primitive_mode *out_primitive_mode, _tessellation_shader_vertex_ordering *out_vertex_ordering,
2656 unsigned int *out_result_buffer_size)
2657 {
2658 DE_ASSERT(m_test_triangles_iterations.size() + m_test_quads_iterations.size() > n_iteration);
2659
2660 _test_iteration &test_iteration = getTestForIteration(n_iteration);
2661
2662 memcpy(out_inner_tess_levels, test_iteration.inner_tess_levels, sizeof(test_iteration.inner_tess_levels));
2663 memcpy(out_outer_tess_levels, test_iteration.outer_tess_levels, sizeof(test_iteration.outer_tess_levels));
2664
2665 *out_point_mode = false;
2666 *out_primitive_mode = test_iteration.primitive_mode;
2667 *out_vertex_ordering = test_iteration.vertex_ordering;
2668
2669 if (out_result_buffer_size != DE_NULL)
2670 {
2671 *out_result_buffer_size = m_utils_ptr->getAmountOfVerticesGeneratedByTessellator(
2672 *out_primitive_mode, out_inner_tess_levels, out_outer_tess_levels, TESSELLATION_SHADER_VERTEX_SPACING_EQUAL,
2673 *out_point_mode);
2674 test_iteration.n_vertices = *out_result_buffer_size;
2675 *out_result_buffer_size =
2676 static_cast<unsigned int>(*out_result_buffer_size * 3 /* components */ * sizeof(float));
2677
2678 DE_ASSERT(*out_result_buffer_size != 0);
2679 }
2680 }
2681
2682 /** Retrieves iteration-specific tessellation evaluation shader code.
2683 *
2684 * @param n_iteration Iteration index, for which the source code is being obtained.
2685 *
2686 * @return Requested source code.
2687 **/
getTECode(unsigned int n_iteration)2688 std::string TessellationShaderInvarianceRule7Test::getTECode(unsigned int n_iteration)
2689 {
2690 DE_ASSERT(m_test_triangles_iterations.size() + m_test_quads_iterations.size() > n_iteration);
2691
2692 const _test_iteration &test_iteration = getTestForIteration(n_iteration);
2693
2694 return TessellationShaderUtils::getGenericTECode(TESSELLATION_SHADER_VERTEX_SPACING_EQUAL,
2695 test_iteration.primitive_mode, test_iteration.vertex_ordering,
2696 false); /* point mode */
2697 }
2698
2699 /** Initializes test iterations for the test. The following modes and inner/outer tess level
2700 * configurations are used to form the test set:
2701 *
2702 * - All inner/outer tessellation level combinations as returned by
2703 * TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode()
2704 * times 3 (for triangles) or 4 (for quads). For each combination,
2705 * the test will capture tessellation coordinates multiple times, each
2706 * time changing a different outer tessellation level value and leaving
2707 * the rest intact.
2708 * - All primitive modes;
2709 * - All vertex spacing modes;
2710 *
2711 * All permutations are used to generate the test set.
2712 **/
initTestIterations()2713 void TessellationShaderInvarianceRule7Test::initTestIterations()
2714 {
2715 DE_ASSERT(m_test_quads_iterations.size() == 0 && m_test_triangles_iterations.size() == 0);
2716
2717 /* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value */
2718 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
2719 glw::GLint gl_max_tess_gen_level_value = 0;
2720
2721 gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value);
2722 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_GEN_LEVEL_EXT pname");
2723
2724 /* Iterate through all primitive and vertex spacing modes relevant to the test */
2725 _tessellation_primitive_mode primitive_modes[] = {TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS,
2726 TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES};
2727 _tessellation_shader_vertex_ordering vo_modes[] = {
2728 TESSELLATION_SHADER_VERTEX_ORDERING_CCW,
2729 TESSELLATION_SHADER_VERTEX_ORDERING_CW,
2730 };
2731
2732 const unsigned int n_primitive_modes = sizeof(primitive_modes) / sizeof(primitive_modes[0]);
2733 const unsigned int n_vo_modes = sizeof(vo_modes) / sizeof(vo_modes[0]);
2734
2735 for (unsigned int n_primitive_mode = 0; n_primitive_mode < n_primitive_modes; ++n_primitive_mode)
2736 {
2737 _tessellation_primitive_mode primitive_mode = primitive_modes[n_primitive_mode];
2738 const unsigned int n_relevant_outer_tess_levels =
2739 (primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS) ? 4 : 3;
2740
2741 for (unsigned int n_vo_mode = 0; n_vo_mode < n_vo_modes; ++n_vo_mode)
2742 {
2743 _tessellation_shader_vertex_ordering vertex_ordering = vo_modes[n_vo_mode];
2744
2745 /* Retrieve inner/outer tessellation level combinations we want the tests to be run for */
2746 _tessellation_levels_set levels_set;
2747
2748 levels_set = TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode(
2749 primitive_mode, gl_max_tess_gen_level_value,
2750 TESSELLATION_LEVEL_SET_FILTER_ALL_LEVELS_USE_THE_SAME_VALUE);
2751
2752 /* Create test descriptor for all inner/outer level configurations we received from the utils function. */
2753 for (_tessellation_levels_set_const_iterator levels_set_iterator = levels_set.begin();
2754 levels_set_iterator != levels_set.end(); levels_set_iterator++)
2755 {
2756 const _tessellation_levels &levels = *levels_set_iterator;
2757
2758 for (unsigned int n_outer_level_to_change = 0;
2759 n_outer_level_to_change < n_relevant_outer_tess_levels + 1 /* base iteration */;
2760 ++n_outer_level_to_change)
2761 {
2762 /* Create a test descriptor for all the parameters we now have */
2763 _test_iteration test;
2764
2765 memcpy(test.inner_tess_levels, levels.inner, sizeof(test.inner_tess_levels));
2766 memcpy(test.outer_tess_levels, levels.outer, sizeof(test.outer_tess_levels));
2767
2768 test.primitive_mode = primitive_mode;
2769 test.vertex_ordering = vertex_ordering;
2770
2771 /* Change iteration-specific outer tessellation level to a different value, but only
2772 * if we're not preparing a base iteration*/
2773 if (n_outer_level_to_change != n_relevant_outer_tess_levels)
2774 {
2775 test.n_modified_outer_tess_level = n_outer_level_to_change;
2776 test.outer_tess_levels[n_outer_level_to_change] = (float)(gl_max_tess_gen_level_value) / 3.0f;
2777 }
2778 else
2779 {
2780 test.is_base_iteration = true;
2781 }
2782
2783 if (primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES)
2784 {
2785 m_test_triangles_iterations.push_back(test);
2786 }
2787 else
2788 {
2789 m_test_quads_iterations.push_back(test);
2790 }
2791 }
2792 } /* for (all levels set entries) */
2793 } /* for (all vertex spacing modes) */
2794 } /* for (all primitive modes) */
2795 }
2796
2797 /** Tells whether a triangle is included in user-provided set of triangles.
2798 * The triangle is expected to use an undefined vertex ordering.
2799 *
2800 * @param base_triangle_data 9 FP values defining 3 vertices of a triangle.
2801 * @param vertex_data Vertex stream. It is expected these vertices
2802 * form triangles. It is also assumed each vertex
2803 * is expressed with 3 components.
2804 * @param vertex_data_n_vertices Amount of vertices that can be found in @param
2805 * vertex_data
2806 *
2807 * @return true if the triangle was found in user-provided triangle set,
2808 * false otherwise.
2809 *
2810 **/
isTriangleDefinedInVertexDataSet(const float * base_triangle_data,const float * vertex_data,unsigned int vertex_data_n_vertices)2811 bool TessellationShaderInvarianceRule7Test::isTriangleDefinedInVertexDataSet(const float *base_triangle_data,
2812 const float *vertex_data,
2813 unsigned int vertex_data_n_vertices)
2814 {
2815 bool result = false;
2816
2817 for (unsigned int n_triangle = 0; n_triangle < vertex_data_n_vertices / 3 /* vertices per triangle */; n_triangle++)
2818 {
2819 const float *current_triangle_data = vertex_data + n_triangle * 3 * /* vertices per triangle */
2820 3; /* components */
2821
2822 if (TessellationShaderUtils::isTriangleDefined(current_triangle_data, base_triangle_data))
2823 {
2824 result = true;
2825
2826 break;
2827 }
2828 } /* for (all vertices) */
2829
2830 return result;
2831 }
2832
2833 /** Verifies result data. Accesses data generated by all iterations.
2834 *
2835 * Throws TestError exception if an error occurs.
2836 *
2837 * @param all_iterations_data An array of pointers to buffers, holding gl_TessCoord
2838 * data generated by subsequent iterations.
2839 **/
verifyResultData(const void ** all_iterations_data)2840 void TessellationShaderInvarianceRule7Test::verifyResultData(const void **all_iterations_data)
2841 {
2842 const float epsilon = 1e-5f;
2843
2844 /* Run two separate iterations:
2845 *
2846 * a) triangles
2847 * b) quads
2848 */
2849 for (unsigned int n_iteration = 0; n_iteration < 2 /* triangles, quads */; ++n_iteration)
2850 {
2851 bool is_triangles_iteration = (n_iteration == 0);
2852 const unsigned int n_base_iteration = (n_iteration == 0) ? 0 : (unsigned int)m_test_triangles_iterations.size();
2853 const unsigned int n_relevant_outer_tess_levels = (is_triangles_iteration) ? 3 : 4;
2854
2855 _tessellation_primitive_mode primitive_mode = (n_iteration == 0) ?
2856 TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES :
2857 TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS;
2858
2859 const _test_iterations &test_iterations =
2860 (n_iteration == 0) ? m_test_triangles_iterations : m_test_quads_iterations;
2861
2862 DE_ASSERT(test_iterations.size() != 0);
2863
2864 /* Find a base iteration first */
2865 for (unsigned int n_base_test_iteration = 0; n_base_test_iteration < test_iterations.size();
2866 n_base_test_iteration++)
2867 {
2868 const _test_iteration &base_iteration = test_iterations[n_base_test_iteration];
2869 std::vector<int> ref_iteration_indices;
2870
2871 if (!base_iteration.is_base_iteration)
2872 {
2873 continue;
2874 }
2875
2876 /* Retrieve reference test iterations */
2877 for (unsigned int n_reference_iteration = 0; n_reference_iteration < n_relevant_outer_tess_levels;
2878 ++n_reference_iteration)
2879 {
2880 const unsigned int n_modified_outer_tess_level =
2881 (base_iteration.n_modified_outer_tess_level + n_reference_iteration + 1) %
2882 n_relevant_outer_tess_levels;
2883 const unsigned int ref_iteration_index = getTestIterationIndex(
2884 is_triangles_iteration, base_iteration.inner_tess_levels, base_iteration.outer_tess_levels,
2885 base_iteration.vertex_ordering, n_modified_outer_tess_level);
2886
2887 DE_ASSERT(ref_iteration_index != 0xFFFFFFFF);
2888 DE_ASSERT(ref_iteration_index != n_base_test_iteration);
2889
2890 ref_iteration_indices.push_back(ref_iteration_index);
2891 }
2892
2893 /* We can now start comparing base data with the information generated for
2894 * reference iterations. */
2895 for (std::vector<int>::const_iterator ref_iteration_iterator = ref_iteration_indices.begin();
2896 ref_iteration_iterator != ref_iteration_indices.end(); ref_iteration_iterator++)
2897 {
2898 const int &n_ref_test_iteration = *ref_iteration_iterator;
2899 const _test_iteration &ref_iteration = test_iterations[n_ref_test_iteration];
2900
2901 /* Now move through all triangles generated for base test iteration. Focus on the ones
2902 * that connect the outer edge with one of the inner ones */
2903 const float *base_iteration_vertex_data =
2904 (const float *)all_iterations_data[n_base_iteration + n_base_test_iteration];
2905 const float *ref_iteration_vertex_data =
2906 (const float *)all_iterations_data[n_base_iteration + n_ref_test_iteration];
2907
2908 for (unsigned int n_base_triangle = 0;
2909 n_base_triangle < base_iteration.n_vertices / 3; /* vertices per triangle */
2910 ++n_base_triangle)
2911 {
2912 const float *base_triangle_data =
2913 base_iteration_vertex_data + n_base_triangle * 3 /* vertices */ * 3; /* components */
2914
2915 /* Is that the triangle type we're after? */
2916 const float *base_triangle_vertex1 = base_triangle_data;
2917 const float *base_triangle_vertex2 = base_triangle_vertex1 + 3; /* components */
2918 const float *base_triangle_vertex3 = base_triangle_vertex2 + 3; /* components */
2919 bool is_base_triangle_vertex1_outer =
2920 TessellationShaderUtils::isOuterEdgeVertex(primitive_mode, base_triangle_vertex1);
2921 bool is_base_triangle_vertex2_outer =
2922 TessellationShaderUtils::isOuterEdgeVertex(primitive_mode, base_triangle_vertex2);
2923 bool is_base_triangle_vertex3_outer =
2924 TessellationShaderUtils::isOuterEdgeVertex(primitive_mode, base_triangle_vertex3);
2925 unsigned int n_outer_edge_vertices_found = 0;
2926
2927 n_outer_edge_vertices_found += (is_base_triangle_vertex1_outer == true);
2928 n_outer_edge_vertices_found += (is_base_triangle_vertex2_outer == true);
2929 n_outer_edge_vertices_found += (is_base_triangle_vertex3_outer == true);
2930
2931 if (n_outer_edge_vertices_found == 0)
2932 {
2933 /* This is an inner triangle, not really of our interest */
2934 continue;
2935 }
2936
2937 /* Which outer tessellation level describes the base data edge? */
2938 unsigned int n_base_tess_level = 0;
2939
2940 if (primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES)
2941 {
2942 if ((!is_base_triangle_vertex1_outer ||
2943 (is_base_triangle_vertex1_outer && base_triangle_vertex1[0] == 0.0f)) &&
2944 (!is_base_triangle_vertex2_outer ||
2945 (is_base_triangle_vertex2_outer && base_triangle_vertex2[0] == 0.0f)) &&
2946 (!is_base_triangle_vertex3_outer ||
2947 (is_base_triangle_vertex3_outer && base_triangle_vertex3[0] == 0.0f)))
2948 {
2949 n_base_tess_level = 0;
2950 }
2951 else if ((!is_base_triangle_vertex1_outer ||
2952 (is_base_triangle_vertex1_outer && base_triangle_vertex1[1] == 0.0f)) &&
2953 (!is_base_triangle_vertex2_outer ||
2954 (is_base_triangle_vertex2_outer && base_triangle_vertex2[1] == 0.0f)) &&
2955 (!is_base_triangle_vertex3_outer ||
2956 (is_base_triangle_vertex3_outer && base_triangle_vertex3[1] == 0.0f)))
2957 {
2958 n_base_tess_level = 1;
2959 }
2960 else
2961 {
2962 DE_ASSERT((!is_base_triangle_vertex1_outer ||
2963 (is_base_triangle_vertex1_outer && base_triangle_vertex1[2] == 0.0f)) &&
2964 (!is_base_triangle_vertex2_outer ||
2965 (is_base_triangle_vertex2_outer && base_triangle_vertex2[2] == 0.0f)) &&
2966 (!is_base_triangle_vertex3_outer ||
2967 (is_base_triangle_vertex3_outer && base_triangle_vertex3[2] == 0.0f)));
2968
2969 n_base_tess_level = 2;
2970 }
2971 } /* if (primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES) */
2972 else
2973 {
2974 DE_ASSERT(primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS);
2975
2976 std::size_t n_outer_edge_vertices = 0;
2977 std::vector<const float *> outer_edge_vertices;
2978
2979 if (is_base_triangle_vertex1_outer)
2980 {
2981 outer_edge_vertices.push_back(base_triangle_vertex1);
2982 }
2983
2984 if (is_base_triangle_vertex2_outer)
2985 {
2986 outer_edge_vertices.push_back(base_triangle_vertex2);
2987 }
2988
2989 if (is_base_triangle_vertex3_outer)
2990 {
2991 outer_edge_vertices.push_back(base_triangle_vertex3);
2992 }
2993
2994 n_outer_edge_vertices = outer_edge_vertices.size();
2995
2996 DE_ASSERT(n_outer_edge_vertices >= 1 && n_outer_edge_vertices <= 2);
2997
2998 bool is_top_outer_edge = true;
2999 bool is_right_outer_edge = true;
3000 bool is_bottom_outer_edge = true;
3001 bool is_left_outer_edge = true;
3002
3003 /* Find which outer edges the vertices don't belong to. If one is in a corner,
3004 * the other will clarify to which edge both vertices belong. */
3005 for (unsigned int n_vertex = 0; n_vertex < n_outer_edge_vertices; ++n_vertex)
3006 {
3007 /* Y < 1, not top outer edge */
3008 if (de::abs(outer_edge_vertices[n_vertex][1] - 1.0f) > epsilon)
3009 {
3010 is_top_outer_edge = false;
3011 }
3012
3013 /* X < 1, not right outer edge */
3014 if (de::abs(outer_edge_vertices[n_vertex][0] - 1.0f) > epsilon)
3015 {
3016 is_right_outer_edge = false;
3017 }
3018
3019 /* Y > 0, not bottom outer edge */
3020 if (de::abs(outer_edge_vertices[n_vertex][1]) > epsilon)
3021 {
3022 is_bottom_outer_edge = false;
3023 }
3024
3025 /* X > 0, not left outer edge */
3026 if (de::abs(outer_edge_vertices[n_vertex][0]) > epsilon)
3027 {
3028 is_left_outer_edge = false;
3029 }
3030 }
3031
3032 if (n_outer_edge_vertices == 1)
3033 {
3034 /* A single vertex with corner-coordinates belongs to two edges. Choose one */
3035 bool x_is_0 = de::abs(outer_edge_vertices[0][0]) < epsilon;
3036 bool x_is_1 = de::abs(outer_edge_vertices[0][0] - 1.0f) < epsilon;
3037 bool y_is_0 = de::abs(outer_edge_vertices[0][1]) < epsilon;
3038 bool y_is_1 = de::abs(outer_edge_vertices[0][1] - 1.0f) < epsilon;
3039
3040 if (x_is_0 && y_is_0)
3041 {
3042 /* bottom edge */
3043 DE_ASSERT(is_left_outer_edge && is_bottom_outer_edge);
3044 is_left_outer_edge = false;
3045 }
3046 else if (x_is_0 && y_is_1)
3047 {
3048 /* left edge */
3049 DE_ASSERT(is_left_outer_edge && is_top_outer_edge);
3050 is_top_outer_edge = false;
3051 }
3052 else if (x_is_1 && y_is_0)
3053 {
3054 /* right edge */
3055 DE_ASSERT(is_right_outer_edge && is_bottom_outer_edge);
3056 is_bottom_outer_edge = false;
3057 }
3058 else if (x_is_1 && y_is_1)
3059 {
3060 /* top edge */
3061 DE_ASSERT(is_right_outer_edge && is_top_outer_edge);
3062 is_right_outer_edge = false;
3063 }
3064 else
3065 {
3066 /* Not a corner vertex, only one of the edge-flags is set */
3067 }
3068 }
3069
3070 /* Quick checks */
3071 DE_UNREF(is_top_outer_edge);
3072 DE_ASSERT((is_left_outer_edge && !is_top_outer_edge && !is_bottom_outer_edge &&
3073 !is_right_outer_edge) ||
3074 (!is_left_outer_edge && is_top_outer_edge && !is_bottom_outer_edge &&
3075 !is_right_outer_edge) ||
3076 (!is_left_outer_edge && !is_top_outer_edge && is_bottom_outer_edge &&
3077 !is_right_outer_edge) ||
3078 (!is_left_outer_edge && !is_top_outer_edge && !is_bottom_outer_edge &&
3079 is_right_outer_edge));
3080
3081 /* We have all the data needed to determine which tessellation level describes
3082 * subdivision of the edge that the triangle touches */
3083 if (is_left_outer_edge)
3084 {
3085 n_base_tess_level = 0;
3086 }
3087 else if (is_bottom_outer_edge)
3088 {
3089 n_base_tess_level = 1;
3090 }
3091 else if (is_right_outer_edge)
3092 {
3093 n_base_tess_level = 2;
3094 }
3095 else
3096 {
3097 n_base_tess_level = 3;
3098 }
3099 }
3100
3101 /* We shouldn't perform the check if the edge we're processing was described
3102 * by a different outer tessellation level in the reference data set */
3103 if (n_base_tess_level == ref_iteration.n_modified_outer_tess_level)
3104 {
3105 continue;
3106 }
3107
3108 /* This triangle should be present in both vertex data sets */
3109 if (!isTriangleDefinedInVertexDataSet(base_triangle_data, ref_iteration_vertex_data,
3110 ref_iteration.n_vertices))
3111 {
3112 const char *primitive_mode_str = (is_triangles_iteration) ? "triangles" : "quads";
3113
3114 m_testCtx.getLog()
3115 << tcu::TestLog::Message << "For primitive mode [" << primitive_mode_str << "] "
3116 << ", inner tessellation levels:"
3117 << "[" << base_iteration.inner_tess_levels[0] << ", " << base_iteration.inner_tess_levels[1]
3118 << "], outer tessellation levels:"
3119 << "[" << base_iteration.outer_tess_levels[0] << ", " << base_iteration.outer_tess_levels[1]
3120 << ", " << base_iteration.outer_tess_levels[2] << ", "
3121 << base_iteration.outer_tess_levels[3] << "], a triangle connecting inner & outer edges:"
3122 << "[" << base_triangle_vertex1[0] << ", " << base_triangle_vertex1[1] << ", "
3123 << base_triangle_vertex1[2] << "]x"
3124 << "[" << base_triangle_vertex2[0] << ", " << base_triangle_vertex2[1] << ", "
3125 << base_triangle_vertex2[2] << "]x"
3126 << "[" << base_triangle_vertex3[0] << ", " << base_triangle_vertex3[1] << ", "
3127 << base_triangle_vertex3[2]
3128 << "] was not found for runs using CW and CCW vertex ordering, "
3129 "which is against the extension specification's rule 7."
3130 << tcu::TestLog::EndMessage;
3131
3132 TCU_FAIL("Implementation is not conformant with Tessellation Rule 7");
3133 }
3134 } /* for (all triangles generated for base test iteration) */
3135 } /* for (all reference iterations) */
3136 } /* for (all base test iterations) */
3137 } /* for (both primitive types) */
3138 }
3139
3140 } /* namespace glcts */
3141