1 #ifndef _ESEXTCTESSELLATIONSHADERVERTEXSPACING_HPP
2 #define _ESEXTCTESSELLATIONSHADERVERTEXSPACING_HPP
3 /*-------------------------------------------------------------------------
4  * OpenGL Conformance Test Suite
5  * -----------------------------
6  *
7  * Copyright (c) 2014-2016 The Khronos Group Inc.
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  */ /*!
22  * \file
23  * \brief
24  */ /*-------------------------------------------------------------------*/
25 
26 #include "../esextcTestCaseBase.hpp"
27 #include "esextcTessellationShaderUtils.hpp"
28 #include "gluShaderUtil.hpp"
29 #include "tcuDefs.hpp"
30 #include <deMath.h>
31 
32 namespace glcts
33 {
34 /** Implementation of Test Case 25
35  *
36  *  Make sure that vertex spacing mode defined in a tessellation evaluation
37  *  shader affects the tessellation primitive generator as per specification,
38  *  to the limit enforced by implementation-dependent behaviour.
39  *  Consider all three tessellation primitive generator modes (triangles,
40  *  quads, isolines). TE stage should be run in point mode.
41  *  Make sure that by default the tessellation primitive generator works in
42  *  equal_spacing spacing mode.
43  *  Make sure that negative inner levels are clamped as defined for active
44  *  vertex spacing mode.
45  *
46  *  Technical details:
47  *
48  *  0. Consider the following set: {-1 (where valid), 1, MAX_TESS_GEN_LEVEL_EXT / 2,
49  *     MAX_TESS_GEN_LEVEL_EXT}. All combinations of values from this set
50  *     in regard to relevant inner/outer tessellation levels for all
51  *     primitive generator modes should be checked by this test.
52  *
53  *  1. This test should capture vertices output by TE stage and verify their
54  *     locations. If an edge is defined by function y = a * t + b (a, b
55  *     computed from locations of edge start & end points), t should be
56  *     calculated for each vertex that is a part of the edge considered.
57  *  2. Test passes if t values are in agreement with the specification
58  *     (assume epsilon 1e-5) and vertex spacing mode considered.
59  *
60  *  This test implementation skips configurations meeting all of the following
61  *  properties:
62  *
63  *  - primitive mode:      QUADS
64  *  - vertex spacing mode: FRACTIONAL ODD
65  *  - inner tess level[0]: <= 1
66  *  - inner tess level[1]: <= 1
67  *
68  *  These configurations are affected by a nuance described in greater
69  *  detail in Khronos Bugzilla#11979, which this test cannot handle.
70  **/
71 class TessellationShaderVertexSpacing : public TestCaseBase
72 {
73 public:
74     /* Public methods */
75     TessellationShaderVertexSpacing(Context &context, const ExtParameters &extParams);
76 
~TessellationShaderVertexSpacing(void)77     virtual ~TessellationShaderVertexSpacing(void)
78     {
79     }
80 
81     virtual void deinit(void);
82     void initTest(void);
83     virtual IterateResult iterate(void);
84 
85 private:
86     /* Private type definitions */
87     /** Stores properties of a single test run */
88     typedef struct _run
89     {
90         float inner[2];
91         float outer[4];
92         _tessellation_primitive_mode primitive_mode;
93         _tessellation_shader_vertex_spacing vertex_spacing;
94 
95         std::vector<char> data;
96         float *data_cartesian; /* only used for 'triangles' case */
97         unsigned int n_vertices;
98 
99         /* Constructor. Resets all fields to default values */
_runglcts::TessellationShaderVertexSpacing::_run100         _run()
101         {
102             memset(inner, 0, sizeof(inner));
103             memset(outer, 0, sizeof(outer));
104             data_cartesian = 0;
105             n_vertices     = 0;
106             primitive_mode = TESSELLATION_SHADER_PRIMITIVE_MODE_UNKNOWN;
107             vertex_spacing = TESSELLATION_SHADER_VERTEX_SPACING_UNKNOWN;
108         }
109     } _run;
110 
111     /** Stores either barycentric or Cartesian coordinate data
112      *  (depending on primitive mode of a test run this structure
113      *  will be instantiated for)
114      */
115     typedef struct _tess_coordinate
116     {
117         float u;
118         float v;
119         float w;
120 
121         /* Constructor. Resets all fields to 0 */
_tess_coordinateglcts::TessellationShaderVertexSpacing::_tess_coordinate122         _tess_coordinate()
123         {
124             u = 0.0f;
125             v = 0.0f;
126             w = 0.0f;
127         }
128 
129         /* Constructor.
130          *
131          * @param u Value to set for U component;
132          * @param v Value to set for V component;
133          * @param w Value to set for W component;
134          */
_tess_coordinateglcts::TessellationShaderVertexSpacing::_tess_coordinate135         _tess_coordinate(float _u, float _v, float _w)
136         {
137             this->u = _u;
138             this->v = _v;
139             this->w = _w;
140         }
141 
142         /** Compares two barycentric/Cartesian coordinates, using test-wide epsilon.
143          *
144          *  @param in Coordinate to compare current instance against.
145          *
146          *  @return true if the coordinates are equal, false otherwise.
147          **/
148         bool operator==(const _tess_coordinate &in) const;
149     } _tess_coordinate;
150 
151     /** Stores Cartesian coordinate data. */
152     typedef struct _tess_coordinate_cartesian
153     {
154         float x;
155         float y;
156 
157         /* Constructor. Resets all values to 0 */
_tess_coordinate_cartesianglcts::TessellationShaderVertexSpacing::_tess_coordinate_cartesian158         _tess_coordinate_cartesian()
159         {
160             x = 0.0f;
161             y = 0.0f;
162         }
163 
164         /* Constructor.
165          *
166          * @param x Value to use for X component;
167          * @param y Value to use for Y component;
168          */
_tess_coordinate_cartesianglcts::TessellationShaderVertexSpacing::_tess_coordinate_cartesian169         _tess_coordinate_cartesian(float _x, float _y)
170         {
171             this->x = _x;
172             this->y = _y;
173         }
174 
175         /** Compares two Cartesian coordinates, using test-wide epsilon.
176          *
177          *  @param in Coordinate to compare current instance against.
178          *
179          *  @return true if the coordinates are equal, false otherwise.
180          **/
181         bool operator==(const _tess_coordinate_cartesian &in) const;
182     } _tess_coordinate_cartesian;
183 
184     /** Stores information on:
185      *
186      *  - a delta between two coordinates;
187      *  - amount of segments that had exactly that length.
188      **/
189     typedef struct _tess_coordinate_delta
190     {
191         unsigned int counter;
192         float delta;
193 
194         /* Constructor. Resets all values to 0 */
_tess_coordinate_deltaglcts::TessellationShaderVertexSpacing::_tess_coordinate_delta195         _tess_coordinate_delta()
196         {
197             counter = 0;
198             delta   = 0.0f;
199         }
200     } _tess_coordinate_delta;
201 
202     /** Vector of coordinate deltas */
203     typedef std::vector<_tess_coordinate_delta> _tess_coordinate_deltas;
204     typedef _tess_coordinate_deltas::const_iterator _tess_coordinate_deltas_const_iterator;
205     typedef _tess_coordinate_deltas::iterator _tess_coordinate_deltas_iterator;
206 
207     /** Vector of Cartesian coordinates making up an edge. */
208     typedef std::vector<_tess_coordinate_cartesian> _tess_edge_points;
209     typedef _tess_edge_points::const_iterator _tess_edge_points_const_iterator;
210     typedef _tess_edge_points::iterator _tess_edge_points_iterator;
211 
212     /** Defines a single edge of a quad/triangle *or* a single isoline (depending
213      *  on the primitive mode used for a test run, for which the edge is defined)
214      */
215     typedef struct _tess_edge
216     {
217         _tess_edge_points points;
218         float edge_length;
219         float outermost_tess_level;
220         float tess_level;
221 
222         /* Constructor.
223          *
224          * @param in_tess_level  Tessellation level value specific to the edge.
225          * @param in_edge_length Total Euclidean length of the edge.
226          */
_tess_edgeglcts::TessellationShaderVertexSpacing::_tess_edge227         _tess_edge(const float &in_tess_level, const float &in_outermost_tess_level, const float &in_edge_length)
228             : edge_length(in_edge_length)
229             , outermost_tess_level(in_outermost_tess_level)
230             , tess_level(in_tess_level)
231         {
232         }
233     } _tess_edge;
234 
235     /** Vector of edges */
236     typedef std::vector<_tess_edge> _tess_edges;
237     typedef _tess_edges::const_iterator _tess_edges_const_iterator;
238     typedef _tess_edges::iterator _tess_edges_iterator;
239 
240     /** Vector of test runs */
241     typedef std::vector<_run> _runs;
242     typedef _runs::const_iterator _runs_const_iterator;
243 
244     /** Comparator that is used to sort points relative to a certain origin. */
245     struct _comparator_relative_to_base_point
246     {
247         /* Constructor. Sets all fields to 0 */
_comparator_relative_to_base_pointglcts::TessellationShaderVertexSpacing::_comparator_relative_to_base_point248         _comparator_relative_to_base_point() : base_point(0, 0)
249         {
250         }
251 
252         /* Constructor.
253          *
254          * @param base_point Origin, against which all comparisons should be run against.
255          */
_comparator_relative_to_base_pointglcts::TessellationShaderVertexSpacing::_comparator_relative_to_base_point256         _comparator_relative_to_base_point(const _tess_coordinate_cartesian &_base_point) : base_point(_base_point)
257         {
258         }
259 
260         /* Tells which of the user-provided points is closer to the instance-specific
261          * "origin".
262          *
263          * @param a First point to use.
264          * @param b Second point to use.
265          *
266          * @return true if point @param a is closer to the "origin", false otherwise.
267          */
operator ()glcts::TessellationShaderVertexSpacing::_comparator_relative_to_base_point268         bool operator()(_tess_coordinate_cartesian a, _tess_coordinate_cartesian b)
269         {
270             float distance_a_to_base =
271                 deFloatSqrt((a.x - base_point.x) * (a.x - base_point.x) + (a.y - base_point.y) * (a.y - base_point.y));
272             float distance_b_to_base =
273                 deFloatSqrt((b.x - base_point.x) * (b.x - base_point.x) + (b.y - base_point.y) * (b.y - base_point.y));
274 
275             return distance_a_to_base < distance_b_to_base;
276         }
277 
278         _tess_coordinate_cartesian base_point;
279     };
280 
281     /** Comparator that is used to compare two tessellation coordinates using FP value
282      *  equal operator.
283      */
284     struct _comparator_exact_tess_coordinate_match
285     {
286         /* Constructor.
287          *
288          * @param in_base_coordinate Base tessellation coordinate to compare against.
289          */
_comparator_exact_tess_coordinate_matchglcts::TessellationShaderVertexSpacing::_comparator_exact_tess_coordinate_match290         _comparator_exact_tess_coordinate_match(const _tess_coordinate_cartesian &in_base_coordinate)
291             : base_coordinate(in_base_coordinate)
292         {
293         }
294 
295         /* Tells if the user-provided tessellation coordinate exactly matches the base tessellation
296          * coordinate.
297          *
298          * @param value Tessellation coordinate to use for the operation.
299          *
300          * @return true if the coordinates are equal, false otherwise.
301          */
operator ()glcts::TessellationShaderVertexSpacing::_comparator_exact_tess_coordinate_match302         bool operator()(const _tess_coordinate_cartesian &value)
303         {
304             return (value.x == base_coordinate.x) && (value.y == base_coordinate.y);
305         }
306 
307         _tess_coordinate_cartesian base_coordinate;
308     };
309 
310     /* Private methods */
311     static bool compareEdgeByX(_tess_coordinate_cartesian a, _tess_coordinate_cartesian b);
312     static bool compareEdgeByY(_tess_coordinate_cartesian a, _tess_coordinate_cartesian b);
313 
314     bool isPointOnLine(const _tess_coordinate_cartesian &line_v1, const _tess_coordinate_cartesian &line_v2,
315                        const _tess_coordinate_cartesian &point);
316 
317     _tess_edges getEdgesForIsolinesTessellation(const _run &run);
318     _tess_edges getEdgesForQuadsTessellation(const _run &run);
319     _tess_edges getEdgesForTrianglesTessellation(const _run &run);
320     void verifyEdges(const _tess_edges &edges, const _run &run);
321 
322     /* Private variables */
323     glw::GLint m_gl_max_tess_gen_level_value;
324     glw::GLuint m_vao_id;
325     _runs m_runs;
326     TessellationShaderUtils *m_utils;
327 };
328 
329 } // namespace glcts
330 
331 #endif // _ESEXTCTESSELLATIONSHADERVERTEXSPACING_HPP
332