blob: 18b0069c081c91e713ecc00516a9baa390f0cf0a [file] [log] [blame] [edit]
#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 <deMath.h>
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<char> 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 : public std::unary_function<float, bool>
{
/* 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