#ifndef _ESEXTCTESSELLATIONSHADERVERTEXSPACING_HPP #define _ESEXTCTESSELLATIONSHADERVERTEXSPACING_HPP /*------------------------------------------------------------------------- * OpenGL Conformance Test Suite * ----------------------------- * * Copyright (c) 2014-2016 The Khronos Group Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ /*! * \file * \brief */ /*-------------------------------------------------------------------*/ #include "../esextcTestCaseBase.hpp" #include "esextcTessellationShaderUtils.hpp" #include "gluShaderUtil.hpp" #include "tcuDefs.hpp" #include namespace glcts { /** Implementation of Test Case 25 * * Make sure that vertex spacing mode defined in a tessellation evaluation * shader affects the tessellation primitive generator as per specification, * to the limit enforced by implementation-dependent behaviour. * Consider all three tessellation primitive generator modes (triangles, * quads, isolines). TE stage should be run in point mode. * Make sure that by default the tessellation primitive generator works in * equal_spacing spacing mode. * Make sure that negative inner levels are clamped as defined for active * vertex spacing mode. * * Technical details: * * 0. Consider the following set: {-1 (where valid), 1, MAX_TESS_GEN_LEVEL_EXT / 2, * MAX_TESS_GEN_LEVEL_EXT}. All combinations of values from this set * in regard to relevant inner/outer tessellation levels for all * primitive generator modes should be checked by this test. * * 1. This test should capture vertices output by TE stage and verify their * locations. If an edge is defined by function y = a * t + b (a, b * computed from locations of edge start & end points), t should be * calculated for each vertex that is a part of the edge considered. * 2. Test passes if t values are in agreement with the specification * (assume epsilon 1e-5) and vertex spacing mode considered. * * This test implementation skips configurations meeting all of the following * properties: * * - primitive mode: QUADS * - vertex spacing mode: FRACTIONAL ODD * - inner tess level[0]: <= 1 * - inner tess level[1]: <= 1 * * These configurations are affected by a nuance described in greater * detail in Khronos Bugzilla#11979, which this test cannot handle. **/ class TessellationShaderVertexSpacing : public TestCaseBase { public: /* Public methods */ TessellationShaderVertexSpacing(Context& context, const ExtParameters& extParams); virtual ~TessellationShaderVertexSpacing(void) { } virtual void deinit(void); void initTest(void); virtual IterateResult iterate(void); private: /* Private type definitions */ /** Stores properties of a single test run */ typedef struct _run { float inner[2]; float outer[4]; _tessellation_primitive_mode primitive_mode; _tessellation_shader_vertex_spacing vertex_spacing; std::vector data; float* data_cartesian; /* only used for 'triangles' case */ unsigned int n_vertices; /* Constructor. Resets all fields to default values */ _run() { memset(inner, 0, sizeof(inner)); memset(outer, 0, sizeof(outer)); data_cartesian = 0; n_vertices = 0; primitive_mode = TESSELLATION_SHADER_PRIMITIVE_MODE_UNKNOWN; vertex_spacing = TESSELLATION_SHADER_VERTEX_SPACING_UNKNOWN; } } _run; /** Stores either barycentric or Cartesian coordinate data * (depending on primitive mode of a test run this structure * will be instantiated for) */ typedef struct _tess_coordinate { float u; float v; float w; /* Constructor. Resets all fields to 0 */ _tess_coordinate() { u = 0.0f; v = 0.0f; w = 0.0f; } /* Constructor. * * @param u Value to set for U component; * @param v Value to set for V component; * @param w Value to set for W component; */ _tess_coordinate(float _u, float _v, float _w) { this->u = _u; this->v = _v; this->w = _w; } /** Compares two barycentric/Cartesian coordinates, using test-wide epsilon. * * @param in Coordinate to compare current instance against. * * @return true if the coordinates are equal, false otherwise. **/ bool operator==(const _tess_coordinate& in) const; } _tess_coordinate; /** Stores Cartesian coordinate data. */ typedef struct _tess_coordinate_cartesian { float x; float y; /* Constructor. Resets all values to 0 */ _tess_coordinate_cartesian() { x = 0.0f; y = 0.0f; } /* Constructor. * * @param x Value to use for X component; * @param y Value to use for Y component; */ _tess_coordinate_cartesian(float _x, float _y) { this->x = _x; this->y = _y; } /** Compares two Cartesian coordinates, using test-wide epsilon. * * @param in Coordinate to compare current instance against. * * @return true if the coordinates are equal, false otherwise. **/ bool operator==(const _tess_coordinate_cartesian& in) const; } _tess_coordinate_cartesian; /** Stores information on: * * - a delta between two coordinates; * - amount of segments that had exactly that length. **/ typedef struct _tess_coordinate_delta { unsigned int counter; float delta; /* Constructor. Resets all values to 0 */ _tess_coordinate_delta() { counter = 0; delta = 0.0f; } } _tess_coordinate_delta; /** Vector of coordinate deltas */ typedef std::vector<_tess_coordinate_delta> _tess_coordinate_deltas; typedef _tess_coordinate_deltas::const_iterator _tess_coordinate_deltas_const_iterator; typedef _tess_coordinate_deltas::iterator _tess_coordinate_deltas_iterator; /** Vector of Cartesian coordinates making up an edge. */ typedef std::vector<_tess_coordinate_cartesian> _tess_edge_points; typedef _tess_edge_points::const_iterator _tess_edge_points_const_iterator; typedef _tess_edge_points::iterator _tess_edge_points_iterator; /** Defines a single edge of a quad/triangle *or* a single isoline (depending * on the primitive mode used for a test run, for which the edge is defined) */ typedef struct _tess_edge { _tess_edge_points points; float edge_length; float outermost_tess_level; float tess_level; /* Constructor. * * @param in_tess_level Tessellation level value specific to the edge. * @param in_edge_length Total Euclidean length of the edge. */ _tess_edge(const float& in_tess_level, const float& in_outermost_tess_level, const float& in_edge_length) : edge_length(in_edge_length), outermost_tess_level(in_outermost_tess_level), tess_level(in_tess_level) { } } _tess_edge; /** Vector of edges */ typedef std::vector<_tess_edge> _tess_edges; typedef _tess_edges::const_iterator _tess_edges_const_iterator; typedef _tess_edges::iterator _tess_edges_iterator; /** Vector of test runs */ typedef std::vector<_run> _runs; typedef _runs::const_iterator _runs_const_iterator; /** Comparator that is used to sort points relative to a certain origin. */ struct _comparator_relative_to_base_point { /* Constructor. Sets all fields to 0 */ _comparator_relative_to_base_point() : base_point(0, 0) { } /* Constructor. * * @param base_point Origin, against which all comparisons should be run against. */ _comparator_relative_to_base_point(const _tess_coordinate_cartesian& _base_point) : base_point(_base_point) { } /* Tells which of the user-provided points is closer to the instance-specific * "origin". * * @param a First point to use. * @param b Second point to use. * * @return true if point @param a is closer to the "origin", false otherwise. */ bool operator()(_tess_coordinate_cartesian a, _tess_coordinate_cartesian b) { float distance_a_to_base = deFloatSqrt((a.x - base_point.x) * (a.x - base_point.x) + (a.y - base_point.y) * (a.y - base_point.y)); float distance_b_to_base = deFloatSqrt((b.x - base_point.x) * (b.x - base_point.x) + (b.y - base_point.y) * (b.y - base_point.y)); return distance_a_to_base < distance_b_to_base; } _tess_coordinate_cartesian base_point; }; /** Comparator that is used to compare two tessellation coordinates using FP value * equal operator. */ struct _comparator_exact_tess_coordinate_match { /* Constructor. * * @param in_base_coordinate Base tessellation coordinate to compare against. */ _comparator_exact_tess_coordinate_match(const _tess_coordinate_cartesian& in_base_coordinate) : base_coordinate(in_base_coordinate) { } /* Tells if the user-provided tessellation coordinate exactly matches the base tessellation * coordinate. * * @param value Tessellation coordinate to use for the operation. * * @return true if the coordinates are equal, false otherwise. */ bool operator()(const _tess_coordinate_cartesian& value) { return (value.x == base_coordinate.x) && (value.y == base_coordinate.y); } _tess_coordinate_cartesian base_coordinate; }; /* Private methods */ static bool compareEdgeByX(_tess_coordinate_cartesian a, _tess_coordinate_cartesian b); static bool compareEdgeByY(_tess_coordinate_cartesian a, _tess_coordinate_cartesian b); bool isPointOnLine(const _tess_coordinate_cartesian& line_v1, const _tess_coordinate_cartesian& line_v2, const _tess_coordinate_cartesian& point); _tess_edges getEdgesForIsolinesTessellation(const _run& run); _tess_edges getEdgesForQuadsTessellation(const _run& run); _tess_edges getEdgesForTrianglesTessellation(const _run& run); void verifyEdges(const _tess_edges& edges, const _run& run); /* Private variables */ glw::GLint m_gl_max_tess_gen_level_value; glw::GLuint m_vao_id; _runs m_runs; TessellationShaderUtils* m_utils; }; } // namespace glcts #endif // _ESEXTCTESSELLATIONSHADERVERTEXSPACING_HPP