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) ?
445 shared_fs_id :
446 (shader_type == SHADER_TYPE_TESSELLATION_CONTROL) ?
447 shared_tc_id :
448 (shader_type == SHADER_TYPE_TESSELLATION_EVALUATION) ? shared_te_id : shared_vs_id;
449 }
450
451 /* Attach the shader object to iteration-specific program object */
452 gl.attachShader(program.po_id, shader_id);
453
454 GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call failed.");
455
456 /* Now that the object has been attached, we can flag it for deletion */
457 if (has_shader_been_generated)
458 {
459 gl.deleteShader(shader_id);
460 GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteShader() call failed");
461 }
462 } /* for (all shader types) */
463
464 /* Set up transform feed-back */
465 unsigned int n_xfb_names = 0;
466 const char** xfb_names = NULL;
467
468 getXFBProperties(n_iteration, &n_xfb_names, &xfb_names);
469
470 gl.transformFeedbackVaryings(program.po_id, n_xfb_names, xfb_names, GL_INTERLEAVED_ATTRIBS);
471 GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() call failed.");
472
473 /* Try to link the program object */
474 glw::GLint link_status = GL_FALSE;
475
476 gl.linkProgram(program.po_id);
477 GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed");
478
479 gl.getProgramiv(program.po_id, GL_LINK_STATUS, &link_status);
480 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed");
481
482 if (link_status != GL_TRUE)
483 {
484 TCU_FAIL("Program linking failed");
485 }
486
487 /* Retrieve inner/outer tess level uniform locations */
488 program.inner_tess_level_uniform_location =
489 gl.getUniformLocation(program.po_id, getInnerTessLevelUniformName());
490 program.outer_tess_level_uniform_location =
491 gl.getUniformLocation(program.po_id, getOuterTessLevelUniformName());
492
493 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetUniformLocation() call(s) failed");
494
495 /* Store the program object */
496 m_programs.push_back(program);
497 } /* for (all iterations) */
498 }
499
500 /** Executes the test.
501 *
502 * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
503 *
504 * Note the function throws exception should an error occur!
505 *
506 * @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again.
507 **/
iterate(void)508 tcu::TestNode::IterateResult TessellationShaderInvarianceBaseTest::iterate(void)
509 {
510 /* Do not execute if required extensions are not supported. */
511 if (!m_is_tessellation_shader_supported)
512 {
513 throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
514 }
515
516 /* Initialize all objects needed to run the test */
517 initTest();
518
519 /* Do a general set-up */
520 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
521
522 gl.enable(GL_RASTERIZER_DISCARD);
523 GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable(GL_RASTERIZER_DISCARD) failed.");
524
525 gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 1);
526 GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteriEXT() failed for GL_PATCH_VERTICES_EXT pname");
527
528 /* There are two types of verification supported by this base test implementation:
529 *
530 * - iteration-specific (verifyResultDataForIteration() )
531 * - global (verifyResultData() )
532 *
533 * It is up to test implementation to decide which of the two (or perhaps both)
534 * entry-points it should overload and use for validating the result data.
535 */
536 const unsigned int n_iterations = getAmountOfIterations();
537 char** iteration_data = new char*[n_iterations];
538
539 /* Execute the test */
540 for (unsigned int n_iteration = 0; n_iteration < n_iterations; ++n_iteration)
541 {
542 _test_program& program = m_programs[n_iteration];
543
544 /* Retrieve iteration properties for current iteration */
545 unsigned int bo_size = 0;
546 float inner_tess_levels[2] = { 0 };
547 bool is_point_mode = false;
548 float outer_tess_levels[4] = { 0 };
549 _tessellation_primitive_mode primitive_mode = TESSELLATION_SHADER_PRIMITIVE_MODE_UNKNOWN;
550 _tessellation_shader_vertex_ordering vertex_ordering = TESSELLATION_SHADER_VERTEX_ORDERING_UNKNOWN;
551
552 getIterationProperties(n_iteration, inner_tess_levels, outer_tess_levels, &is_point_mode, &primitive_mode,
553 &vertex_ordering, &bo_size);
554
555 DE_ASSERT(bo_size != 0);
556
557 /* Activate iteration-specific program */
558 gl.useProgram(program.po_id);
559 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() failed.");
560
561 /* Set up buffer object storage */
562 {
563 char* zero_bo_data = new char[bo_size];
564
565 memset(zero_bo_data, 0, bo_size);
566
567 gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, bo_size, zero_bo_data, GL_STATIC_DRAW);
568 GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() failed");
569
570 delete[] zero_bo_data;
571 zero_bo_data = NULL;
572 }
573
574 /* Allocate space for iteration-specific data */
575 iteration_data[n_iteration] = new char[bo_size];
576
577 /* Configure inner/outer tessellation levels as requested for the iteration */
578 gl.uniform2fv(program.inner_tess_level_uniform_location, 1, /* count */
579 inner_tess_levels);
580 GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform2fv() call failed");
581
582 gl.uniform4fv(program.outer_tess_level_uniform_location, 1, /* count */
583 outer_tess_levels);
584 GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform4fv() call failed");
585
586 /* Launch the TFPW query */
587 gl.beginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, m_qo_tfpw_id);
588 GLU_EXPECT_NO_ERROR(gl.getError(),
589 "glBeginQuery() for GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN target failed.");
590
591 /* Prepare for TF */
592 glw::GLenum tf_mode = TessellationShaderUtils::getTFModeForPrimitiveMode(primitive_mode, is_point_mode);
593
594 gl.beginTransformFeedback(tf_mode);
595 GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() call failed");
596 {
597 /* Execute the draw call */
598 executeDrawCall(n_iteration);
599
600 GLU_EXPECT_NO_ERROR(gl.getError(), "Draw call failed");
601 }
602 gl.endTransformFeedback();
603 GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() call failed");
604
605 gl.endQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
606 GLU_EXPECT_NO_ERROR(gl.getError(), "glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN) call failed");
607
608 /* Make sure that we had sufficient amount of space in a buffer object we used to
609 * capture XFB data.
610 **/
611 glw::GLuint n_tf_primitives_written = 0;
612 glw::GLuint used_tf_bo_size = 0;
613
614 gl.getQueryObjectuiv(m_qo_tfpw_id, GL_QUERY_RESULT, &n_tf_primitives_written);
615 GLU_EXPECT_NO_ERROR(gl.getError(),
616 "Could not retrieve GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN query object result");
617
618 if (is_point_mode)
619 {
620 used_tf_bo_size = static_cast<glw::GLuint>(n_tf_primitives_written * sizeof(float) * 3 /* components */);
621 }
622 else if (primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES)
623 {
624 used_tf_bo_size = static_cast<glw::GLuint>(n_tf_primitives_written * sizeof(float) * 2 /* vertices */ *
625 3 /* components */);
626 }
627 else
628 {
629 used_tf_bo_size = static_cast<glw::GLuint>(n_tf_primitives_written * sizeof(float) * 3 /* vertices */ *
630 3 /* components */);
631 }
632
633 if (used_tf_bo_size != bo_size)
634 {
635 m_testCtx.getLog() << tcu::TestLog::Message << "Expected " << bo_size
636 << " to be filled with tessellation data, "
637 "only "
638 << used_tf_bo_size << "was used." << tcu::TestLog::EndMessage;
639
640 TCU_FAIL("Amount of primitives generated during TF does not match amount of primitives that were expected"
641 " to be generated by the tessellator");
642 }
643
644 /* Map the buffer object we earlier bound to GL_TRANSFORM_FEEDBACK_BUFFER
645 * target into process space. */
646 const void* xfb_data = gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* offset */
647 bo_size, GL_MAP_READ_BIT);
648
649 GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() call failed");
650
651 memcpy(iteration_data[n_iteration], xfb_data, bo_size);
652
653 /* Unmap the buffer object */
654 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
655 GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed");
656
657 /* Ask the test implementation to verify the results */
658 verifyResultDataForIteration(n_iteration, iteration_data[n_iteration]);
659 } /* for (all iterations) */
660
661 /* Now that we've executed all iterations, we can call a global verification
662 * entry-point */
663 verifyResultData((const void**)iteration_data);
664
665 /* At this point we're safe to release space allocated for data coming from
666 * all the iterations */
667 for (unsigned int n_iteration = 0; n_iteration < n_iterations; ++n_iteration)
668 {
669 char* iter_data = (char*)iteration_data[n_iteration];
670 delete[] iter_data;
671
672 iteration_data[n_iteration] = DE_NULL;
673 } /* for (all iterations) */
674
675 delete[] iteration_data;
676 iteration_data = DE_NULL;
677
678 /* All done */
679 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
680 return STOP;
681 }
682
683 /* Does nothing (stub implementation)
684 *
685 * @param n_iteration Not used.
686 * @param data Not used.
687 *
688 **/
verifyResultDataForIteration(unsigned int n_iteration,const void * data)689 void TessellationShaderInvarianceBaseTest::verifyResultDataForIteration(unsigned int n_iteration, const void* data)
690 {
691 DE_UNREF(n_iteration && data);
692
693 /* Do nothing - this is just a stub. */
694 }
695
696 /* Does nothing (stub implementation)
697 *
698 * @param all_iterations_data Not used.
699 *
700 **/
verifyResultData(const void ** all_iterations_data)701 void TessellationShaderInvarianceBaseTest::verifyResultData(const void** all_iterations_data)
702 {
703 DE_UNREF(all_iterations_data);
704
705 /* Do nothing - this is just a stub. */
706 }
707
708 /** Constructor.
709 *
710 * @param context Rendering context.
711 *
712 **/
TessellationShaderInvarianceRule1Test(Context & context,const ExtParameters & extParams)713 TessellationShaderInvarianceRule1Test::TessellationShaderInvarianceRule1Test(Context& context,
714 const ExtParameters& extParams)
715 : TessellationShaderInvarianceBaseTest(context, extParams, "invariance_rule1",
716 "Verifies conformance with first invariance rule")
717 {
718 /* Left blank intentionally */
719 }
720
721 /** Destructor. */
~TessellationShaderInvarianceRule1Test()722 TessellationShaderInvarianceRule1Test::~TessellationShaderInvarianceRule1Test()
723 {
724 /* Left blank intentionally */
725 }
726
727 /** Retrieves amount of iterations the base test implementation should run before
728 * calling global verification routine.
729 *
730 * @return Always 6.
731 **/
getAmountOfIterations()732 unsigned int TessellationShaderInvarianceRule1Test::getAmountOfIterations()
733 {
734 return 6;
735 }
736
737 /** Returns a value that should be used for the draw call's "count" argument.
738 *
739 * @param Always 3
740 **/
getDrawCallCountArgument()741 unsigned int TessellationShaderInvarianceRule1Test::getDrawCallCountArgument()
742 {
743 return 3;
744 }
745
746 /** Retrieves iteration-specific tessellation properties.
747 *
748 * @param n_iteration Iteration index to retrieve the properties for.
749 * @param out_inner_tess_levels Deref will be used to store iteration-specific inner
750 * tessellation level values. Must not be NULL.
751 * @param out_outer_tess_levels Deref will be used to store iteration-specific outer
752 * tessellation level values. Must not be NULL.
753 * @param out_point_mode Deref will be used to store iteration-specific flag
754 * telling whether point mode should be enabled for given pass.
755 * Must not be NULL.
756 * @param out_primitive_mode Deref will be used to store iteration-specific primitive
757 * mode. Must not be NULL.
758 * @param out_vertex_ordering Deref will be used to store iteration-specific vertex ordering.
759 * Must not be NULL.
760 * @param out_result_buffer_size Deref will be used to store amount of bytes XFB buffer object
761 * storage should offer for the draw call to succeed. Must not
762 * be NULL.
763 **/
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)764 void TessellationShaderInvarianceRule1Test::getIterationProperties(
765 unsigned int n_iteration, float* out_inner_tess_levels, float* out_outer_tess_levels, bool* out_point_mode,
766 _tessellation_primitive_mode* out_primitive_mode, _tessellation_shader_vertex_ordering* out_vertex_ordering,
767 unsigned int* out_result_buffer_size)
768 {
769 *out_vertex_ordering = TESSELLATION_SHADER_VERTEX_ORDERING_CCW;
770
771 switch (n_iteration)
772 {
773 case 0:
774 case 5:
775 {
776 /* Triangles (point mode) */
777 out_inner_tess_levels[0] = 1.0f;
778 out_outer_tess_levels[0] = 1.0f;
779 out_outer_tess_levels[1] = 1.0f;
780 out_outer_tess_levels[2] = 1.0f;
781
782 *out_point_mode = true;
783 *out_primitive_mode = TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES;
784
785 break;
786 }
787
788 case 1:
789 case 3:
790 {
791 /* Lines */
792 out_outer_tess_levels[0] = 1.0f;
793 out_outer_tess_levels[1] = 1.0f;
794
795 *out_point_mode = false;
796 *out_primitive_mode = TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES;
797
798 break;
799 }
800
801 case 2:
802 case 4:
803 {
804 /* Triangles */
805 out_inner_tess_levels[0] = 1.0f;
806 out_outer_tess_levels[0] = 1.0f;
807 out_outer_tess_levels[1] = 1.0f;
808 out_outer_tess_levels[2] = 1.0f;
809
810 *out_point_mode = false;
811 *out_primitive_mode = TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES;
812
813 break;
814 }
815
816 default:
817 {
818 TCU_FAIL("Unrecognzied iteration index");
819 }
820 }
821
822 *out_result_buffer_size = m_utils_ptr->getAmountOfVerticesGeneratedByTessellator(
823 *out_primitive_mode, out_inner_tess_levels, out_outer_tess_levels, TESSELLATION_SHADER_VERTEX_SPACING_EQUAL,
824 *out_point_mode);
825
826 *out_result_buffer_size = static_cast<unsigned int>(*out_result_buffer_size * getDrawCallCountArgument() *
827 3 /* components */ * sizeof(float));
828
829 DE_ASSERT(*out_result_buffer_size != 0);
830 }
831
832 /** Retrieves iteration-specific tessellation evaluation shader code.
833 *
834 * @param n_iteration Iteration index, for which the source code is being obtained.
835 *
836 * @return Requested source code.
837 **/
getTECode(unsigned int n_iteration)838 std::string TessellationShaderInvarianceRule1Test::getTECode(unsigned int n_iteration)
839 {
840 unsigned int bo_size = 0;
841 float inner_tess_levels[2] = { 0 };
842 float outer_tess_levels[4] = { 0 };
843 bool point_mode = false;
844 _tessellation_primitive_mode primitive_mode = TESSELLATION_SHADER_PRIMITIVE_MODE_UNKNOWN;
845 _tessellation_shader_vertex_ordering vertex_ordering = TESSELLATION_SHADER_VERTEX_ORDERING_UNKNOWN;
846
847 getIterationProperties(n_iteration, inner_tess_levels, outer_tess_levels, &point_mode, &primitive_mode,
848 &vertex_ordering, &bo_size);
849
850 return TessellationShaderUtils::getGenericTECode(TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, primitive_mode,
851 vertex_ordering, point_mode);
852 }
853
854 /** Verifies result data. Accesses data generated by all iterations.
855 *
856 * Throws TestError exception if an error occurs.
857 *
858 * @param all_iterations_data An array of pointers to buffers, holding gl_TessCoord
859 * data generated by subsequent iterations.
860 **/
verifyResultData(const void ** all_iterations_data)861 void TessellationShaderInvarianceRule1Test::verifyResultData(const void** all_iterations_data)
862 {
863 const float* lines_vertex_data_1 = (const float*)all_iterations_data[1];
864 const float* lines_vertex_data_2 = (const float*)all_iterations_data[3];
865 const float* point_vertex_data_1 = (const float*)all_iterations_data[0];
866 const float* point_vertex_data_2 = (const float*)all_iterations_data[5];
867 const float* tris_vertex_data_1 = (const float*)all_iterations_data[2];
868 const float* tris_vertex_data_2 = (const float*)all_iterations_data[4];
869
870 const unsigned int n_line_vertices = 2 /* vertices per line segment */ * getDrawCallCountArgument(); /* lines */
871 const unsigned int n_point_vertices = 1 /* vertices per point */ * getDrawCallCountArgument(); /* points */
872 const unsigned int n_tri_vertices = 3 /* vertices per triangle */ * getDrawCallCountArgument(); /* triangles */
873 const unsigned int vertex_size = sizeof(float) * 3; /* components */
874
875 /* Make sure the data sets match, given different draw call ordering */
876 for (int n_type = 0; n_type < 3 /* lines, points, tris */; ++n_type)
877 {
878 const float* data1_ptr = DE_NULL;
879 const float* data2_ptr = DE_NULL;
880 std::string data_type_string;
881 unsigned int n_vertices = 0;
882
883 switch (n_type)
884 {
885 case 0:
886 {
887 data1_ptr = lines_vertex_data_1;
888 data2_ptr = lines_vertex_data_2;
889 data_type_string = "Line";
890 n_vertices = n_line_vertices;
891
892 break;
893 }
894
895 case 1:
896 {
897 data1_ptr = point_vertex_data_1;
898 data2_ptr = point_vertex_data_2;
899 data_type_string = "Point";
900 n_vertices = n_point_vertices;
901
902 break;
903 }
904
905 case 2:
906 {
907 data1_ptr = tris_vertex_data_1;
908 data2_ptr = tris_vertex_data_2;
909 data_type_string = "Triangle";
910 n_vertices = n_tri_vertices;
911
912 break;
913 }
914
915 default:
916 {
917 TCU_FAIL("Internal error: type index was not recognized");
918 }
919 } /* switch (n_type) */
920
921 /* Make sure the buffer storage in both cases has been modified */
922 {
923 unsigned int zero_bo_size = vertex_size * n_vertices;
924 char* zero_bo_data = new char[vertex_size * n_vertices];
925
926 memset(zero_bo_data, 0, zero_bo_size);
927
928 if (memcmp(data1_ptr, zero_bo_data, zero_bo_size) == 0 ||
929 memcmp(data2_ptr, zero_bo_data, zero_bo_size) == 0)
930 {
931 TCU_FAIL("One of the draw calls has not outputted any data to XFB buffer object storage");
932 }
933
934 delete[] zero_bo_data;
935 zero_bo_data = NULL;
936 }
937
938 /* Compare the data */
939 if (memcmp(data1_ptr, data2_ptr, vertex_size * n_vertices) != 0)
940 {
941 std::stringstream logMessage;
942
943 logMessage << data_type_string << " data rendered in pass 1: (";
944
945 for (unsigned int n_vertex = 0; n_vertex < n_vertices; ++n_vertex)
946 {
947 logMessage << data1_ptr[n_vertex];
948
949 if (n_vertex != (n_vertices - 1))
950 {
951 logMessage << ", ";
952 }
953 else
954 {
955 logMessage << ") ";
956 }
957 } /* for (all vertices) */
958
959 logMessage << "and in pass 2: (";
960
961 for (unsigned int n_vertex = 0; n_vertex < n_vertices; ++n_vertex)
962 {
963 logMessage << data2_ptr[n_vertex];
964
965 if (n_vertex != (n_vertices - 1))
966 {
967 logMessage << ", ";
968 }
969 else
970 {
971 logMessage << ") ";
972 }
973 } /* for (all vertices) */
974
975 logMessage << "do not match";
976
977 m_testCtx.getLog() << tcu::TestLog::Message << logMessage.str().c_str() << tcu::TestLog::EndMessage;
978
979 TCU_FAIL("Data mismatch");
980 } /* if (data mismatch) */
981 } /* for (all primitive types) */
982 }
983
984 /** Constructor.
985 *
986 * @param context Rendering context.
987 *
988 **/
TessellationShaderInvarianceRule2Test(Context & context,const ExtParameters & extParams)989 TessellationShaderInvarianceRule2Test::TessellationShaderInvarianceRule2Test(Context& context,
990 const ExtParameters& extParams)
991 : TessellationShaderInvarianceBaseTest(context, extParams, "invariance_rule2",
992 "Verifies conformance with second invariance rule")
993 {
994 memset(m_n_tessellated_vertices, 0, sizeof(m_n_tessellated_vertices));
995 }
996
997 /** Destructor. */
~TessellationShaderInvarianceRule2Test()998 TessellationShaderInvarianceRule2Test::~TessellationShaderInvarianceRule2Test()
999 {
1000 /* Left blank intentionally */
1001 }
1002
1003 /** Retrieves amount of iterations the base test implementation should run before
1004 * calling global verification routine.
1005 *
1006 * @return Always 4.
1007 **/
getAmountOfIterations()1008 unsigned int TessellationShaderInvarianceRule2Test::getAmountOfIterations()
1009 {
1010 return 4;
1011 }
1012
1013 /** Retrieves iteration-specific tessellation properties.
1014 *
1015 * @param n_iteration Iteration index to retrieve the properties for.
1016 * @param out_inner_tess_levels Deref will be used to store iteration-specific inner
1017 * tessellation level values. Must not be NULL.
1018 * @param out_outer_tess_levels Deref will be used to store iteration-specific outer
1019 * tessellation level values. Must not be NULL.
1020 * @param out_point_mode Deref will be used to store iteration-specific flag
1021 * telling whether point mode should be enabled for given pass.
1022 * Must not be NULL.
1023 * @param out_primitive_mode Deref will be used to store iteration-specific primitive
1024 * mode. Must not be NULL.
1025 * @param out_vertex_ordering Deref will be used to store iteration-specific vertex
1026 * ordering. Must not be NULL.
1027 * @param out_result_buffer_size Deref will be used to store amount of bytes XFB buffer object
1028 * storage should offer for the draw call to succeed. Can
1029 * be NULL.
1030 **/
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)1031 void TessellationShaderInvarianceRule2Test::getIterationProperties(
1032 unsigned int n_iteration, float* out_inner_tess_levels, float* out_outer_tess_levels, bool* out_point_mode,
1033 _tessellation_primitive_mode* out_primitive_mode, _tessellation_shader_vertex_ordering* out_vertex_ordering,
1034 unsigned int* out_result_buffer_size)
1035 {
1036 *out_vertex_ordering = TESSELLATION_SHADER_VERTEX_ORDERING_CCW;
1037
1038 switch (n_iteration)
1039 {
1040 case 0:
1041 case 1:
1042 {
1043 /* Triangles */
1044 out_outer_tess_levels[0] = 2.0f;
1045 out_outer_tess_levels[1] = 3.0f;
1046 out_outer_tess_levels[2] = 4.0f;
1047
1048 if (n_iteration == 0)
1049 {
1050 out_inner_tess_levels[0] = 4.0f;
1051 out_inner_tess_levels[1] = 5.0f;
1052 }
1053 else
1054 {
1055 out_inner_tess_levels[0] = 3.0f;
1056 out_inner_tess_levels[1] = 4.0f;
1057 }
1058
1059 *out_point_mode = false;
1060 *out_primitive_mode = TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES;
1061
1062 break;
1063 }
1064
1065 case 2:
1066 case 3:
1067 {
1068 /* Quads */
1069 out_outer_tess_levels[0] = 2.0f;
1070 out_outer_tess_levels[1] = 3.0f;
1071 out_outer_tess_levels[2] = 4.0f;
1072 out_outer_tess_levels[3] = 5.0f;
1073
1074 if (n_iteration == 2)
1075 {
1076 out_inner_tess_levels[0] = 2.0f;
1077 out_inner_tess_levels[1] = 3.0f;
1078 }
1079 else
1080 {
1081 out_inner_tess_levels[0] = 4.0f;
1082 out_inner_tess_levels[1] = 5.0f;
1083 }
1084
1085 *out_point_mode = false;
1086 *out_primitive_mode = TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS;
1087
1088 break;
1089 }
1090
1091 default:
1092 {
1093 TCU_FAIL("Unrecognized iteration index");
1094 }
1095 }
1096
1097 if (out_result_buffer_size != DE_NULL)
1098 {
1099 *out_result_buffer_size = m_utils_ptr->getAmountOfVerticesGeneratedByTessellator(
1100 *out_primitive_mode, out_inner_tess_levels, out_outer_tess_levels, TESSELLATION_SHADER_VERTEX_SPACING_EQUAL,
1101 *out_point_mode);
1102
1103 m_n_tessellated_vertices[n_iteration] = *out_result_buffer_size;
1104 *out_result_buffer_size =
1105 static_cast<unsigned int>(*out_result_buffer_size * 3 /* components */ * sizeof(float));
1106
1107 DE_ASSERT(*out_result_buffer_size != 0);
1108 }
1109 }
1110
1111 /** Retrieves iteration-specific tessellation evaluation shader code.
1112 *
1113 * @param n_iteration Iteration index, for which the source code is being obtained.
1114 *
1115 * @return Requested source code.
1116 **/
getTECode(unsigned int n_iteration)1117 std::string TessellationShaderInvarianceRule2Test::getTECode(unsigned int n_iteration)
1118 {
1119 unsigned int bo_size = 0;
1120 float inner_tess_levels[2] = { 0 };
1121 float outer_tess_levels[4] = { 0 };
1122 bool point_mode = false;
1123 _tessellation_primitive_mode primitive_mode = TESSELLATION_SHADER_PRIMITIVE_MODE_UNKNOWN;
1124 _tessellation_shader_vertex_ordering vertex_ordering = TESSELLATION_SHADER_VERTEX_ORDERING_UNKNOWN;
1125
1126 getIterationProperties(n_iteration, inner_tess_levels, outer_tess_levels, &point_mode, &primitive_mode,
1127 &vertex_ordering, &bo_size);
1128
1129 return TessellationShaderUtils::getGenericTECode(TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, primitive_mode,
1130 vertex_ordering, point_mode);
1131 }
1132
1133 /** Verifies result data. Accesses data generated by all iterations.
1134 *
1135 * Throws TestError exception if an error occurs.
1136 *
1137 * @param all_iterations_data An array of pointers to buffers, holding gl_TessCoord
1138 * data generated by subsequent iterations.
1139 **/
verifyResultData(const void ** all_iterations_data)1140 void TessellationShaderInvarianceRule2Test::verifyResultData(const void** all_iterations_data)
1141 {
1142 /* Iterate through one tessellated set of vertices for a given primitive type
1143 * and identify outer vertices. Make sure exactly the same vertices can be
1144 * found in the other set of vertices, generated with different input tessellation
1145 * level.
1146 */
1147 for (int n_primitive_type = 0; n_primitive_type < 2; /* triangles / quads */
1148 ++n_primitive_type)
1149 {
1150 const float* data1_ptr = (const float*)all_iterations_data[n_primitive_type * 2 + 0];
1151 const float* data2_ptr = (const float*)all_iterations_data[n_primitive_type * 2 + 1];
1152 _tessellation_primitive_mode primitive_mode = (n_primitive_type == 0) ?
1153 TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES :
1154 TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS;
1155 std::vector<_vertex> outer_vertices;
1156
1157 /* Iterate through all data1 vertices.. */
1158 for (unsigned int n_vertex = 0; n_vertex < m_n_tessellated_vertices[n_primitive_type * 2]; ++n_vertex)
1159 {
1160 /* Check if any of the components is equal to 0 or 1. If so, this could
1161 * be an edge vertex.
1162 */
1163 const float* vertex_ptr = data1_ptr + n_vertex * 3; /* components */
1164
1165 if (TessellationShaderUtils::isOuterEdgeVertex(primitive_mode, vertex_ptr))
1166 {
1167 /* Only add the vertex if it has not been added already to the vector */
1168 bool has_already_been_added = false;
1169
1170 for (std::vector<_vertex>::const_iterator vertex_iterator = outer_vertices.begin();
1171 vertex_iterator != outer_vertices.end(); vertex_iterator++)
1172 {
1173 if (vertex_iterator->u == vertex_ptr[0] && vertex_iterator->v == vertex_ptr[1] &&
1174 vertex_iterator->w == vertex_ptr[2])
1175 {
1176 has_already_been_added = true;
1177
1178 break;
1179 }
1180 } /* for (all outer vertices stored so far) */
1181
1182 if (!has_already_been_added)
1183 {
1184 _vertex vertex;
1185
1186 vertex.u = vertex_ptr[0];
1187 vertex.v = vertex_ptr[1];
1188 vertex.w = vertex_ptr[2];
1189
1190 outer_vertices.push_back(vertex);
1191 }
1192 } /* if (input vertex is located on outer edge) */
1193 } /* for (all input vertices) */
1194
1195 DE_ASSERT(outer_vertices.size() != 0);
1196
1197 /* Now that we know where outer vertices are, make sure they are present in the other data set */
1198 for (std::vector<_vertex>::const_iterator ref_vertex_iterator = outer_vertices.begin();
1199 ref_vertex_iterator != outer_vertices.end(); ref_vertex_iterator++)
1200 {
1201 bool has_been_found = false;
1202 const _vertex& ref_vertex = *ref_vertex_iterator;
1203
1204 for (unsigned int n_vertex = 0; n_vertex < m_n_tessellated_vertices[n_primitive_type * 2 + 1]; ++n_vertex)
1205 {
1206 const float* vertex_ptr = data2_ptr + n_vertex * 3; /* components */
1207
1208 if (vertex_ptr[0] == ref_vertex.u && vertex_ptr[1] == ref_vertex.v && vertex_ptr[2] == ref_vertex.w)
1209 {
1210 has_been_found = true;
1211
1212 break;
1213 }
1214 } /* for (all vertices in the other data set) */
1215
1216 if (!has_been_found)
1217 {
1218 float cmp_inner_tess_levels[2];
1219 float cmp_outer_tess_levels[4];
1220 bool cmp_point_mode;
1221 _tessellation_primitive_mode cmp_primitive_mode;
1222 _tessellation_shader_vertex_ordering cmp_vertex_ordering;
1223 std::string primitive_type = (n_primitive_type == 0) ? "triangles" : "quads";
1224 float ref_inner_tess_levels[2];
1225 float ref_outer_tess_levels[4];
1226 bool ref_point_mode;
1227 _tessellation_primitive_mode ref_primitive_mode;
1228 _tessellation_shader_vertex_ordering ref_vertex_ordering;
1229
1230 getIterationProperties(n_primitive_type * 2, ref_inner_tess_levels, ref_outer_tess_levels,
1231 &ref_point_mode, &ref_primitive_mode, &ref_vertex_ordering, NULL);
1232 getIterationProperties(n_primitive_type * 2 + 1, cmp_inner_tess_levels, cmp_outer_tess_levels,
1233 &cmp_point_mode, &cmp_primitive_mode, &cmp_vertex_ordering, NULL);
1234
1235 m_testCtx.getLog() << tcu::TestLog::Message << "Outer vertex"
1236 << " (" << ref_vertex.u << ", " << ref_vertex.v << ", " << ref_vertex.w << ")"
1237 << " was not found in tessellated data coordinate set generated"
1238 << " for primitive type: " << primitive_type.c_str()
1239 << ". Reference inner tessellation level:"
1240 << " (" << ref_inner_tess_levels[0] << ", " << ref_inner_tess_levels[1]
1241 << "), reference outer tessellation level:"
1242 << " (" << ref_outer_tess_levels[0] << ", " << ref_outer_tess_levels[1] << ", "
1243 << ref_outer_tess_levels[2] << ", " << ref_outer_tess_levels[3]
1244 << "), test inner tessellation level:"
1245 << " (" << cmp_inner_tess_levels[0] << ", " << cmp_inner_tess_levels[1]
1246 << "), reference outer tessellation level:"
1247 << " (" << cmp_outer_tess_levels[0] << ", " << cmp_outer_tess_levels[1] << ", "
1248 << cmp_outer_tess_levels[2] << ", " << cmp_outer_tess_levels[3] << ")."
1249 << tcu::TestLog::EndMessage;
1250
1251 TCU_FAIL("Outer edge vertex was not found in tessellated coordinate set generated for "
1252 "the same outer tessellation levels and vertex spacing, but different inner "
1253 "tessellation levels");
1254 } /* if (outer edge vertex was not found in the other set) */
1255 } /* for (all outer edge vertices) */
1256 } /* for (both primitive types) */
1257 }
1258
1259 /** Constructor.
1260 *
1261 * @param context Rendering context.
1262 *
1263 **/
TessellationShaderInvarianceRule3Test(Context & context,const ExtParameters & extParams)1264 TessellationShaderInvarianceRule3Test::TessellationShaderInvarianceRule3Test(Context& context,
1265 const ExtParameters& extParams)
1266 : TessellationShaderInvarianceBaseTest(context, extParams, "invariance_rule3",
1267 "Verifies conformance with third invariance rule")
1268 {
1269 }
1270
1271 /** Destructor. */
~TessellationShaderInvarianceRule3Test()1272 TessellationShaderInvarianceRule3Test::~TessellationShaderInvarianceRule3Test()
1273 {
1274 /* Left blank intentionally */
1275 }
1276
1277 /** Retrieves amount of iterations the base test implementation should run before
1278 * calling global verification routine.
1279 *
1280 * @return A value that depends on initTestIterations() behavior.
1281 **/
getAmountOfIterations()1282 unsigned int TessellationShaderInvarianceRule3Test::getAmountOfIterations()
1283 {
1284 if (m_test_iterations.size() == 0)
1285 {
1286 initTestIterations();
1287 }
1288
1289 return (unsigned int)m_test_iterations.size();
1290 }
1291
1292 /** Retrieves iteration-specific tessellation properties.
1293 *
1294 * @param n_iteration Iteration index to retrieve the properties for.
1295 * @param out_inner_tess_levels Deref will be used to store iteration-specific inner
1296 * tessellation level values. Must not be NULL.
1297 * @param out_outer_tess_levels Deref will be used to store iteration-specific outer
1298 * tessellation level values. Must not be NULL.
1299 * @param out_point_mode Deref will be used to store iteration-specific flag
1300 * telling whether point mode should be enabled for given pass.
1301 * Must not be NULL.
1302 * @param out_primitive_mode Deref will be used to store iteration-specific primitive
1303 * mode. Must not be NULL.
1304 * @param out_vertex_ordering Deref will be used to store iteration-specific vertex
1305 * ordering. Must not be NULL.
1306 * @param out_result_buffer_size Deref will be used to store amount of bytes XFB buffer object
1307 * storage should offer for the draw call to succeed. Can
1308 * be NULL.
1309 **/
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)1310 void TessellationShaderInvarianceRule3Test::getIterationProperties(
1311 unsigned int n_iteration, float* out_inner_tess_levels, float* out_outer_tess_levels, bool* out_point_mode,
1312 _tessellation_primitive_mode* out_primitive_mode, _tessellation_shader_vertex_ordering* out_vertex_ordering,
1313 unsigned int* out_result_buffer_size)
1314 {
1315 DE_ASSERT(m_test_iterations.size() > n_iteration);
1316
1317 _test_iteration& test_iteration = m_test_iterations[n_iteration];
1318
1319 memcpy(out_inner_tess_levels, test_iteration.inner_tess_levels, sizeof(test_iteration.inner_tess_levels));
1320 memcpy(out_outer_tess_levels, test_iteration.outer_tess_levels, sizeof(test_iteration.outer_tess_levels));
1321
1322 *out_point_mode = false;
1323 *out_primitive_mode = test_iteration.primitive_mode;
1324 *out_vertex_ordering = TESSELLATION_SHADER_VERTEX_ORDERING_CCW;
1325
1326 if (out_result_buffer_size != DE_NULL)
1327 {
1328 *out_result_buffer_size = m_utils_ptr->getAmountOfVerticesGeneratedByTessellator(
1329 *out_primitive_mode, out_inner_tess_levels, out_outer_tess_levels, test_iteration.vertex_spacing,
1330 *out_point_mode);
1331 test_iteration.n_vertices = *out_result_buffer_size;
1332 *out_result_buffer_size =
1333 static_cast<unsigned int>(*out_result_buffer_size * 3 /* components */ * sizeof(float));
1334
1335 DE_ASSERT(*out_result_buffer_size != 0);
1336 }
1337 }
1338
1339 /** Retrieves iteration-specific tessellation evaluation shader code.
1340 *
1341 * @param n_iteration Iteration index, for which the source code is being obtained.
1342 *
1343 * @return Requested source code.
1344 **/
getTECode(unsigned int n_iteration)1345 std::string TessellationShaderInvarianceRule3Test::getTECode(unsigned int n_iteration)
1346 {
1347 DE_ASSERT(m_test_iterations.size() > n_iteration);
1348
1349 const _test_iteration& test_iteration = m_test_iterations[n_iteration];
1350
1351 return TessellationShaderUtils::getGenericTECode(test_iteration.vertex_spacing, test_iteration.primitive_mode,
1352 TESSELLATION_SHADER_VERTEX_ORDERING_CCW, false); /* point mode */
1353 }
1354
1355 /** Initializes test iterations for the test. The following modes and inner/outer tess level
1356 * configurations are used to form the test set:
1357 *
1358 * - Inner/outer tessellation level combinations as returned by
1359 * TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode()
1360 * - All primitive modes;
1361 * - All vertex spacing modes;
1362 *
1363 * All permutations are used to generate the test set.
1364 **/
initTestIterations()1365 void TessellationShaderInvarianceRule3Test::initTestIterations()
1366 {
1367 DE_ASSERT(m_test_iterations.size() == 0);
1368
1369 /* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value */
1370 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1371 glw::GLint gl_max_tess_gen_level_value = 0;
1372
1373 gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value);
1374 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_GEN_LEVEL_EXT pname");
1375
1376 /* Iterate through all primitive and vertex spacing modes */
1377 _tessellation_primitive_mode primitive_modes[] = { TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES,
1378 TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS,
1379 TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES };
1380 _tessellation_shader_vertex_spacing vs_modes[] = { TESSELLATION_SHADER_VERTEX_SPACING_EQUAL,
1381 TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_EVEN,
1382 TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD };
1383
1384 const unsigned int n_primitive_modes = sizeof(primitive_modes) / sizeof(primitive_modes[0]);
1385 const unsigned int n_vs_modes = sizeof(vs_modes) / sizeof(vs_modes[0]);
1386
1387 for (unsigned int n_primitive_mode = 0; n_primitive_mode < n_primitive_modes; ++n_primitive_mode)
1388 {
1389 _tessellation_primitive_mode primitive_mode = primitive_modes[n_primitive_mode];
1390
1391 for (unsigned int n_vs_mode = 0; n_vs_mode < n_vs_modes; ++n_vs_mode)
1392 {
1393 _tessellation_shader_vertex_spacing vs_mode = vs_modes[n_vs_mode];
1394
1395 /* Retrieve inner/outer tessellation level combinations we want the tests to be run for */
1396 _tessellation_levels_set levels_set;
1397
1398 levels_set = TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode(
1399 primitive_mode, gl_max_tess_gen_level_value,
1400 TESSELLATION_LEVEL_SET_FILTER_ALL_LEVELS_USE_THE_SAME_VALUE);
1401
1402 /* Iterate through all configurations */
1403 for (_tessellation_levels_set_const_iterator levels_iterator = levels_set.begin();
1404 levels_iterator != levels_set.end(); levels_iterator++)
1405 {
1406 const _tessellation_levels& levels = *levels_iterator;
1407
1408 /* Create a test descriptor for all the parameters we now have */
1409 _test_iteration test;
1410
1411 memcpy(test.inner_tess_levels, levels.inner, sizeof(test.inner_tess_levels));
1412 memcpy(test.outer_tess_levels, levels.outer, sizeof(test.outer_tess_levels));
1413
1414 test.primitive_mode = primitive_mode;
1415 test.vertex_spacing = vs_mode;
1416
1417 m_test_iterations.push_back(test);
1418 } /* for (all inner/outer tessellation levels) */
1419 } /* for (all vertex spacing modes) */
1420 } /* for (all primitive modes) */
1421 }
1422
1423 /** Verifies result data on per-iteration basis.
1424 *
1425 * Throws TestError exception if an error occurs.
1426 *
1427 * @param n_iteration Index of iteration the check should be performed for.
1428 * @param data Points to array of vec3s storing the vertices as
1429 * generated by tessellation
1430 **/
verifyResultDataForIteration(unsigned int n_iteration,const void * data)1431 void TessellationShaderInvarianceRule3Test::verifyResultDataForIteration(unsigned int n_iteration, const void* data)
1432 {
1433 DE_ASSERT(m_test_iterations.size() > n_iteration);
1434
1435 const glw::GLfloat* data_float = (const glw::GLfloat*)data;
1436 const _test_iteration& test_iteration = m_test_iterations[n_iteration];
1437
1438 /* Iterate through all generated vertices.. */
1439 for (unsigned int n_vertex = 0; n_vertex < test_iteration.n_vertices; ++n_vertex)
1440 {
1441 _vertex expected_vertex;
1442 const glw::GLfloat* vertex_data = data_float + 3 /* components */ * n_vertex;
1443
1444 expected_vertex.u = -1.0f;
1445 expected_vertex.v = -1.0f;
1446 expected_vertex.w = -1.0f;
1447
1448 /* Make sure that for each vertex, the following language from the extension
1449 * spec is followed:
1450 */
1451 switch (test_iteration.primitive_mode)
1452 {
1453 case TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES:
1454 {
1455 /* For isoline tessellation, if it generates vertices at (0,x) and (1,x)
1456 * where <x> is not zero, it will also generate vertices at exactly (0,1-x)
1457 * and (1,1-x), respectively.
1458 */
1459 if (vertex_data[0] == 0.0f && vertex_data[1] != 0.0f)
1460 {
1461 expected_vertex.u = vertex_data[0];
1462 expected_vertex.v = 1.0f - vertex_data[1];
1463 expected_vertex.w = -1.0f;
1464 }
1465 else if (vertex_data[0] == 1.0f && vertex_data[1] != 0.0f)
1466 {
1467 expected_vertex.u = vertex_data[0];
1468 expected_vertex.v = 1.0f - vertex_data[1];
1469 expected_vertex.w = -1.0f;
1470 }
1471
1472 break;
1473 } /* case TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES: */
1474
1475 case TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS:
1476 {
1477 /* For quad tessellation, if the subdivision generates a vertex with
1478 * coordinates of (x,0) or (0,x), it will also generate a vertex with
1479 * coordinates of exactly (1-x,0) or (0,1-x), respectively.
1480 */
1481 if (vertex_data[0] != 0.0f && vertex_data[1] == 0.0f)
1482 {
1483 expected_vertex.u = 1.0f - vertex_data[0];
1484 expected_vertex.v = vertex_data[1];
1485 expected_vertex.w = -1.0f;
1486 }
1487 else if (vertex_data[0] == 0.0f && vertex_data[1] != 0.0f)
1488 {
1489 expected_vertex.u = vertex_data[0];
1490 expected_vertex.v = 1.0f - vertex_data[1];
1491 expected_vertex.w = -1.0f;
1492 }
1493
1494 break;
1495 } /* case TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS: */
1496
1497 case TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES:
1498 {
1499 /* For triangle tessellation, if the subdivision generates a vertex with
1500 * tessellation coordinates of the form (0,x,1-x), (x,0,1-x), or (x,1-x,0),
1501 * it will also generate a vertex with coordinates of exactly (0,1-x,x),
1502 * (1-x,0,x), or (1-x,x,0), respectively.
1503 */
1504 if (vertex_data[0] == 0.0f && vertex_data[1] != 0.0f && vertex_data[2] == (1.0f - vertex_data[1]))
1505 {
1506 expected_vertex.u = vertex_data[0];
1507 expected_vertex.v = vertex_data[2];
1508 expected_vertex.w = vertex_data[1];
1509 }
1510 else if (vertex_data[0] != 0.0f && vertex_data[1] == 0.0f && vertex_data[2] == (1.0f - vertex_data[0]))
1511 {
1512 expected_vertex.u = vertex_data[2];
1513 expected_vertex.v = vertex_data[1];
1514 expected_vertex.w = vertex_data[0];
1515 }
1516 else if (vertex_data[0] != 0.0f && vertex_data[1] == (1.0f - vertex_data[0]) && vertex_data[2] == 0.0f)
1517 {
1518 expected_vertex.u = vertex_data[1];
1519 expected_vertex.v = vertex_data[0];
1520 expected_vertex.w = vertex_data[2];
1521 }
1522
1523 break;
1524 } /* case TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES: */
1525
1526 default:
1527 {
1528 TCU_FAIL("Primitive mode unrecognized");
1529 }
1530 } /* switch (test_iteration.primitive_mode) */
1531
1532 /* If any of the "expected vertex"'s components is no longer negative,
1533 * make sure the vertex can be found in the result data */
1534 if (expected_vertex.u >= 0.0f || expected_vertex.v >= 0.0f || expected_vertex.w >= 0.0f)
1535 {
1536 bool has_been_found = false;
1537
1538 for (unsigned int n_find_vertex = 0; n_find_vertex < test_iteration.n_vertices; ++n_find_vertex)
1539 {
1540 const glw::GLfloat* current_vertex_data = data_float + 3 /* components */ * n_find_vertex;
1541
1542 const glw::GLfloat epsilon = 1e-4f;
1543 glw::GLfloat absDelta[3] = { de::abs(current_vertex_data[0] - expected_vertex.u),
1544 de::abs(current_vertex_data[1] - expected_vertex.v),
1545 de::abs(current_vertex_data[2] - expected_vertex.w) };
1546
1547 if (absDelta[0] < epsilon && absDelta[1] < epsilon &&
1548 ((expected_vertex.w < 0.0f) || (expected_vertex.w >= 0.0f && absDelta[2] < epsilon)))
1549 {
1550 has_been_found = true;
1551
1552 break;
1553 } /* if (the vertex data matches the expected vertex data) */
1554 } /* for (all generated vertices)*/
1555
1556 if (!has_been_found)
1557 {
1558 TCU_FAIL("Expected symmetrical vertex data was not generated by the tessellator.");
1559 }
1560 } /* if (any of the components of expected_vertex is no longer negative) */
1561 } /* for (all generated vertices) */
1562 }
1563
1564 /** Constructor.
1565 *
1566 * @param context Rendering context.
1567 *
1568 **/
TessellationShaderInvarianceRule4Test(Context & context,const ExtParameters & extParams)1569 TessellationShaderInvarianceRule4Test::TessellationShaderInvarianceRule4Test(Context& context,
1570 const ExtParameters& extParams)
1571 : TessellationShaderInvarianceBaseTest(context, extParams, "invariance_rule4",
1572 "Verifies conformance with fourth invariance rule")
1573 {
1574 }
1575
1576 /** Destructor. */
~TessellationShaderInvarianceRule4Test()1577 TessellationShaderInvarianceRule4Test::~TessellationShaderInvarianceRule4Test()
1578 {
1579 /* Left blank intentionally */
1580 }
1581
1582 /** Retrieves amount of iterations the base test implementation should run before
1583 * calling global verification routine.
1584 *
1585 * @return A value that depends on initTestIterations() behavior.
1586 **/
getAmountOfIterations()1587 unsigned int TessellationShaderInvarianceRule4Test::getAmountOfIterations()
1588 {
1589 if (m_test_iterations.size() == 0)
1590 {
1591 initTestIterations();
1592 }
1593
1594 return (unsigned int)m_test_iterations.size();
1595 }
1596
1597 /** Retrieves iteration-specific tessellation properties.
1598 *
1599 * @param n_iteration Iteration index to retrieve the properties for.
1600 * @param out_inner_tess_levels Deref will be used to store iteration-specific inner
1601 * tessellation level values. Must not be NULL.
1602 * @param out_outer_tess_levels Deref will be used to store iteration-specific outer
1603 * tessellation level values. Must not be NULL.
1604 * @param out_point_mode Deref will be used to store iteration-specific flag
1605 * telling whether point mode should be enabled for given pass.
1606 * Must not be NULL.
1607 * @param out_primitive_mode Deref will be used to store iteration-specific primitive
1608 * mode. Must not be NULL.
1609 * @param out_vertex_ordering Deref will be used to store iteration-specific vertex
1610 * ordering. Must not be NULL.
1611 * @param out_result_buffer_size Deref will be used to store amount of bytes XFB buffer object
1612 * storage should offer for the draw call to succeed. Can
1613 * be NULL.
1614 **/
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)1615 void TessellationShaderInvarianceRule4Test::getIterationProperties(
1616 unsigned int n_iteration, float* out_inner_tess_levels, float* out_outer_tess_levels, bool* out_point_mode,
1617 _tessellation_primitive_mode* out_primitive_mode, _tessellation_shader_vertex_ordering* out_vertex_ordering,
1618 unsigned int* out_result_buffer_size)
1619 {
1620 DE_ASSERT(m_test_iterations.size() > n_iteration);
1621
1622 _test_iteration& test_iteration = m_test_iterations[n_iteration];
1623
1624 memcpy(out_inner_tess_levels, test_iteration.inner_tess_levels, sizeof(test_iteration.inner_tess_levels));
1625 memcpy(out_outer_tess_levels, test_iteration.outer_tess_levels, sizeof(test_iteration.outer_tess_levels));
1626
1627 *out_point_mode = false;
1628 *out_primitive_mode = test_iteration.primitive_mode;
1629 *out_vertex_ordering = TESSELLATION_SHADER_VERTEX_ORDERING_CCW;
1630
1631 if (out_result_buffer_size != DE_NULL)
1632 {
1633 *out_result_buffer_size = m_utils_ptr->getAmountOfVerticesGeneratedByTessellator(
1634 *out_primitive_mode, out_inner_tess_levels, out_outer_tess_levels, test_iteration.vertex_spacing,
1635 *out_point_mode);
1636 test_iteration.n_vertices = *out_result_buffer_size;
1637 *out_result_buffer_size =
1638 static_cast<unsigned int>(*out_result_buffer_size * 3 /* components */ * sizeof(float));
1639
1640 DE_ASSERT(*out_result_buffer_size != 0);
1641 }
1642 }
1643
1644 /** Retrieves iteration-specific tessellation evaluation shader code.
1645 *
1646 * @param n_iteration Iteration index, for which the source code is being obtained.
1647 *
1648 * @return Requested source code.
1649 **/
getTECode(unsigned int n_iteration)1650 std::string TessellationShaderInvarianceRule4Test::getTECode(unsigned int n_iteration)
1651 {
1652 DE_ASSERT(m_test_iterations.size() > n_iteration);
1653
1654 const _test_iteration& test_iteration = m_test_iterations[n_iteration];
1655
1656 return TessellationShaderUtils::getGenericTECode(test_iteration.vertex_spacing, test_iteration.primitive_mode,
1657 TESSELLATION_SHADER_VERTEX_ORDERING_CCW, false); /* point mode */
1658 }
1659
1660 /** Initializes test iterations for the test. The following modes and inner/outer tess level
1661 * configurations are used to form the test set:
1662 *
1663 * - Inner/outer tessellation level combinations as returned by
1664 * TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode()
1665 * - 'Quads' and 'Triangles' primitive modes;
1666 * - All vertex spacing modes;
1667 *
1668 * All permutations are used to generate the test set.
1669 **/
initTestIterations()1670 void TessellationShaderInvarianceRule4Test::initTestIterations()
1671 {
1672 DE_ASSERT(m_test_iterations.size() == 0);
1673
1674 /* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value */
1675 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1676 glw::GLint gl_max_tess_gen_level_value = 0;
1677
1678 gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value);
1679 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_GEN_LEVEL_EXT pname");
1680
1681 /* Iterate through all primitive and vertex spacing modes relevant to the test */
1682 _tessellation_primitive_mode primitive_modes[] = { TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS,
1683 TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES };
1684 _tessellation_shader_vertex_spacing vs_modes[] = { TESSELLATION_SHADER_VERTEX_SPACING_EQUAL,
1685 TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_EVEN,
1686 TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD };
1687
1688 const unsigned int n_primitive_modes = sizeof(primitive_modes) / sizeof(primitive_modes[0]);
1689 const unsigned int n_vs_modes = sizeof(vs_modes) / sizeof(vs_modes[0]);
1690
1691 for (unsigned int n_primitive_mode = 0; n_primitive_mode < n_primitive_modes; ++n_primitive_mode)
1692 {
1693 _tessellation_primitive_mode primitive_mode = primitive_modes[n_primitive_mode];
1694
1695 for (unsigned int n_vs_mode = 0; n_vs_mode < n_vs_modes; ++n_vs_mode)
1696 {
1697 _tessellation_shader_vertex_spacing vs_mode = vs_modes[n_vs_mode];
1698
1699 /* Retrieve inner/outer tessellation level combinations we want the tests to be run for */
1700 _tessellation_levels_set levels;
1701
1702 levels = TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode(
1703 primitive_mode, gl_max_tess_gen_level_value,
1704 TESSELLATION_LEVEL_SET_FILTER_ALL_LEVELS_USE_THE_SAME_VALUE);
1705
1706 /* Iterate through all configurations */
1707 for (_tessellation_levels_set_const_iterator levels_iterator = levels.begin();
1708 levels_iterator != levels.end(); levels_iterator++)
1709 {
1710 const _tessellation_levels& current_levels = *levels_iterator;
1711
1712 /* Create a test descriptor for all the parameters we now have.
1713 *
1714 * The set we're operating on uses different outer tessellation level values, so we
1715 * need to make sure the levels are set to the same FP values in order for the test
1716 * to succeed. */
1717 _test_iteration test;
1718
1719 memcpy(test.inner_tess_levels, current_levels.inner, sizeof(test.inner_tess_levels));
1720
1721 for (int n = 0; n < 4 /* outer tess levels */; ++n)
1722 {
1723 test.outer_tess_levels[n] = current_levels.outer[0];
1724 }
1725
1726 test.primitive_mode = primitive_mode;
1727 test.vertex_spacing = vs_mode;
1728
1729 m_test_iterations.push_back(test);
1730 } /* for (all inner/outer tessellation levels) */
1731 } /* for (all vertex spacing modes) */
1732 } /* for (all primitive modes) */
1733 }
1734
1735 /** Verifies user-provided vertex data can be found in the provided vertex data array.
1736 *
1737 * @param vertex_data Vertex data array the requested vertex data are to be found in.
1738 * @param n_vertices Amount of vertices declared in @param vertex_data;
1739 * @param vertex_data_seeked Vertex data to be found in @param vertex_data;
1740 * @param n_vertex_data_seeked_components Amount of components to take into account.
1741 *
1742 * @return true if the vertex data was found, false otherwise.
1743 **/
isVertexDefined(const float * vertex_data,unsigned int n_vertices,const float * vertex_data_seeked,unsigned int n_vertex_data_seeked_components)1744 bool TessellationShaderInvarianceRule4Test::isVertexDefined(const float* vertex_data, unsigned int n_vertices,
1745 const float* vertex_data_seeked,
1746 unsigned int n_vertex_data_seeked_components)
1747 {
1748 bool result = false;
1749
1750 DE_ASSERT(n_vertex_data_seeked_components >= 2);
1751
1752 for (unsigned int n_vertex = 0; n_vertex < n_vertices; ++n_vertex)
1753 {
1754 const float* current_vertex_data = vertex_data + 3 /* components */ * n_vertex;
1755
1756 if ((vertex_data_seeked[0] == current_vertex_data[0]) && (vertex_data_seeked[1] == current_vertex_data[1]) &&
1757 ((n_vertex_data_seeked_components < 3) ||
1758 (n_vertex_data_seeked_components >= 3 && (vertex_data_seeked[2] == current_vertex_data[2]))))
1759 {
1760 result = true;
1761
1762 break;
1763 } /* if (components match) */
1764 } /* for (all vertices) */
1765
1766 return result;
1767 }
1768
1769 /** Verifies result data on per-iteration basis.
1770 *
1771 * Throws TestError exception if an error occurs.
1772 *
1773 * @param n_iteration Index of iteration the check should be performed for.
1774 * @param data Points to array of vec3s storing the vertices as
1775 * generated by tessellation
1776 **/
verifyResultDataForIteration(unsigned int n_iteration,const void * data)1777 void TessellationShaderInvarianceRule4Test::verifyResultDataForIteration(unsigned int n_iteration, const void* data)
1778 {
1779 DE_ASSERT(m_test_iterations.size() > n_iteration);
1780
1781 const glw::GLfloat* data_float = (const glw::GLfloat*)data;
1782 const _test_iteration& test_iteration = m_test_iterations[n_iteration];
1783
1784 /* Iterate through all generated vertices.. */
1785 for (unsigned int n_vertex = 0; n_vertex < test_iteration.n_vertices; ++n_vertex)
1786 {
1787 std::vector<_vertex> expected_vertices;
1788 const glw::GLfloat* vertex_data = data_float + 3 /* components */ * n_vertex;
1789
1790 /* Make sure that for each vertex, the following language from the extension
1791 * spec is followed:
1792 */
1793 switch (test_iteration.primitive_mode)
1794 {
1795 case TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS:
1796 {
1797 /* For quad tessellation, if vertices at (x,0) and (1-x,0) are generated
1798 * when subdividing the v==0 edge, vertices must be generated at (0,x) and
1799 * (0,1-x) when subdividing an otherwise identical u==0 edge.
1800 */
1801 if (vertex_data[0] != 0.0f && vertex_data[1] == 0.0f)
1802 {
1803 const float paired_vertex_data[] = { 1.0f - vertex_data[0], vertex_data[1] };
1804
1805 if (isVertexDefined(data_float, test_iteration.n_vertices, paired_vertex_data, 2)) /* components */
1806 {
1807 _vertex expected_vertex;
1808
1809 /* First expected vertex */
1810 expected_vertex.u = vertex_data[1];
1811 expected_vertex.v = vertex_data[0];
1812 expected_vertex.w = -1.0f;
1813
1814 expected_vertices.push_back(expected_vertex);
1815
1816 /* The other expected vertex */
1817 expected_vertex.u = vertex_data[1];
1818 expected_vertex.v = 1.0f - vertex_data[0];
1819
1820 expected_vertices.push_back(expected_vertex);
1821 } /* if (the other required vertex is defined) */
1822 } /* if (the first required vertex is defined) */
1823
1824 break;
1825 } /* case TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS: */
1826
1827 case TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES:
1828 {
1829 /* For triangular tessellation, if vertices at (x,1-x,0) and (1-x,x,0) are
1830 * generated when subdividing the w==0 edge, vertices must be generated at
1831 * (x,0,1-x) and (1-x,0,x) when subdividing an otherwise identical v==0
1832 * edge.
1833 */
1834 if (vertex_data[0] != 0.0f && vertex_data[1] == (1.0f - vertex_data[0]) && vertex_data[2] == 0)
1835 {
1836 const float paired_vertex_data[] = { vertex_data[1], vertex_data[0], vertex_data[2] };
1837
1838 if (isVertexDefined(data_float, test_iteration.n_vertices, paired_vertex_data, 3)) /* components */
1839 {
1840 _vertex expected_vertex;
1841
1842 /* First expected vertex */
1843 expected_vertex.u = vertex_data[0];
1844 expected_vertex.v = vertex_data[2];
1845 expected_vertex.w = vertex_data[1];
1846
1847 expected_vertices.push_back(expected_vertex);
1848
1849 /* The other expected vertex */
1850 expected_vertex.u = vertex_data[1];
1851 expected_vertex.v = vertex_data[2];
1852 expected_vertex.w = vertex_data[0];
1853
1854 expected_vertices.push_back(expected_vertex);
1855 } /* if (the other required vertex is defined) */
1856 } /* if (the firsst required vertex is defined) */
1857
1858 break;
1859 } /* case TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES: */
1860
1861 default:
1862 {
1863 TCU_FAIL("Primitive mode unrecognized");
1864 }
1865 } /* switch (test_iteration.primitive_mode) */
1866
1867 /* Iterate through all expected vertices */
1868 for (std::vector<_vertex>::const_iterator expected_vertex_iterator = expected_vertices.begin();
1869 expected_vertex_iterator != expected_vertices.end(); expected_vertex_iterator++)
1870 {
1871 const _vertex& expected_vertex = *expected_vertex_iterator;
1872 const float expected_vertex_raw[] = { expected_vertex.u, expected_vertex.v, expected_vertex.w };
1873 bool has_been_found = false;
1874
1875 has_been_found = isVertexDefined(data_float, test_iteration.n_vertices, expected_vertex_raw,
1876 (expected_vertex.w < 0) ? 2 : 3);
1877
1878 if (!has_been_found)
1879 {
1880 std::stringstream expected_vertex_sstream;
1881
1882 expected_vertex_sstream << expected_vertex.u << ", " << expected_vertex.v;
1883
1884 if (expected_vertex.w >= 0.0f)
1885 {
1886 expected_vertex_sstream << ", " << expected_vertex.w;
1887 }
1888
1889 m_testCtx.getLog() << tcu::TestLog::Message << "For primitive mode:"
1890 << "["
1891 << TessellationShaderUtils::getESTokenForPrimitiveMode(test_iteration.primitive_mode)
1892 << "]"
1893 << "and vertex spacing mode:"
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, TESSELLATION_SHADER_VERTEX_ORDERING_CW,
2053 };
2054
2055 const unsigned int n_primitive_modes = sizeof(primitive_modes) / sizeof(primitive_modes[0]);
2056 const unsigned int n_vo_modes = sizeof(vo_modes) / sizeof(vo_modes[0]);
2057
2058 for (unsigned int n_primitive_mode = 0; n_primitive_mode < n_primitive_modes; ++n_primitive_mode)
2059 {
2060 _tessellation_primitive_mode primitive_mode = primitive_modes[n_primitive_mode];
2061
2062 for (unsigned int n_vo_mode = 0; n_vo_mode < n_vo_modes; ++n_vo_mode)
2063 {
2064 _tessellation_shader_vertex_ordering vertex_ordering = vo_modes[n_vo_mode];
2065
2066 /* Retrieve inner/outer tessellation level combinations we want the tests to be run for */
2067 _tessellation_levels_set levels_set;
2068
2069 levels_set = TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode(
2070 primitive_mode, gl_max_tess_gen_level_value,
2071 TESSELLATION_LEVEL_SET_FILTER_ALL_LEVELS_USE_THE_SAME_VALUE);
2072
2073 /* Only use the last inner/outer level configuration, as reported by the utils function. */
2074 const _tessellation_levels& levels = levels_set[levels_set.size() - 1];
2075
2076 /* Create a test descriptor for all the parameters we now have */
2077 _test_iteration test;
2078
2079 memcpy(test.inner_tess_levels, levels.inner, sizeof(test.inner_tess_levels));
2080 memcpy(test.outer_tess_levels, levels.outer, sizeof(test.outer_tess_levels));
2081
2082 test.primitive_mode = primitive_mode;
2083 test.vertex_ordering = vertex_ordering;
2084
2085 if (primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES)
2086 {
2087 m_test_triangles_iterations.push_back(test);
2088 }
2089 else
2090 {
2091 m_test_quads_iterations.push_back(test);
2092 }
2093 } /* for (all vertex spacing modes) */
2094 } /* for (all primitive modes) */
2095 }
2096
2097 /** Verifies user-provided vertex data can be found in the provided vertex data array.
2098 *
2099 * @param vertex_data Vertex data array the requested vertex data are to be found in.
2100 * @param n_vertices Amount of vertices declared in @param vertex_data;
2101 * @param vertex_data_seeked Vertex data to be found in @param vertex_data;
2102 * @param n_vertex_data_seeked_components Amount of components to take into account.
2103 *
2104 * @return true if the vertex data was found, false otherwise.
2105 **/
isVertexDefined(const float * vertex_data,unsigned int n_vertices,const float * vertex_data_seeked,unsigned int n_vertex_data_seeked_components)2106 bool TessellationShaderInvarianceRule5Test::isVertexDefined(const float* vertex_data, unsigned int n_vertices,
2107 const float* vertex_data_seeked,
2108 unsigned int n_vertex_data_seeked_components)
2109 {
2110 const float epsilon = 1e-5f;
2111 bool result = false;
2112
2113 DE_ASSERT(n_vertex_data_seeked_components >= 2);
2114
2115 for (unsigned int n_vertex = 0; n_vertex < n_vertices; ++n_vertex)
2116 {
2117 const float* current_vertex_data = vertex_data + 3 /* components */ * n_vertex;
2118
2119 if (de::abs(vertex_data_seeked[0] - current_vertex_data[0]) < epsilon &&
2120 de::abs(vertex_data_seeked[1] - current_vertex_data[1]) < epsilon &&
2121 ((n_vertex_data_seeked_components < 3) ||
2122 (n_vertex_data_seeked_components >= 3 &&
2123 de::abs(vertex_data_seeked[2] - current_vertex_data[2]) < epsilon)))
2124 {
2125 result = true;
2126
2127 break;
2128 } /* if (components match) */
2129 } /* for (all vertices) */
2130
2131 return result;
2132 }
2133
2134 /** Verifies result data. Accesses data generated by all iterations.
2135 *
2136 * Throws TestError exception if an error occurs.
2137 *
2138 * @param all_iterations_data An array of pointers to buffers, holding gl_TessCoord
2139 * data generated by subsequent iterations.
2140 **/
verifyResultData(const void ** all_iterations_data)2141 void TessellationShaderInvarianceRule5Test::verifyResultData(const void** all_iterations_data)
2142 {
2143 /* Run two separate iterations:
2144 *
2145 * a) triangles
2146 * b) quads
2147 */
2148 for (unsigned int n_iteration = 0; n_iteration < 2 /* quads, triangles */; ++n_iteration)
2149 {
2150 const unsigned int n_base_iteration =
2151 (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 =
2421 (n_iteration == 0) ? 0 : (unsigned int)m_test_triangles_iterations.size();
2422
2423 const unsigned int n_sets = (n_iteration == 0) ? (unsigned int)m_test_triangles_iterations.size() :
2424 (unsigned int)m_test_quads_iterations.size();
2425
2426 _tessellation_primitive_mode primitive_mode = (n_iteration == 0) ?
2427 TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES :
2428 TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS;
2429
2430 const _test_iterations& test_iterations =
2431 (n_iteration == 0) ? m_test_triangles_iterations : m_test_quads_iterations;
2432
2433 const unsigned int n_triangles_in_base_set = test_iterations[0].n_vertices / 3 /* vertices per triangle */;
2434
2435 DE_ASSERT(test_iterations.size() != 0);
2436
2437 /* For each iteration, verify that all vertices generated for all three vertex spacing modes.
2438 * are exactly the same (but in different order) */
2439 const _test_iteration& base_test = test_iterations[0];
2440 const float* base_vertex_data = (const float*)all_iterations_data[n_base_iteration + 0];
2441
2442 for (unsigned int n_set = 1; n_set < n_sets; ++n_set)
2443 {
2444 const _test_iteration& set_test = test_iterations[n_set];
2445 const float* set_vertex_data = (const float*)all_iterations_data[n_base_iteration + n_set];
2446
2447 /* We're operating on triangles so make sure the amount of vertices we're dealing with is
2448 * divisible by 3 */
2449 DE_ASSERT((test_iterations[n_set].n_vertices % 3) == 0);
2450
2451 const unsigned int n_triangles_in_curr_set = test_iterations[n_set].n_vertices / 3;
2452
2453 /* Take base triangles and make sure they can be found in iteration-specific set.
2454 * Now, thing to keep in mind here is that we must not assume any specific vertex
2455 * and triangle order which is why the slow search. */
2456 for (unsigned int n_base_triangle = 0; n_base_triangle < n_triangles_in_base_set; ++n_base_triangle)
2457 {
2458 /* Extract base triangle data first */
2459 const float* base_triangle_vertex1 = base_vertex_data +
2460 n_base_triangle * 3 * /* vertices per triangle */
2461 3; /* components */
2462 const float* base_triangle_vertex2 = base_triangle_vertex1 + 3; /* components */
2463 const float* base_triangle_vertex3 = base_triangle_vertex2 + 3; /* components */
2464
2465 /* Only interior triangles should be left intact. Is this an interior triangle? */
2466 if (!TessellationShaderUtils::isOuterEdgeVertex(primitive_mode, base_triangle_vertex1) &&
2467 !TessellationShaderUtils::isOuterEdgeVertex(primitive_mode, base_triangle_vertex2) &&
2468 !TessellationShaderUtils::isOuterEdgeVertex(primitive_mode, base_triangle_vertex3))
2469 {
2470 /* Iterate through all triangles in considered set */
2471 bool has_base_set_triangle_been_found = false;
2472
2473 for (unsigned int n_curr_set_triangle = 0; n_curr_set_triangle < n_triangles_in_curr_set;
2474 ++n_curr_set_triangle)
2475 {
2476 const float* curr_triangle = set_vertex_data +
2477 n_curr_set_triangle * 3 * /* vertices per triangle */
2478 3; /* components */
2479
2480 if (TessellationShaderUtils::isTriangleDefined(base_triangle_vertex1, curr_triangle))
2481 {
2482 has_base_set_triangle_been_found = true;
2483
2484 break;
2485 }
2486 } /* for (all triangles in currently processed set) */
2487
2488 if (!has_base_set_triangle_been_found)
2489 {
2490 std::string primitive_mode_str =
2491 TessellationShaderUtils::getESTokenForPrimitiveMode(base_test.primitive_mode);
2492
2493 m_testCtx.getLog()
2494 << tcu::TestLog::Message << "For primitive mode [" << primitive_mode_str << "]"
2495 << ", base inner tessellation levels:"
2496 << "[" << base_test.inner_tess_levels[0] << ", " << base_test.inner_tess_levels[1] << "]"
2497 << ", base outer tessellation levels:"
2498 << "[" << base_test.outer_tess_levels[0] << ", " << base_test.outer_tess_levels[1] << ", "
2499 << base_test.outer_tess_levels[2] << ", " << base_test.outer_tess_levels[3] << "]"
2500 << ", reference inner tessellation levels:"
2501 << "[" << set_test.inner_tess_levels[0] << ", " << set_test.inner_tess_levels[1] << "]"
2502 << ", reference outer tessellation levels:"
2503 << "[" << set_test.outer_tess_levels[0] << ", " << set_test.outer_tess_levels[1] << ", "
2504 << set_test.outer_tess_levels[2] << ", " << set_test.outer_tess_levels[3] << "]"
2505 << ", the following triangle formed during base tessellation run was not found in "
2506 "reference run:"
2507 << "[" << base_triangle_vertex1[0] << ", " << base_triangle_vertex1[1] << ", "
2508 << base_triangle_vertex1[2] << "]x"
2509 << "[" << base_triangle_vertex2[0] << ", " << base_triangle_vertex2[1] << ", "
2510 << base_triangle_vertex2[2] << "]x"
2511 << "[" << base_triangle_vertex3[0] << ", " << base_triangle_vertex3[1] << ", "
2512 << base_triangle_vertex3[2]
2513
2514 << tcu::TestLog::EndMessage;
2515
2516 TCU_FAIL("Implementation does not appear to be rule 6-conformant");
2517 } /* if (triangle created during base run was not found in reference run) */
2518 } /* if (base triangle is interior) */
2519 } /* for (all base set's vertices) */
2520 } /* for (all sets) */
2521 } /* for (both primitive types) */
2522 }
2523
2524 /** Constructor.
2525 *
2526 * @param context Rendering context.
2527 *
2528 **/
TessellationShaderInvarianceRule7Test(Context & context,const ExtParameters & extParams)2529 TessellationShaderInvarianceRule7Test::TessellationShaderInvarianceRule7Test(Context& context,
2530 const ExtParameters& extParams)
2531 : TessellationShaderInvarianceBaseTest(context, extParams, "invariance_rule7",
2532 "Verifies conformance with seventh invariance rule")
2533 {
2534 }
2535
2536 /** Destructor. */
~TessellationShaderInvarianceRule7Test()2537 TessellationShaderInvarianceRule7Test::~TessellationShaderInvarianceRule7Test()
2538 {
2539 /* Left blank intentionally */
2540 }
2541
2542 /** Retrieves amount of iterations the base test implementation should run before
2543 * calling global verification routine.
2544 *
2545 * @return A value that depends on initTestIterations() behavior.
2546 **/
getAmountOfIterations()2547 unsigned int TessellationShaderInvarianceRule7Test::getAmountOfIterations()
2548 {
2549 if (m_test_quads_iterations.size() == 0 || m_test_triangles_iterations.size() == 0)
2550 {
2551 initTestIterations();
2552 }
2553
2554 return (unsigned int)(m_test_quads_iterations.size() + m_test_triangles_iterations.size());
2555 }
2556
2557 /** Retrieves index of a test iteration that was initialized with user-provided
2558 * properties.
2559 *
2560 * @param is_triangles_iteration true if the seeked test iteration should have
2561 * been run for 'triangles' primitive mode', false
2562 * if 'quads' primitive mode run is seeked.
2563 * @param inner_tess_levels Two FP values describing inner tessellation level
2564 * values the seeked run should have used.
2565 * @param outer_tess_levels Four FP values describing outer tessellation level
2566 * values the seeked run should have used.
2567 * @param vertex_ordering Vertex ordering mode the seeked run should have used.
2568 * @param n_modified_outer_tess_level Tells which outer tessellation level should be
2569 * excluded from checking.
2570 *
2571 * @return 0xFFFFFFFF if no test iteration was run for user-provided properties,
2572 * actual index otherwise.
2573 *
2574 **/
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)2575 unsigned int TessellationShaderInvarianceRule7Test::getTestIterationIndex(
2576 bool is_triangles_iteration, const float* inner_tess_levels, const float* outer_tess_levels,
2577 _tessellation_shader_vertex_ordering vertex_ordering, unsigned int n_modified_outer_tess_level)
2578 {
2579 const float epsilon = 1e-5f;
2580 unsigned int result = 0xFFFFFFFF;
2581 const _test_iterations& test_iterations =
2582 (is_triangles_iteration) ? m_test_triangles_iterations : m_test_quads_iterations;
2583 const unsigned int n_test_iterations = (unsigned int)test_iterations.size();
2584
2585 for (unsigned int n_test_iteration = 0; n_test_iteration < n_test_iterations; ++n_test_iteration)
2586 {
2587 _test_iteration test_iteration = test_iterations[n_test_iteration];
2588
2589 if (de::abs(test_iteration.inner_tess_levels[0] - inner_tess_levels[0]) < epsilon &&
2590 de::abs(test_iteration.inner_tess_levels[1] - inner_tess_levels[1]) < epsilon &&
2591 test_iteration.vertex_ordering == vertex_ordering &&
2592 test_iteration.n_modified_outer_tess_level == n_modified_outer_tess_level)
2593 {
2594 /* Only compare outer tessellation levels that have not been modified */
2595 if (((n_modified_outer_tess_level == 0) ||
2596 (n_modified_outer_tess_level != 0 &&
2597 de::abs(test_iteration.outer_tess_levels[0] - outer_tess_levels[0]) < epsilon)) &&
2598 ((n_modified_outer_tess_level == 1) ||
2599 (n_modified_outer_tess_level != 1 &&
2600 de::abs(test_iteration.outer_tess_levels[1] - outer_tess_levels[1]) < epsilon)) &&
2601 ((n_modified_outer_tess_level == 2) ||
2602 (n_modified_outer_tess_level != 2 &&
2603 de::abs(test_iteration.outer_tess_levels[2] - outer_tess_levels[2]) < epsilon)) &&
2604 ((n_modified_outer_tess_level == 3) ||
2605 (n_modified_outer_tess_level != 3 &&
2606 de::abs(test_iteration.outer_tess_levels[3] - outer_tess_levels[3]) < epsilon)))
2607 {
2608 result = n_test_iteration;
2609
2610 break;
2611 }
2612 }
2613 } /* for (all test iterations) */
2614
2615 return result;
2616 }
2617
2618 /** Retrieves _test_iteration instance specific for user-specified iteration index.
2619 *
2620 * @param n_iteration Iteration index to retrieve _test_iteration instance for.
2621 *
2622 * @return Iteration-specific _test_iteration instance.
2623 *
2624 **/
getTestForIteration(unsigned int n_iteration)2625 TessellationShaderInvarianceRule7Test::_test_iteration& TessellationShaderInvarianceRule7Test::getTestForIteration(
2626 unsigned int n_iteration)
2627 {
2628 unsigned int n_triangles_tests = (unsigned int)m_test_triangles_iterations.size();
2629 _test_iteration& test_iteration = (n_iteration < n_triangles_tests) ?
2630 m_test_triangles_iterations[n_iteration] :
2631 m_test_quads_iterations[n_iteration - n_triangles_tests];
2632
2633 return test_iteration;
2634 }
2635
2636 /** Retrieves iteration-specific tessellation properties.
2637 *
2638 * @param n_iteration Iteration index to retrieve the properties for.
2639 * @param out_inner_tess_levels Deref will be used to store iteration-specific inner
2640 * tessellation level values. Must not be NULL.
2641 * @param out_outer_tess_levels Deref will be used to store iteration-specific outer
2642 * tessellation level values. Must not be NULL.
2643 * @param out_point_mode Deref will be used to store iteration-specific flag
2644 * telling whether point mode should be enabled for given pass.
2645 * Must not be NULL.
2646 * @param out_primitive_mode Deref will be used to store iteration-specific primitive
2647 * mode. Must not be NULL.
2648 * @param out_vertex_ordering Deref will be used to store iteration-specific vertex
2649 * ordering. Must not be NULL.
2650 * @param out_result_buffer_size Deref will be used to store amount of bytes XFB buffer object
2651 * storage should offer for the draw call to succeed. Can
2652 * be NULL.
2653 **/
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)2654 void TessellationShaderInvarianceRule7Test::getIterationProperties(
2655 unsigned int n_iteration, float* out_inner_tess_levels, float* out_outer_tess_levels, bool* out_point_mode,
2656 _tessellation_primitive_mode* out_primitive_mode, _tessellation_shader_vertex_ordering* out_vertex_ordering,
2657 unsigned int* out_result_buffer_size)
2658 {
2659 DE_ASSERT(m_test_triangles_iterations.size() + m_test_quads_iterations.size() > n_iteration);
2660
2661 _test_iteration& test_iteration = getTestForIteration(n_iteration);
2662
2663 memcpy(out_inner_tess_levels, test_iteration.inner_tess_levels, sizeof(test_iteration.inner_tess_levels));
2664 memcpy(out_outer_tess_levels, test_iteration.outer_tess_levels, sizeof(test_iteration.outer_tess_levels));
2665
2666 *out_point_mode = false;
2667 *out_primitive_mode = test_iteration.primitive_mode;
2668 *out_vertex_ordering = test_iteration.vertex_ordering;
2669
2670 if (out_result_buffer_size != DE_NULL)
2671 {
2672 *out_result_buffer_size = m_utils_ptr->getAmountOfVerticesGeneratedByTessellator(
2673 *out_primitive_mode, out_inner_tess_levels, out_outer_tess_levels, TESSELLATION_SHADER_VERTEX_SPACING_EQUAL,
2674 *out_point_mode);
2675 test_iteration.n_vertices = *out_result_buffer_size;
2676 *out_result_buffer_size =
2677 static_cast<unsigned int>(*out_result_buffer_size * 3 /* components */ * sizeof(float));
2678
2679 DE_ASSERT(*out_result_buffer_size != 0);
2680 }
2681 }
2682
2683 /** Retrieves iteration-specific tessellation evaluation shader code.
2684 *
2685 * @param n_iteration Iteration index, for which the source code is being obtained.
2686 *
2687 * @return Requested source code.
2688 **/
getTECode(unsigned int n_iteration)2689 std::string TessellationShaderInvarianceRule7Test::getTECode(unsigned int n_iteration)
2690 {
2691 DE_ASSERT(m_test_triangles_iterations.size() + m_test_quads_iterations.size() > n_iteration);
2692
2693 const _test_iteration& test_iteration = getTestForIteration(n_iteration);
2694
2695 return TessellationShaderUtils::getGenericTECode(TESSELLATION_SHADER_VERTEX_SPACING_EQUAL,
2696 test_iteration.primitive_mode, test_iteration.vertex_ordering,
2697 false); /* point mode */
2698 }
2699
2700 /** Initializes test iterations for the test. The following modes and inner/outer tess level
2701 * configurations are used to form the test set:
2702 *
2703 * - All inner/outer tessellation level combinations as returned by
2704 * TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode()
2705 * times 3 (for triangles) or 4 (for quads). For each combination,
2706 * the test will capture tessellation coordinates multiple times, each
2707 * time changing a different outer tessellation level value and leaving
2708 * the rest intact.
2709 * - All primitive modes;
2710 * - All vertex spacing modes;
2711 *
2712 * All permutations are used to generate the test set.
2713 **/
initTestIterations()2714 void TessellationShaderInvarianceRule7Test::initTestIterations()
2715 {
2716 DE_ASSERT(m_test_quads_iterations.size() == 0 && m_test_triangles_iterations.size() == 0);
2717
2718 /* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value */
2719 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2720 glw::GLint gl_max_tess_gen_level_value = 0;
2721
2722 gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value);
2723 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_GEN_LEVEL_EXT pname");
2724
2725 /* Iterate through all primitive and vertex spacing modes relevant to the test */
2726 _tessellation_primitive_mode primitive_modes[] = { TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS,
2727 TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES };
2728 _tessellation_shader_vertex_ordering vo_modes[] = {
2729 TESSELLATION_SHADER_VERTEX_ORDERING_CCW, 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 +
2820 n_triangle * 3 * /* vertices per triangle */
2821 3; /* components */
2822
2823 if (TessellationShaderUtils::isTriangleDefined(current_triangle_data, base_triangle_data))
2824 {
2825 result = true;
2826
2827 break;
2828 }
2829 } /* for (all vertices) */
2830
2831 return result;
2832 }
2833
2834 /** Verifies result data. Accesses data generated by all iterations.
2835 *
2836 * Throws TestError exception if an error occurs.
2837 *
2838 * @param all_iterations_data An array of pointers to buffers, holding gl_TessCoord
2839 * data generated by subsequent iterations.
2840 **/
verifyResultData(const void ** all_iterations_data)2841 void TessellationShaderInvarianceRule7Test::verifyResultData(const void** all_iterations_data)
2842 {
2843 const float epsilon = 1e-5f;
2844
2845 /* Run two separate iterations:
2846 *
2847 * a) triangles
2848 * b) quads
2849 */
2850 for (unsigned int n_iteration = 0; n_iteration < 2 /* triangles, quads */; ++n_iteration)
2851 {
2852 bool is_triangles_iteration = (n_iteration == 0);
2853 const unsigned int n_base_iteration =
2854 (n_iteration == 0) ? 0 : (unsigned int)m_test_triangles_iterations.size();
2855 const unsigned int n_relevant_outer_tess_levels = (is_triangles_iteration) ? 3 : 4;
2856
2857 _tessellation_primitive_mode primitive_mode = (n_iteration == 0) ?
2858 TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES :
2859 TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS;
2860
2861 const _test_iterations& test_iterations =
2862 (n_iteration == 0) ? m_test_triangles_iterations : m_test_quads_iterations;
2863
2864 DE_ASSERT(test_iterations.size() != 0);
2865
2866 /* Find a base iteration first */
2867 for (unsigned int n_base_test_iteration = 0; n_base_test_iteration < test_iterations.size();
2868 n_base_test_iteration++)
2869 {
2870 const _test_iteration& base_iteration = test_iterations[n_base_test_iteration];
2871 std::vector<int> ref_iteration_indices;
2872
2873 if (!base_iteration.is_base_iteration)
2874 {
2875 continue;
2876 }
2877
2878 /* Retrieve reference test iterations */
2879 for (unsigned int n_reference_iteration = 0; n_reference_iteration < n_relevant_outer_tess_levels;
2880 ++n_reference_iteration)
2881 {
2882 const unsigned int n_modified_outer_tess_level =
2883 (base_iteration.n_modified_outer_tess_level + n_reference_iteration + 1) %
2884 n_relevant_outer_tess_levels;
2885 const unsigned int ref_iteration_index = getTestIterationIndex(
2886 is_triangles_iteration, base_iteration.inner_tess_levels, base_iteration.outer_tess_levels,
2887 base_iteration.vertex_ordering, n_modified_outer_tess_level);
2888
2889 DE_ASSERT(ref_iteration_index != 0xFFFFFFFF);
2890 DE_ASSERT(ref_iteration_index != n_base_test_iteration);
2891
2892 ref_iteration_indices.push_back(ref_iteration_index);
2893 }
2894
2895 /* We can now start comparing base data with the information generated for
2896 * reference iterations. */
2897 for (std::vector<int>::const_iterator ref_iteration_iterator = ref_iteration_indices.begin();
2898 ref_iteration_iterator != ref_iteration_indices.end(); ref_iteration_iterator++)
2899 {
2900 const int& n_ref_test_iteration = *ref_iteration_iterator;
2901 const _test_iteration& ref_iteration = test_iterations[n_ref_test_iteration];
2902
2903 /* Now move through all triangles generated for base test iteration. Focus on the ones
2904 * that connect the outer edge with one of the inner ones */
2905 const float* base_iteration_vertex_data =
2906 (const float*)all_iterations_data[n_base_iteration + n_base_test_iteration];
2907 const float* ref_iteration_vertex_data =
2908 (const float*)all_iterations_data[n_base_iteration + n_ref_test_iteration];
2909
2910 for (unsigned int n_base_triangle = 0;
2911 n_base_triangle < base_iteration.n_vertices / 3; /* vertices per triangle */
2912 ++n_base_triangle)
2913 {
2914 const float* base_triangle_data =
2915 base_iteration_vertex_data + n_base_triangle * 3 /* vertices */ * 3; /* components */
2916
2917 /* Is that the triangle type we're after? */
2918 const float* base_triangle_vertex1 = base_triangle_data;
2919 const float* base_triangle_vertex2 = base_triangle_vertex1 + 3; /* components */
2920 const float* base_triangle_vertex3 = base_triangle_vertex2 + 3; /* components */
2921 bool is_base_triangle_vertex1_outer =
2922 TessellationShaderUtils::isOuterEdgeVertex(primitive_mode, base_triangle_vertex1);
2923 bool is_base_triangle_vertex2_outer =
2924 TessellationShaderUtils::isOuterEdgeVertex(primitive_mode, base_triangle_vertex2);
2925 bool is_base_triangle_vertex3_outer =
2926 TessellationShaderUtils::isOuterEdgeVertex(primitive_mode, base_triangle_vertex3);
2927 unsigned int n_outer_edge_vertices_found = 0;
2928
2929 n_outer_edge_vertices_found += (is_base_triangle_vertex1_outer == true);
2930 n_outer_edge_vertices_found += (is_base_triangle_vertex2_outer == true);
2931 n_outer_edge_vertices_found += (is_base_triangle_vertex3_outer == true);
2932
2933 if (n_outer_edge_vertices_found == 0)
2934 {
2935 /* This is an inner triangle, not really of our interest */
2936 continue;
2937 }
2938
2939 /* Which outer tessellation level describes the base data edge? */
2940 unsigned int n_base_tess_level = 0;
2941
2942 if (primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES)
2943 {
2944 if ((!is_base_triangle_vertex1_outer ||
2945 (is_base_triangle_vertex1_outer && base_triangle_vertex1[0] == 0.0f)) &&
2946 (!is_base_triangle_vertex2_outer ||
2947 (is_base_triangle_vertex2_outer && base_triangle_vertex2[0] == 0.0f)) &&
2948 (!is_base_triangle_vertex3_outer ||
2949 (is_base_triangle_vertex3_outer && base_triangle_vertex3[0] == 0.0f)))
2950 {
2951 n_base_tess_level = 0;
2952 }
2953 else if ((!is_base_triangle_vertex1_outer ||
2954 (is_base_triangle_vertex1_outer && base_triangle_vertex1[1] == 0.0f)) &&
2955 (!is_base_triangle_vertex2_outer ||
2956 (is_base_triangle_vertex2_outer && base_triangle_vertex2[1] == 0.0f)) &&
2957 (!is_base_triangle_vertex3_outer ||
2958 (is_base_triangle_vertex3_outer && base_triangle_vertex3[1] == 0.0f)))
2959 {
2960 n_base_tess_level = 1;
2961 }
2962 else
2963 {
2964 DE_ASSERT((!is_base_triangle_vertex1_outer ||
2965 (is_base_triangle_vertex1_outer && base_triangle_vertex1[2] == 0.0f)) &&
2966 (!is_base_triangle_vertex2_outer ||
2967 (is_base_triangle_vertex2_outer && base_triangle_vertex2[2] == 0.0f)) &&
2968 (!is_base_triangle_vertex3_outer ||
2969 (is_base_triangle_vertex3_outer && base_triangle_vertex3[2] == 0.0f)));
2970
2971 n_base_tess_level = 2;
2972 }
2973 } /* if (primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES) */
2974 else
2975 {
2976 DE_ASSERT(primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS);
2977
2978 std::size_t n_outer_edge_vertices = 0;
2979 std::vector<const float*> outer_edge_vertices;
2980
2981 if (is_base_triangle_vertex1_outer)
2982 {
2983 outer_edge_vertices.push_back(base_triangle_vertex1);
2984 }
2985
2986 if (is_base_triangle_vertex2_outer)
2987 {
2988 outer_edge_vertices.push_back(base_triangle_vertex2);
2989 }
2990
2991 if (is_base_triangle_vertex3_outer)
2992 {
2993 outer_edge_vertices.push_back(base_triangle_vertex3);
2994 }
2995
2996 n_outer_edge_vertices = outer_edge_vertices.size();
2997
2998 DE_ASSERT(n_outer_edge_vertices >= 1 && n_outer_edge_vertices <= 2);
2999
3000 bool is_top_outer_edge = true;
3001 bool is_right_outer_edge = true;
3002 bool is_bottom_outer_edge = true;
3003 bool is_left_outer_edge = true;
3004
3005 /* Find which outer edges the vertices don't belong to. If one is in a corner,
3006 * the other will clarify to which edge both vertices belong. */
3007 for (unsigned int n_vertex = 0; n_vertex < n_outer_edge_vertices; ++n_vertex)
3008 {
3009 /* Y < 1, not top outer edge */
3010 if (de::abs(outer_edge_vertices[n_vertex][1] - 1.0f) > epsilon)
3011 {
3012 is_top_outer_edge = false;
3013 }
3014
3015 /* X < 1, not right outer edge */
3016 if (de::abs(outer_edge_vertices[n_vertex][0] - 1.0f) > epsilon)
3017 {
3018 is_right_outer_edge = false;
3019 }
3020
3021 /* Y > 0, not bottom outer edge */
3022 if (de::abs(outer_edge_vertices[n_vertex][1]) > epsilon)
3023 {
3024 is_bottom_outer_edge = false;
3025 }
3026
3027 /* X > 0, not left outer edge */
3028 if (de::abs(outer_edge_vertices[n_vertex][0]) > epsilon)
3029 {
3030 is_left_outer_edge = false;
3031 }
3032 }
3033
3034 if (n_outer_edge_vertices == 1)
3035 {
3036 /* A single vertex with corner-coordinates belongs to two edges. Choose one */
3037 bool x_is_0 = de::abs(outer_edge_vertices[0][0]) < epsilon;
3038 bool x_is_1 = de::abs(outer_edge_vertices[0][0] - 1.0f) < epsilon;
3039 bool y_is_0 = de::abs(outer_edge_vertices[0][1]) < epsilon;
3040 bool y_is_1 = de::abs(outer_edge_vertices[0][1] - 1.0f) < epsilon;
3041
3042 if (x_is_0 && y_is_0)
3043 {
3044 /* bottom edge */
3045 DE_ASSERT(is_left_outer_edge && is_bottom_outer_edge);
3046 is_left_outer_edge = false;
3047 }
3048 else if (x_is_0 && y_is_1)
3049 {
3050 /* left edge */
3051 DE_ASSERT(is_left_outer_edge && is_top_outer_edge);
3052 is_top_outer_edge = false;
3053 }
3054 else if (x_is_1 && y_is_0)
3055 {
3056 /* right edge */
3057 DE_ASSERT(is_right_outer_edge && is_bottom_outer_edge);
3058 is_bottom_outer_edge = false;
3059 }
3060 else if (x_is_1 && y_is_1)
3061 {
3062 /* top edge */
3063 DE_ASSERT(is_right_outer_edge && is_top_outer_edge);
3064 is_right_outer_edge = false;
3065 }
3066 else
3067 {
3068 /* Not a corner vertex, only one of the edge-flags is set */
3069 }
3070 }
3071
3072 /* Sanity checks */
3073 DE_UNREF(is_top_outer_edge);
3074 DE_ASSERT((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 (!is_left_outer_edge && !is_top_outer_edge && !is_bottom_outer_edge &&
3081 is_right_outer_edge));
3082
3083 /* We have all the data needed to determine which tessellation level describes
3084 * subdivision of the edge that the triangle touches */
3085 if (is_left_outer_edge)
3086 {
3087 n_base_tess_level = 0;
3088 }
3089 else if (is_bottom_outer_edge)
3090 {
3091 n_base_tess_level = 1;
3092 }
3093 else if (is_right_outer_edge)
3094 {
3095 n_base_tess_level = 2;
3096 }
3097 else
3098 {
3099 n_base_tess_level = 3;
3100 }
3101 }
3102
3103 /* We shouldn't perform the check if the edge we're processing was described
3104 * by a different outer tessellation level in the reference data set */
3105 if (n_base_tess_level == ref_iteration.n_modified_outer_tess_level)
3106 {
3107 continue;
3108 }
3109
3110 /* This triangle should be present in both vertex data sets */
3111 if (!isTriangleDefinedInVertexDataSet(base_triangle_data, ref_iteration_vertex_data,
3112 ref_iteration.n_vertices))
3113 {
3114 const char* primitive_mode_str = (is_triangles_iteration) ? "triangles" : "quads";
3115
3116 m_testCtx.getLog()
3117 << tcu::TestLog::Message << "For primitive mode [" << primitive_mode_str << "] "
3118 << ", inner tessellation levels:"
3119 << "[" << base_iteration.inner_tess_levels[0] << ", " << base_iteration.inner_tess_levels[1]
3120 << "], outer tessellation levels:"
3121 << "[" << base_iteration.outer_tess_levels[0] << ", " << base_iteration.outer_tess_levels[1]
3122 << ", " << base_iteration.outer_tess_levels[2] << ", "
3123 << base_iteration.outer_tess_levels[3] << "], a triangle connecting inner & outer edges:"
3124 << "[" << base_triangle_vertex1[0] << ", " << base_triangle_vertex1[1] << ", "
3125 << base_triangle_vertex1[2] << "]x"
3126 << "[" << base_triangle_vertex2[0] << ", " << base_triangle_vertex2[1] << ", "
3127 << base_triangle_vertex2[2] << "]x"
3128 << "[" << base_triangle_vertex3[0] << ", " << base_triangle_vertex3[1] << ", "
3129 << base_triangle_vertex3[2] << "] was not found for runs using CW and CCW vertex ordering, "
3130 "which is against the extension specification's rule 7."
3131 << tcu::TestLog::EndMessage;
3132
3133 TCU_FAIL("Implementation is not conformant with Tessellation Rule 7");
3134 }
3135 } /* for (all triangles generated for base test iteration) */
3136 } /* for (all reference iterations) */
3137 } /* for (all base test iterations) */
3138 } /* for (both primitive types) */
3139 }
3140
3141 } /* namespace glcts */
3142