1 /*-------------------------------------------------------------------------
2 * OpenGL Conformance Test Suite
3 * -----------------------------
5 * Copyright (c) 2014-2016 The Khronos Group Inc.
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
22 */ /*-------------------------------------------------------------------*/
24 #include "esextcTessellationShaderVertexSpacing.hpp"
25 #include "esextcTessellationShaderUtils.hpp"
26 #include "gluContextInfo.hpp"
27 #include "gluDefs.hpp"
28 #include "glwEnums.hpp"
29 #include "glwFunctions.hpp"
30 #include "tcuTestLog.hpp"
33 /* Precision, with which the test should be executed. */
34 const float epsilon = 1e-3f;
38 /** Compares two barycentric/cartesian coordinates, using test-wide epsilon.
40 * @param in Coordinate to compare current instance against.
42 * @return true if the coordinates are equal, false otherwise.
44 bool TessellationShaderVertexSpacing::_tess_coordinate::operator==(
45 const TessellationShaderVertexSpacing::_tess_coordinate& in) const
47 if (de::abs(this->u - in.u) < epsilon && de::abs(this->v - in.v) < epsilon && de::abs(this->w - in.w) < epsilon)
57 /** Compares two Cartesian coordinates, using test-wide epsilon.
59 * @param in Coordinate to compare current instance against.
61 * @return true if the coordinates are equal, false otherwise.
63 bool TessellationShaderVertexSpacing::_tess_coordinate_cartesian::operator==(
64 const TessellationShaderVertexSpacing::_tess_coordinate_cartesian& in) const
66 if (de::abs(this->x - in.x) < epsilon && de::abs(this->y - in.y) < epsilon)
78 * @param context Test context
80 TessellationShaderVertexSpacing::TessellationShaderVertexSpacing(Context& context, const ExtParameters& extParams)
81 : TestCaseBase(context, extParams, "vertex_spacing", "Verifies vertex spacing qualifier behaves as specified")
82 , m_gl_max_tess_gen_level_value(0)
86 /* Left blank on purpose */
89 /** Comparator function, used to compare two _tess_coordinate_cartesian
90 * instances by their X components.
92 * @param a First coordinate to use for comparison;
93 * @param b Second coordinate to use for comparison.
95 * @return true if X component of @param a is lower than b's;
98 bool TessellationShaderVertexSpacing::compareEdgeByX(_tess_coordinate_cartesian a, _tess_coordinate_cartesian b)
103 /** Comparator function, used to compare two _tess_coordinate_cartesian
104 * instances by their Y components.
106 * @param a First coordinate to use for comparison;
107 * @param b Second coordinate to use for comparison.
109 * @return true if Y component of @param a is lower than b's;
112 bool TessellationShaderVertexSpacing::compareEdgeByY(_tess_coordinate_cartesian a, _tess_coordinate_cartesian b)
117 /** Deinitializes ES objects created for the test. */
118 void TessellationShaderVertexSpacing::deinit()
120 /* Call base class' deinit() */
121 TestCaseBase::deinit();
123 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
125 /* Unbind vertex array object */
126 gl.bindVertexArray(0);
128 /* Delete vertex array object */
131 gl.deleteVertexArrays(1, &m_vao_id);
136 /* Deinitialize utils instance */
137 if (m_utils != DE_NULL)
145 /** Takes data generated by tessellator for a specific run configuration and
146 * converts it into a set of edges that correspond to subsequent isolines.
147 * This function asserts that the run uses a 'isolines' primitive mode.
149 * @param run Test run properties.
151 * @return A vector storing found edges.
153 TessellationShaderVertexSpacing::_tess_edges TessellationShaderVertexSpacing::getEdgesForIsolinesTessellation(
158 /* First convert the array data to a vector of edges, where each edge
159 * is a vector of points with the same V component. After this is done,
160 * points for each edge need to be sorted by U component.
162 for (unsigned int n_vertex = 0; n_vertex < run.n_vertices; ++n_vertex)
164 /* Isolines are simple - we only need to create a new edge per each unique height */
165 const float* coordinate = (const float*)(&run.data[0]) + 3 /* components */ * n_vertex;
166 _tess_coordinate_cartesian new_item;
168 new_item.x = coordinate[0];
169 new_item.y = coordinate[1];
171 /* Is V recognized? */
172 _tess_edges_iterator edges_iterator;
174 for (edges_iterator = result.begin(); edges_iterator != result.end(); edges_iterator++)
176 _tess_edge& edge = *edges_iterator;
178 /* Each edge uses the same Y component, so we only need to check the first entry */
179 if (de::abs(edge.points[0].y - coordinate[1]) < epsilon)
181 /* Add the new point to the vector */
182 edge.points.push_back(new_item);
186 } /* for (all edges) */
188 if (edges_iterator == result.end())
190 /* New edge starts at this point.
192 * Note that outermost tessellation level does not apply to this
195 _tess_edge new_edge(run.outer[1], run.outer[1], 1.0f);
197 new_edge.points.push_back(new_item);
199 result.push_back(new_edge);
201 } /* for (all vertices) */
203 /* For each edge, sort the points by U coordinate */
204 for (_tess_edges_iterator edges_iterator = result.begin(); edges_iterator != result.end(); ++edges_iterator)
206 _tess_edge_points& edge_points = edges_iterator->points;
208 std::sort(edge_points.begin(), edge_points.end(), compareEdgeByX);
215 /** Takes data generated by tessellator for a specific run configuration and
216 * converts it into a set of edges that define the outer and inner quad.
217 * This function asserts that the run uses a 'quads' primitive mode.
219 * @param run Test run properties.
221 * @return A vector storing found edges.
223 TessellationShaderVertexSpacing::_tess_edges TessellationShaderVertexSpacing::getEdgesForQuadsTessellation(
228 /* First, convert the raw coordinate array into a vector of cartesian coordinates.
229 * For this method, we will need to take out vertices in no specific order. */
230 std::vector<_tess_coordinate_cartesian> coordinates;
232 for (unsigned int n_vertex = 0; n_vertex < run.n_vertices; ++n_vertex)
234 _tess_coordinate_cartesian new_coordinate;
235 const float* vertex_data = (const float*)(&run.data[0]) + 3 /* components */ * n_vertex;
237 new_coordinate.x = vertex_data[0];
238 new_coordinate.y = vertex_data[1];
240 coordinates.push_back(new_coordinate);
243 /* Data set is expected to describe an outer and inner rectangles. We will execute the quad extraction
244 * process in two iterations:
246 * - first iteration will determine all coordinates that are part of the outer quad;
247 * - second iteration will focus on the inner quad.
249 * Each iteration will start from identifying corner vertices:
251 * - top-left corner (x delta from (0.5, 0.5) should be negative, y delta from (0.5, 0.5) should be positive);
252 * - top-right corner (x delta from (0.5, 0.5) should be positive, y delta from (0.5, 0.5) should be positive);
253 * - bottom-left corner (x delta from (0.5, 0.5) should be negative, y delta from (0.5, 0.5) should be negative);
254 * - bottom-right corner (x delta from (0.5, 0.5) should be positive, y delta from (0.5, 0.5) should be negative);
256 * Once we know where the corner vertices are, we will remove them from the data set and iterate again over the
257 * data set to identify all points that are part of edges connecting the edge corners. After the loop is done,
258 * these vertices will have been associated with relevant edges and removed from the data sets.
260 * Once two iterations are complete, we're done.
262 const unsigned int n_iterations = (run.inner[0] > 1) ? 2 : 1;
264 for (unsigned int n_iteration = 0; n_iteration < n_iterations; ++n_iteration)
266 _tess_coordinate_cartesian current_tl_point;
267 float current_tl_point_delta = 0.0f;
268 _tess_coordinate_cartesian current_tr_point;
269 float current_tr_point_delta = 0.0f;
270 _tess_coordinate_cartesian current_bl_point;
271 float current_bl_point_delta = 0.0f;
272 _tess_coordinate_cartesian current_br_point;
273 float current_br_point_delta = 0.0f;
275 /* Iterate over all points */
276 for (std::vector<_tess_coordinate_cartesian>::const_iterator coordinate_iterator = coordinates.begin();
277 coordinate_iterator != coordinates.end(); coordinate_iterator++)
279 const _tess_coordinate_cartesian& coordinate = *coordinate_iterator;
280 float delta_x = coordinate.x - 0.5f;
281 float delta_y = coordinate.y - 0.5f;
282 float delta = deFloatSqrt(delta_x * delta_x + delta_y * delta_y);
284 /* top-left corner (x delta from (0.5, 0.5) should be negative, y delta from (0.5, 0.5) should be positive); */
285 if (delta_x <= 0.0f && delta_y >= 0.0f)
287 if (delta > current_tl_point_delta)
289 current_tl_point = coordinate;
290 current_tl_point_delta = delta;
294 /* top-right corner (x delta from (0.5, 0.5) should be positive, y delta from (0.5, 0.5) should be positive); */
295 if (delta_x >= 0.0f && delta_y >= 0.0f)
297 if (delta > current_tr_point_delta)
299 current_tr_point = coordinate;
300 current_tr_point_delta = delta;
304 /* bottom-left corner (x delta from (0.5, 0.5) should be negative, y delta from (0.5, 0.5) should be negative); */
305 if (delta_x <= 0.0f && delta_y <= 0.0f)
307 if (delta > current_bl_point_delta)
309 current_bl_point = coordinate;
310 current_bl_point_delta = delta;
314 /* bottom-right corner (x delta from (0.5, 0.5) should be positive, y delta from (0.5, 0.5) should be negative); */
315 if (delta_x >= 0.0f && delta_y <= 0.0f)
317 if (delta > current_br_point_delta)
319 current_br_point = coordinate;
320 current_br_point_delta = delta;
323 } /* for (all coordinates) */
325 /* Note: If any of the outer tessellation level is 1, at least
326 * two "current" points will refer to the same point.
328 * Now that we know where the corner vertices are, remove them from the data set
330 const _tess_coordinate_cartesian* corner_coordinate_ptrs[] = { ¤t_tl_point, ¤t_tr_point,
331 ¤t_bl_point, ¤t_br_point };
332 const unsigned int n_corner_coordinate_ptrs =
333 sizeof(corner_coordinate_ptrs) / sizeof(corner_coordinate_ptrs[0]);
335 for (unsigned int n_corner_coordinate = 0; n_corner_coordinate < n_corner_coordinate_ptrs;
336 ++n_corner_coordinate)
338 const _tess_coordinate_cartesian& corner_coordinate = *(corner_coordinate_ptrs[n_corner_coordinate]);
339 std::vector<_tess_coordinate_cartesian>::iterator iterator =
340 std::find(coordinates.begin(), coordinates.end(), corner_coordinate);
342 /* Iterator can be invalid at this point of any of the corner coordinates
343 * referred more than once to the same point. */
344 if (iterator != coordinates.end())
346 coordinates.erase(iterator);
348 } /* for (all corner coordinates) */
350 /* Proceed with identification of coordinates describing the edges.
352 * Note: for inner quad, we need to subtract 2 segments connecting outer and inner coordinates */
354 deFloatSqrt((current_tl_point.x - current_tr_point.x) * (current_tl_point.x - current_tr_point.x) +
355 (current_tl_point.y - current_tr_point.y) * (current_tl_point.y - current_tr_point.y));
357 deFloatSqrt((current_tr_point.x - current_br_point.x) * (current_tr_point.x - current_br_point.x) +
358 (current_tr_point.y - current_br_point.y) * (current_tr_point.y - current_br_point.y));
360 deFloatSqrt((current_br_point.x - current_bl_point.x) * (current_br_point.x - current_bl_point.x) +
361 (current_br_point.y - current_bl_point.y) * (current_br_point.y - current_bl_point.y));
363 deFloatSqrt((current_bl_point.x - current_tl_point.x) * (current_bl_point.x - current_tl_point.x) +
364 (current_bl_point.y - current_tl_point.y) * (current_bl_point.y - current_tl_point.y));
366 _tess_edge tl_tr_edge(0, 0, tl_tr_delta);
367 _tess_edge tr_br_edge(0, 0, tr_br_delta);
368 _tess_edge br_bl_edge(0, 0, br_bl_delta);
369 _tess_edge bl_tl_edge(0, 0, bl_tl_delta);
371 tl_tr_edge.outermost_tess_level = run.outer[3];
372 tr_br_edge.outermost_tess_level = run.outer[2];
373 br_bl_edge.outermost_tess_level = run.outer[1];
374 bl_tl_edge.outermost_tess_level = run.outer[0];
376 if (n_iteration == 0)
378 tl_tr_edge.tess_level = run.outer[3];
379 tr_br_edge.tess_level = run.outer[2];
380 br_bl_edge.tess_level = run.outer[1];
381 bl_tl_edge.tess_level = run.outer[0];
385 tl_tr_edge.tess_level = run.inner[0] - 2 /* segments between inner and outer edges */;
386 br_bl_edge.tess_level = run.inner[0] - 2 /* segments between inner and outer edges */;
387 tr_br_edge.tess_level = run.inner[1] - 2 /* segments between inner and outer edges */;
388 bl_tl_edge.tess_level = run.inner[1] - 2 /* segments between inner and outer edges */;
391 /* Add corner points to edge descriptors. Do *NOT* add the same point twice, as
392 * that will confuse verifyEdges() and cause incorrect failures.
394 tl_tr_edge.points.push_back(current_tl_point);
396 if (!(current_tl_point == current_tr_point))
398 tl_tr_edge.points.push_back(current_tr_point);
401 tr_br_edge.points.push_back(current_tr_point);
403 if (!(current_tr_point == current_br_point))
405 tr_br_edge.points.push_back(current_br_point);
408 br_bl_edge.points.push_back(current_br_point);
410 if (!(current_br_point == current_bl_point))
412 br_bl_edge.points.push_back(current_bl_point);
415 bl_tl_edge.points.push_back(current_bl_point);
417 if (!(current_bl_point == current_tl_point))
419 bl_tl_edge.points.push_back(current_tl_point);
422 /* Identify points that lie on any of the edges considered */
423 _tess_edge* edge_ptrs[] = { &tl_tr_edge, &tr_br_edge, &br_bl_edge, &bl_tl_edge };
424 const unsigned int n_edge_ptrs = sizeof(edge_ptrs) / sizeof(edge_ptrs[0]);
426 for (unsigned int n_edge = 0; n_edge < n_edge_ptrs; ++n_edge)
428 _tess_edge& edge = *(edge_ptrs[n_edge]);
430 /* Degenerate edges will only consist of one point, for which the following
431 * code needs not be executed */
432 if (edge.points.size() > 1)
434 /* Retrieve edge's start & end points */
435 _tess_coordinate_cartesian edge_start_point = edge.points[0];
436 _tess_coordinate_cartesian edge_end_point = edge.points[1];
438 /* Iterate over the data set */
439 for (std::vector<_tess_coordinate_cartesian>::const_iterator iterator = coordinates.begin();
440 iterator != coordinates.end(); iterator++)
442 const _tess_coordinate_cartesian& coordinate = *iterator;
444 if (isPointOnLine(edge_start_point, edge_end_point, coordinate) &&
445 !(edge_start_point == coordinate) && !(edge_end_point == coordinate))
447 /* Make sure the point has not already been added. If this happens,
448 * it is very likely there is a bug in the way the implementation's
449 * support of point mode */
450 if (std::find_if(edge.points.begin(), edge.points.end(),
451 _comparator_exact_tess_coordinate_match(coordinate)) == edge.points.end())
453 edge.points.push_back(coordinate);
457 std::string primitive_mode_string =
458 TessellationShaderUtils::getESTokenForPrimitiveMode(run.primitive_mode);
459 std::string vertex_spacing_string =
460 TessellationShaderUtils::getESTokenForVertexSpacingMode(run.vertex_spacing);
463 << tcu::TestLog::Message << "A duplicate vertex"
464 << " (" << coordinate.x << ", " << coordinate.y
465 << ") was found in set of coordinates generated for the following configuration:"
466 << " inner tessellation levels:(" << run.inner[0] << ", " << run.inner[1]
467 << ") outer tessellation levels:(" << run.outer[0] << ", " << run.outer[1] << ", "
468 << run.outer[2] << ", " << run.outer[3] << ") primitive mode:" << primitive_mode_string
469 << " vertex spacing mode:" << vertex_spacing_string << " point mode:yes"
470 << tcu::TestLog::EndMessage;
472 TCU_FAIL("A duplicate vertex was found in generated tessellation coordinate set "
473 "when point mode was used");
476 } /* for (all coordinates in the data set) */
478 /* Sort all points in the edge relative to the start point */
479 std::sort(edge.points.begin(), edge.points.end(), _comparator_relative_to_base_point(edge_start_point));
481 } /* for (all edges) */
483 /* Remove all coordinates associated to edges from the data set */
484 for (unsigned int n_edge = 0; n_edge < n_edge_ptrs; ++n_edge)
486 _tess_edge& edge = *(edge_ptrs[n_edge]);
488 for (std::vector<_tess_coordinate_cartesian>::const_iterator iterator = edge.points.begin();
489 iterator != edge.points.end(); iterator++)
491 const _tess_coordinate_cartesian& coordinate = *iterator;
492 std::vector<_tess_coordinate_cartesian>::iterator dataset_iterator =
493 std::find(coordinates.begin(), coordinates.end(), coordinate);
495 if (dataset_iterator != coordinates.end())
497 coordinates.erase(dataset_iterator);
499 } /* for (all edge points) */
500 } /* for (all edges) */
502 /* Store the edges */
503 for (unsigned int n_edge = 0; n_edge < n_edge_ptrs; ++n_edge)
505 _tess_edge& edge = *(edge_ptrs[n_edge]);
507 result.push_back(edge);
509 } /* for (both iterations) */
514 /** Takes data generated by tessellator for a specific run configuration and
515 * converts it into a set of edges that correspond to subsequent triangles.
516 * This function asserts that the run uses a 'triangles' primitive mode.
518 * This function throws a TestError, should an error occur or the data is found
521 * @param run Test run properties.
523 * @return A vector storing found edges.
525 TessellationShaderVertexSpacing::_tess_edges TessellationShaderVertexSpacing::getEdgesForTrianglesTessellation(
528 DE_ASSERT(run.data_cartesian != DE_NULL);
530 /* Before we proceed, convert the raw arrayed data into a vector. We'll need to take items out
531 * in an undefined order */
532 std::vector<_tess_coordinate_cartesian> coordinates;
534 for (unsigned int n_vertex = 0; n_vertex < run.n_vertices; ++n_vertex)
536 const float* vertex_data_cartesian = (const float*)run.data_cartesian + n_vertex * 2; /* components */
538 _tess_coordinate_cartesian cartesian;
540 cartesian.x = vertex_data_cartesian[0];
541 cartesian.y = vertex_data_cartesian[1];
543 coordinates.push_back(cartesian);
546 /* The function iterates over the data set generated by the tessellator and:
548 * 1) Finds three corner vertices. These coordinates are considered to correspond to corner vertices
549 * of the outermost triangle. The coordinates are removed from the data set. Note that it is an
550 * error if less than three coordinates are available in the data set at this point.
551 * 2) Iterates over remaining points in the data set and associates them with AB, BC and CA edges.
552 * Each point found to be a part of any of the edges considered is removed from the data set.
553 * 3) If more than 0 coordinates are still available in the data set at this point, implementation
556 * After the implementation runs out of tessellation coordinates, a few sanity checks are executed
557 * and the function returns to the caller.
559 float base_tess_level = 0.0f;
560 unsigned int tess_level_delta = 0;
563 /* Make sure to follow the cited extension spec language:
565 * If the inner tessellation level is one and any of the outer tessellation
566 * levels is greater than one, the inner tessellation level is treated as
567 * though it were originally specified as 1+epsilon and will be rounded up to
568 * result in a two- or three-segment subdivision according to the
569 * tessellation spacing.
572 float inner0_round_clamped_value = 0;
574 TessellationShaderUtils::getTessellationLevelAfterVertexSpacing(
575 run.vertex_spacing, run.inner[0], m_gl_max_tess_gen_level_value, DE_NULL, /* out_clamped */
576 &inner0_round_clamped_value);
578 if (inner0_round_clamped_value == 1.0f && (run.outer[0] > 1.0f || run.outer[1] > 1.0f || run.outer[2] > 1.0f))
580 TessellationShaderUtils::getTessellationLevelAfterVertexSpacing(
581 run.vertex_spacing, inner0_round_clamped_value + 1.0f /* epsilon */, m_gl_max_tess_gen_level_value,
582 DE_NULL, /* out_clamped */
587 TessellationShaderUtils::getTessellationLevelAfterVertexSpacing(
588 run.vertex_spacing, run.inner[0], m_gl_max_tess_gen_level_value, DE_NULL, /* out_clamped */
592 while (coordinates.size() > 0)
594 /* If we're using an odd tessellation level, it is an error if less than three coordinates are
595 * available at this point.
596 * If it's an even tessellation level, we must have at least three coordinates at hand OR
597 * one, in which case the only coordinate left is the degenerate one. Should that happen,
598 * it's time to leave. */
599 if ((((int)base_tess_level) % 2 == 0) && (coordinates.size() == 1))
601 /* We're left with the degenerate vertex. Leave the loop */
605 if (coordinates.size() < 3)
607 TCU_FAIL("Could not extract three corner vertices that would make up a triangle");
610 /* Iterate over all vertices left and identify three corner vertices. For the outermost triangle,
611 * these will be represented by (1, 0, 0), (0, 1, 0) and (0, 0, 1) barycentric coordinates, which
612 * correspond to the following coordinates in Euclidean space: (0.5, 0), (1, 1), (0, 1) (as defined
613 * in TessellationShaderUtils::convertCartesianCoordinatesToBarycentric() ).
615 * The idea here is to identify vertices that are the closest to the ideal coordinates, not necessarily
616 * to find a perfect match. */
617 unsigned int curr_index = 0;
618 float delta_v1 = 0.0f; /* barycentric:(1, 0, 0) -> Euclidean:(0.5, 0.0) */
619 float delta_v2 = 0.0f; /* barycentric:(0, 1, 0) -> Euclidean:(1.0, 1.0) */
620 float delta_v3 = 0.0f; /* barycentric:(0, 0, 1) -> Euclidean:(0.0, 1.0) */
621 bool is_first_iteration = true;
622 unsigned int selected_v1_index = 0;
623 unsigned int selected_v2_index = 0;
624 unsigned int selected_v3_index = 0;
626 for (std::vector<_tess_coordinate_cartesian>::const_iterator iterator = coordinates.begin();
627 iterator != coordinates.end(); iterator++, curr_index++)
629 const _tess_coordinate_cartesian& cartesian_coordinate = *iterator;
631 float curr_delta_v1 = deFloatSqrt((cartesian_coordinate.x - 0.5f) * (cartesian_coordinate.x - 0.5f) +
632 (cartesian_coordinate.y - 0.0f) * (cartesian_coordinate.y - 0.0f));
633 float curr_delta_v2 = deFloatSqrt((cartesian_coordinate.x - 1.0f) * (cartesian_coordinate.x - 1.0f) +
634 (cartesian_coordinate.y - 1.0f) * (cartesian_coordinate.y - 1.0f));
635 float curr_delta_v3 = deFloatSqrt((cartesian_coordinate.x - 0.0f) * (cartesian_coordinate.x - 0.0f) +
636 (cartesian_coordinate.y - 1.0f) * (cartesian_coordinate.y - 1.0f));
638 if (is_first_iteration)
640 delta_v1 = curr_delta_v1;
641 delta_v2 = curr_delta_v2;
642 delta_v3 = curr_delta_v3;
644 /* No need to update selected vertex indices, since this is the very first iteration */
645 is_first_iteration = false;
649 if (curr_delta_v1 < delta_v1)
651 delta_v1 = curr_delta_v1;
652 selected_v1_index = curr_index;
655 if (curr_delta_v2 < delta_v2)
657 delta_v2 = curr_delta_v2;
658 selected_v2_index = curr_index;
661 if (curr_delta_v3 < delta_v3)
663 delta_v3 = curr_delta_v3;
664 selected_v3_index = curr_index;
667 } /* for (all remaining coordinates) */
669 /* Extract the vertices out of the data set */
670 _tess_coordinate_cartesian corner_vertices[] = { *(coordinates.begin() + selected_v1_index),
671 *(coordinates.begin() + selected_v2_index),
672 *(coordinates.begin() + selected_v3_index) };
673 const unsigned int n_corner_vertices = sizeof(corner_vertices) / sizeof(corner_vertices[0]);
675 /* Remove the vertices from the data set */
676 for (unsigned int n_corner_vertex = 0; n_corner_vertex < n_corner_vertices; ++n_corner_vertex)
678 const _tess_coordinate_cartesian& vertex = corner_vertices[n_corner_vertex];
679 std::vector<_tess_coordinate_cartesian>::iterator iterator =
680 std::find(coordinates.begin(), coordinates.end(), vertex);
682 DE_ASSERT(iterator != coordinates.end());
683 if (iterator != coordinates.end())
685 coordinates.erase(iterator);
687 } /* for (all corner vertices) */
689 /* Now that we know where the corner vertices are, identify all points that lie
690 * on edges defined by these vertices */
691 std::vector<_tess_coordinate_cartesian> edge_v1_v2_vertices;
692 std::vector<_tess_coordinate_cartesian> edge_v2_v3_vertices;
693 std::vector<_tess_coordinate_cartesian> edge_v3_v1_vertices;
694 const _tess_coordinate_cartesian& v1 = corner_vertices[0];
695 const _tess_coordinate_cartesian& v2 = corner_vertices[1];
696 const _tess_coordinate_cartesian& v3 = corner_vertices[2];
698 for (std::vector<_tess_coordinate_cartesian>::const_iterator iterator = coordinates.begin();
699 iterator != coordinates.end(); iterator++, curr_index++)
701 const _tess_coordinate_cartesian& cartesian_coordinate = *iterator;
703 if (isPointOnLine(v1, v2, cartesian_coordinate))
705 edge_v1_v2_vertices.push_back(*iterator);
708 if (isPointOnLine(v2, v3, cartesian_coordinate))
710 edge_v2_v3_vertices.push_back(*iterator);
713 if (isPointOnLine(v3, v1, cartesian_coordinate))
715 edge_v3_v1_vertices.push_back(*iterator);
717 } /* for (all coordinates in data set) */
719 /* Now that edge vertices have been identified, remove them from the data set */
720 const std::vector<_tess_coordinate_cartesian>* edge_ptrs[] = { &edge_v1_v2_vertices, &edge_v2_v3_vertices,
721 &edge_v3_v1_vertices };
722 const unsigned int n_edge_ptrs = sizeof(edge_ptrs) / sizeof(edge_ptrs[0]);
724 for (unsigned int n_edge_ptr = 0; n_edge_ptr < n_edge_ptrs; ++n_edge_ptr)
726 const std::vector<_tess_coordinate_cartesian>& edge = *edge_ptrs[n_edge_ptr];
727 const unsigned int n_edge_vertices = (unsigned int)edge.size();
729 for (unsigned int n_edge_vertex = 0; n_edge_vertex < n_edge_vertices; ++n_edge_vertex)
731 const _tess_coordinate_cartesian& coordinate = edge[n_edge_vertex];
732 std::vector<_tess_coordinate_cartesian>::iterator iterator =
733 std::find(coordinates.begin(), coordinates.end(), coordinate);
735 if (iterator != coordinates.end())
737 coordinates.erase(iterator);
739 } /* for (all edge vertices) */
740 } /* for (all edges) */
742 /* Add corner coordinates to our vectors, but only if they are not
745 if (std::find(edge_v1_v2_vertices.begin(), edge_v1_v2_vertices.end(), v1) == edge_v1_v2_vertices.end())
747 edge_v1_v2_vertices.push_back(v1);
750 if (std::find(edge_v1_v2_vertices.begin(), edge_v1_v2_vertices.end(), v2) == edge_v1_v2_vertices.end())
752 edge_v1_v2_vertices.push_back(v2);
755 if (std::find(edge_v2_v3_vertices.begin(), edge_v2_v3_vertices.end(), v2) == edge_v2_v3_vertices.end())
757 edge_v2_v3_vertices.push_back(v2);
760 if (std::find(edge_v2_v3_vertices.begin(), edge_v2_v3_vertices.end(), v3) == edge_v2_v3_vertices.end())
762 edge_v2_v3_vertices.push_back(v3);
765 if (std::find(edge_v3_v1_vertices.begin(), edge_v3_v1_vertices.end(), v3) == edge_v3_v1_vertices.end())
767 edge_v3_v1_vertices.push_back(v3);
770 if (std::find(edge_v3_v1_vertices.begin(), edge_v3_v1_vertices.end(), v1) == edge_v3_v1_vertices.end())
772 edge_v3_v1_vertices.push_back(v1);
775 /* Sort all points relative to corner point */
776 std::sort(edge_v1_v2_vertices.begin(), edge_v1_v2_vertices.end(), _comparator_relative_to_base_point(v1));
778 std::sort(edge_v2_v3_vertices.begin(), edge_v2_v3_vertices.end(), _comparator_relative_to_base_point(v2));
780 std::sort(edge_v3_v1_vertices.begin(), edge_v3_v1_vertices.end(), _comparator_relative_to_base_point(v3));
782 /* We now have all the data to update the result vector with new edge data */
783 for (unsigned int n_edge_ptr = 0; n_edge_ptr < n_edge_ptrs; ++n_edge_ptr)
785 /* Compute tessellation level values for the edge */
786 glw::GLfloat curr_tess_level = 0.0f;
787 glw::GLfloat outermost_tess_level = 0.0f;
789 if (tess_level_delta == 0)
801 curr_tess_level = run.outer[2];
802 outermost_tess_level = run.outer[2];
809 curr_tess_level = run.outer[0];
810 outermost_tess_level = run.outer[0];
817 curr_tess_level = run.outer[1];
818 outermost_tess_level = run.outer[1];
825 DE_FATAL("Invalid edge index");
827 } /* switch (n_edge_ptr) */
831 curr_tess_level = base_tess_level - (float)tess_level_delta;
832 outermost_tess_level = base_tess_level;
835 /* Convert internal representation to _tess_edge */
836 const std::vector<_tess_coordinate_cartesian>& edge = *edge_ptrs[n_edge_ptr];
837 const _tess_coordinate_cartesian& edge_start_point = *edge.begin();
838 const _tess_coordinate_cartesian& edge_end_point = *(edge.begin() + (edge.size() - 1));
840 deFloatSqrt((edge_end_point.x - edge_start_point.x) * (edge_end_point.x - edge_start_point.x) +
841 (edge_end_point.y - edge_start_point.y) * (edge_end_point.y - edge_start_point.y));
842 _tess_edge result_edge(curr_tess_level, outermost_tess_level, edge_length);
844 for (std::vector<_tess_coordinate_cartesian>::const_iterator edge_point_iterator = edge.begin();
845 edge_point_iterator != edge.end(); edge_point_iterator++)
847 const _tess_coordinate_cartesian& edge_point = *edge_point_iterator;
849 result_edge.points.push_back(edge_point);
852 /* Good to store the edge now */
853 result.push_back(result_edge);
854 } /* for (all edges) */
856 /* Moving on with next inner triangle. As per spec, reduce tessellation level by 2 */
857 tess_level_delta += 2;
858 } /* while (run.n_vertices > 0) */
863 /** Tells whether given two-dimensional point is located on a two-dimensional line defined
866 * @param line_v1 First vertex defining the line;
867 * @param line_v2 Second vertex defining the line;
868 * @param point Point to check.
870 * @return true if the point was determned to be a part of the line,
873 bool TessellationShaderVertexSpacing::isPointOnLine(const _tess_coordinate_cartesian& line_v1,
874 const _tess_coordinate_cartesian& line_v2,
875 const _tess_coordinate_cartesian& point)
880 /* Calculate distance from a point to a line passing through two points */
881 float Dx = line_v1.x - line_v2.x;
882 float Dy = line_v1.y - line_v2.y;
883 float denominator = deFloatSqrt(Dx * Dx + Dy * Dy);
884 float d = de::abs(Dy * point.x - Dx * point.y + line_v1.x * line_v2.y - line_v2.x * line_v1.y) / denominator;
886 if (de::abs(d) < epsilon)
894 /** Initializes ES objects necessary to run the test. */
895 void TessellationShaderVertexSpacing::initTest()
897 /* Skip if required extensions are not supported. */
898 if (!m_is_tessellation_shader_supported)
900 throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
903 /* Initialize Utils instance */
904 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
906 m_utils = new TessellationShaderUtils(gl, this);
908 /* Initialize vertex array object */
909 gl.genVertexArrays(1, &m_vao_id);
910 GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object");
912 gl.bindVertexArray(m_vao_id);
913 GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!");
915 /* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value */
916 gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &m_gl_max_tess_gen_level_value);
917 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() call failed for GL_MAX_TESS_GEN_LEVEL_EXT pname");
919 const _tessellation_shader_vertex_spacing vs_modes[] = { TESSELLATION_SHADER_VERTEX_SPACING_EQUAL,
920 TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_EVEN,
921 TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD,
922 TESSELLATION_SHADER_VERTEX_SPACING_DEFAULT };
923 const unsigned int n_vs_modes = sizeof(vs_modes) / sizeof(vs_modes[0]);
925 const _tessellation_primitive_mode primitive_modes[] = { TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES,
926 TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES,
927 TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS };
928 const unsigned int n_primitive_modes = sizeof(primitive_modes) / sizeof(primitive_modes[0]);
930 /* Iterate through all primitive modes */
931 for (unsigned int n_primitive_mode = 0; n_primitive_mode < n_primitive_modes; ++n_primitive_mode)
933 _tessellation_primitive_mode primitive_mode = primitive_modes[n_primitive_mode];
935 /* Generate tessellation level set for current primitive mode */
936 _tessellation_levels_set tess_levels_set;
938 tess_levels_set = TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode(
939 primitive_mode, m_gl_max_tess_gen_level_value,
940 TESSELLATION_LEVEL_SET_FILTER_INNER_AND_OUTER_LEVELS_USE_DIFFERENT_VALUES);
942 /* Iterate through all vertex spacing modes */
943 for (unsigned int n_vs_mode = 0; n_vs_mode < n_vs_modes; ++n_vs_mode)
945 _tessellation_shader_vertex_spacing vs_mode = vs_modes[n_vs_mode];
947 /* Iterate through all tessellation level combinations */
948 for (_tessellation_levels_set_const_iterator tess_levels_set_iterator = tess_levels_set.begin();
949 tess_levels_set_iterator != tess_levels_set.end(); tess_levels_set_iterator++)
951 const _tessellation_levels& tess_levels = *tess_levels_set_iterator;
954 /* Skip border cases that this test cannot handle */
955 if (primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS &&
956 vs_mode == TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD &&
957 (tess_levels.inner[0] <= 1 || tess_levels.inner[1] <= 1))
962 /* Fill run descriptor */
963 memcpy(run.inner, tess_levels.inner, sizeof(run.inner));
964 memcpy(run.outer, tess_levels.outer, sizeof(run.outer));
966 run.primitive_mode = primitive_mode;
967 run.vertex_spacing = vs_mode;
969 /* Retrieve vertex data for both passes */
970 run.n_vertices = m_utils->getAmountOfVerticesGeneratedByTessellator(
971 run.primitive_mode, run.inner, run.outer, run.vertex_spacing, true); /* is_point_mode_enabled */
973 if (run.n_vertices == 0)
975 std::string primitive_mode_string =
976 TessellationShaderUtils::getESTokenForPrimitiveMode(primitive_mode);
977 std::string vs_mode_string = TessellationShaderUtils::getESTokenForVertexSpacingMode(vs_mode);
979 m_testCtx.getLog() << tcu::TestLog::Message << "No vertices were generated by tessellator for: "
982 << run.inner[0] << ", " << run.inner[1] << "]"
983 ", outer tess levels:"
985 << run.outer[0] << ", " << run.outer[1] << ", " << run.outer[2] << ", "
986 << run.outer[3] << "]"
988 << primitive_mode_string << ", vertex spacing: " << vs_mode_string
989 << tcu::TestLog::EndMessage;
991 TCU_FAIL("Zero vertices were generated by tessellator");
994 /* Retrieve the data buffers */
995 run.data = m_utils->getDataGeneratedByTessellator(
996 run.inner, true, /* is_point_mode_enabled */
997 run.primitive_mode, TESSELLATION_SHADER_VERTEX_ORDERING_CCW, run.vertex_spacing, run.outer);
999 /* 'triangles' tessellation data is expressed in barycentric coordinates. Before we can
1000 * continue, we need to convert the data to Euclidean space */
1001 if (run.primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES)
1003 run.data_cartesian = new float[run.n_vertices * 2 /* components */];
1005 for (unsigned int n_vertex = 0; n_vertex < run.n_vertices; ++n_vertex)
1007 const float* barycentric_vertex_data =
1008 (const float*)(&run.data[0]) + n_vertex * 3; /* components */
1009 float* cartesian_vertex_data = (float*)run.data_cartesian + n_vertex * 2; /* components */
1011 TessellationShaderUtils::convertBarycentricCoordinatesToCartesian(barycentric_vertex_data,
1012 cartesian_vertex_data);
1014 } /* if (run.primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES) */
1017 run.data_cartesian = DE_NULL;
1020 /* Store the run data */
1021 m_runs.push_back(run);
1022 } /* for (all tessellation level values ) */
1023 } /* for (all primitive modes) */
1024 } /* for (all vertex spacing modes) */
1027 /** Executes the test.
1029 * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
1031 * Note the function throws exception should an error occur!
1033 * @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again.
1035 tcu::TestNode::IterateResult TessellationShaderVertexSpacing::iterate(void)
1037 /* Do not execute if required extensions are not supported. */
1038 if (!m_is_tessellation_shader_supported)
1040 throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
1043 /* Initialize the test */
1046 /* Iterate through all runs */
1047 for (_runs_const_iterator run_iterator = m_runs.begin(); run_iterator != m_runs.end(); run_iterator++)
1050 const _run& run = *run_iterator;
1052 switch (run.primitive_mode)
1054 case TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES:
1056 edges = getEdgesForIsolinesTessellation(run);
1061 case TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS:
1063 edges = getEdgesForQuadsTessellation(run);
1068 case TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES:
1070 edges = getEdgesForTrianglesTessellation(run);
1077 TCU_FAIL("Unrecognized primitive mode");
1079 } /* switch (run.primitive_mode) */
1081 verifyEdges(edges, run);
1082 } /* for (all runs) */
1085 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1089 /* Verifies that user-provided edges follow the vertex spacing convention, as
1090 * defined in the extension specification.
1092 * This function throws a TestError, should an error occur or the data is found
1095 * @param edges Data of all edges to run the check against.
1096 * @param run Test run properties.
1098 void TessellationShaderVertexSpacing::verifyEdges(const _tess_edges& edges, const _run& run)
1100 /* Cache strings that may be used by logging the routines */
1101 const std::string primitive_mode_string = TessellationShaderUtils::getESTokenForPrimitiveMode(run.primitive_mode);
1102 const std::string vertex_spacing_string =
1103 TessellationShaderUtils::getESTokenForVertexSpacingMode(run.vertex_spacing);
1105 /* Iterate through all edges */
1106 unsigned int n_edge = 0;
1108 for (_tess_edges_const_iterator edges_iterator = edges.begin(); edges_iterator != edges.end();
1109 edges_iterator++, n_edge++)
1111 const _tess_edge& edge = *edges_iterator;
1112 float edge_clamped_tess_level = 0.0f;
1113 float edge_clamped_rounded_tess_level = 0.0f;
1114 float outermost_edge_tess_level_clamped_rounded = 0.0f;
1115 _tess_coordinate_deltas segment_deltas;
1117 TessellationShaderUtils::getTessellationLevelAfterVertexSpacing(
1118 run.vertex_spacing, edge.outermost_tess_level, m_gl_max_tess_gen_level_value, DE_NULL, /* out_clamped */
1119 &outermost_edge_tess_level_clamped_rounded);
1121 /* Retrieve amount of segments the edge should consist of */
1122 TessellationShaderUtils::getTessellationLevelAfterVertexSpacing(
1123 run.vertex_spacing, edge.tess_level, m_gl_max_tess_gen_level_value, &edge_clamped_tess_level,
1124 &edge_clamped_rounded_tess_level);
1126 /* Take two subsequent points if they are available. Vertex spacing has no meaning
1127 * in a world of degenerate edges, so skip the check if we have just encountered one.
1129 const unsigned int n_points = (unsigned int)edge.points.size();
1136 /* Compute segment deltas */
1137 for (unsigned int n_base_point = 0; n_base_point < n_points - 1; n_base_point++)
1139 const _tess_coordinate_cartesian& point_a = edge.points[n_base_point + 0];
1140 const _tess_coordinate_cartesian& point_b = edge.points[n_base_point + 1];
1142 /* Calculate the distance between the points */
1143 float distance_nonsqrt = 0.0f;
1144 float distance = 0.0f;
1147 (point_a.x - point_b.x) * (point_a.x - point_b.x) + (point_a.y - point_b.y) * (point_a.y - point_b.y);
1149 distance = deFloatSqrt(distance_nonsqrt);
1151 /* Check if the distance is not already recognized. */
1152 _tess_coordinate_deltas_iterator deltas_iterator;
1154 for (deltas_iterator = segment_deltas.begin(); deltas_iterator != segment_deltas.end(); deltas_iterator++)
1156 if (de::abs(deltas_iterator->delta - distance) < epsilon)
1158 /* Increment the counter and leave */
1159 deltas_iterator->counter++;
1165 if (deltas_iterator == segment_deltas.end())
1167 /* This is the first time we're encountering a segment of this specific length. */
1168 _tess_coordinate_delta new_item;
1170 new_item.counter = 1;
1171 new_item.delta = distance;
1173 segment_deltas.push_back(new_item);
1175 } /* for (all base points) */
1177 DE_ASSERT(segment_deltas.size() != 0);
1179 switch (run.vertex_spacing)
1181 case TESSELLATION_SHADER_VERTEX_SPACING_DEFAULT:
1182 case TESSELLATION_SHADER_VERTEX_SPACING_EQUAL:
1184 /* For equal vertex spacings, we should end up with a single _tess_coordinate_delta instance
1185 * of a predefined length, describing exactly edge_clamped_rounded_tess_level invocations */
1186 float expected_delta = edge.edge_length / edge_clamped_rounded_tess_level;
1188 if (segment_deltas.size() != 1)
1190 m_testCtx.getLog() << tcu::TestLog::Message
1191 << "More than one segment delta was generated for the following tessellation"
1194 << primitive_mode_string << "vertex spacing mode:" << vertex_spacing_string
1195 << "inner tessellation levels: (" << run.inner[0] << ", " << run.inner[1]
1197 ", outer tessellation levels: ("
1198 << run.outer[0] << ", " << run.outer[1] << ", " << run.outer[2] << ", "
1199 << run.outer[3] << ")" << tcu::TestLog::EndMessage;
1201 TCU_FAIL("Equal vertex spacing mode tessellation generated segment edges of varying lengths, "
1202 "whereas only one was expected.");
1205 if (de::abs(segment_deltas[0].delta - expected_delta) > epsilon)
1207 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid segment delta (expected:" << expected_delta
1208 << ", found: " << segment_deltas[0].delta
1209 << ") was generated for the following tessellation configuration: "
1211 << primitive_mode_string << "vertex spacing mode:" << vertex_spacing_string
1212 << "inner tessellation levels: (" << run.inner[0] << ", " << run.inner[1]
1214 ", outer tessellation levels: ("
1215 << run.outer[0] << ", " << run.outer[1] << ", " << run.outer[2] << ", "
1216 << run.outer[3] << ")" << tcu::TestLog::EndMessage;
1218 TCU_FAIL("Invalid delta between segments generated by the tessellator configured to run "
1219 "in equal vertex spacing mode");
1222 if (segment_deltas[0].counter != (unsigned int)edge_clamped_rounded_tess_level)
1224 m_testCtx.getLog() << tcu::TestLog::Message
1225 << "Invalid amount of segments (expected:" << (int)edge_clamped_rounded_tess_level
1226 << ", found: " << segment_deltas[0].counter
1228 "was generated for the following tessellation configuration: "
1230 << primitive_mode_string << "vertex spacing mode:" << vertex_spacing_string
1231 << "inner tessellation levels: (" << run.inner[0] << ", " << run.inner[1]
1233 ", outer tessellation levels: ("
1234 << run.outer[0] << ", " << run.outer[1] << ", " << run.outer[2] << ", "
1235 << run.outer[3] << ")" << tcu::TestLog::EndMessage;
1237 TCU_FAIL("Invalid amount of segments generated for equal vertex spacing mode");
1241 } /* default/equal vertex spacing */
1243 case TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_EVEN:
1244 case TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD:
1246 /* For fractional vertex spacings, situation is more tricky. The extension specification
1247 * is very liberal when it comes to defining segment lengths. Hence the only thing we
1248 * should be testing here is that:
1250 * a) No more than 2 deltas are generated for a single edge.
1252 * b) If a single delta is generated, it should:
1254 * 1. define exactly edge_clamped_rounded_tess_level-2 segments if
1255 * |edge_clamped_rounded_tess_level - edge_clamped_tess_level| == 2.0f,
1257 * 2. define exactly edge_clamped_rounded_tess_level segments otherwise.
1259 * c) If two deltas are generated, one of them should define 2 segments, and the other
1260 * one should define edge_clamped_rounded_tess_level-2 segments.
1263 if (segment_deltas.size() > 2)
1265 m_testCtx.getLog() << tcu::TestLog::Message << "More than two segment deltas (" << segment_deltas.size()
1266 << ") were generated for the following tessellation configuration: "
1268 << primitive_mode_string << "vertex spacing mode:" << vertex_spacing_string
1269 << "inner tessellation levels: (" << run.inner[0] << ", " << run.inner[1]
1271 ", outer tessellation levels: ("
1272 << run.outer[0] << ", " << run.outer[1] << ", " << run.outer[2] << ", "
1273 << run.outer[3] << ")" << tcu::TestLog::EndMessage;
1275 TCU_FAIL("Fractional spacing mode tessellated edges to segments of more than two "
1276 "differentiable lengths");
1279 if (segment_deltas.size() == 1)
1281 int expected_counter = 0;
1283 if (run.primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES)
1285 /* With each triangle level, 2 segments go out. Each triangle consists of 3 edges */
1286 expected_counter = (int)outermost_edge_tess_level_clamped_rounded - 2 * (n_edge / 3);
1290 expected_counter = (int)edge_clamped_rounded_tess_level;
1291 if (run.primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS &&
1292 run.vertex_spacing == TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD)
1294 /* 8 edges expected in total; we should expect 2 segments less for the inner quad */
1295 expected_counter = (int)edge_clamped_rounded_tess_level - 2 * (n_edge / 4);
1298 /* For degenerate cases, always assume exactly one segment should be generated */
1299 if (edge.tess_level <= 0.0f)
1301 expected_counter = 1;
1305 if (segment_deltas[0].counter != (unsigned int)expected_counter)
1307 m_testCtx.getLog() << tcu::TestLog::Message
1308 << "Invalid amount of segments (expected:" << expected_counter
1309 << ", found: " << segment_deltas[0].counter
1311 "was generated for the following tessellation configuration: "
1313 << primitive_mode_string << "vertex spacing mode:" << vertex_spacing_string
1314 << "inner tessellation levels: (" << run.inner[0] << ", " << run.inner[1]
1316 ", outer tessellation levels: ("
1317 << run.outer[0] << ", " << run.outer[1] << ", " << run.outer[2] << ", "
1318 << run.outer[3] << ")" << tcu::TestLog::EndMessage;
1320 TCU_FAIL("Invalid amount of segments generated for fractional vertex spacing mode");
1325 DE_ASSERT(segment_deltas.size() == 2);
1327 if (!((segment_deltas[0].counter == 2 &&
1328 segment_deltas[1].counter == ((unsigned int)edge_clamped_rounded_tess_level - 2)) ||
1329 (segment_deltas[1].counter == 2 &&
1330 segment_deltas[0].counter == ((unsigned int)edge_clamped_rounded_tess_level - 2))))
1332 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid number of segments with different deltas ("
1333 << segment_deltas[0].delta << " and " << segment_deltas[1].delta
1334 << ") was generated. "
1336 << primitive_mode_string << "vertex spacing mode:" << vertex_spacing_string
1337 << "inner tessellation levels: (" << run.inner[0] << ", " << run.inner[1]
1339 ", outer tessellation levels: ("
1340 << run.outer[0] << ", " << run.outer[1] << ", " << run.outer[2] << ", "
1341 << run.outer[3] << ")" << tcu::TestLog::EndMessage;
1343 TCU_FAIL("Equal amount of segments was generated for segments of different deltas");
1346 if (segment_deltas[0].counter != 2 && segment_deltas[1].counter != 2)
1348 m_testCtx.getLog() << tcu::TestLog::Message
1349 << "Neither of the segments generated by the tessellator was defined "
1352 << primitive_mode_string << "vertex spacing mode:" << vertex_spacing_string
1353 << "inner tessellation levels: (" << run.inner[0] << ", " << run.inner[1]
1355 ", outer tessellation levels: ("
1356 << run.outer[0] << ", " << run.outer[1] << ", " << run.outer[2] << ", "
1357 << run.outer[3] << ")" << tcu::TestLog::EndMessage;
1359 TCU_FAIL("Neither of the generated segments was repeated exactly twice "
1360 "for fractional vertex spacing mode");
1365 } /* fractional even/odd vertex spacing types */
1369 TCU_FAIL("Unrecognized vertex spacing mode");
1371 } /* switch (run.vertex_spacing) */
1372 } /* for (all edges) */
1376 /* namespace glcts */