#ifndef _ESEXTCTESSELLATIONSHADERUTILS_HPP #define _ESEXTCTESSELLATIONSHADERUTILS_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 "gluContextInfo.hpp" #include "gluDefs.hpp" #include "glwFunctions.hpp" #include "tcuDefs.hpp" #include #include namespace glcts { /** Stores an ivec4 representation */ typedef struct _ivec4 { int x; int y; int z; int w; /** Constructor. * * @param in_x Value to use for X component; * @param in_y Value to use for Y component; * @param in_z Value to use for Z component; * @param in_w Value to use for W component. */ _ivec4(int in_x, int in_y, int in_z, int in_w) { x = in_x; y = in_y; z = in_z; w = in_w; } /** Compares all components of _ivec4 instance with * another instance. * * @return true if all components match, false otherwise. **/ bool operator==(const _ivec4& in) const { return (x == in.x) && (y == in.y) && (z == in.z) && (w == in.w); } /** Implements inequality operator. * * @return true if any of the compared components * do not match, false otherwise. **/ bool operator!=(const _ivec4& in) const { return !(*this == in); } } _ivec4; /* Stores a vec2 representation */ typedef struct _vec2 { float x; float y; /** Constructor. * * @param in_x Value to use for X component; * @param in_y Value to use for Y component; */ _vec2(float in_x, float in_y) { x = in_x; y = in_y; } /** Compares all components of _vec2 instance with * another instance, using == operator. * * @return true if all components match, false otherwise. **/ bool operator==(const _vec2& in) const { return (x == in.x) && (y == in.y); } /** Implements inequality operator. * * @return true if any of the compared components * do not match, false otherwise. **/ bool operator!=(const _vec2& in) const { return !(*this == in); } } _vec2; /* Stores a vec4 representation */ typedef struct _vec4 { float x; float y; float z; float w; /** Constructor. * * @param in_x Value to use for X component; * @param in_y Value to use for Y component; * @param in_z Value to use for Z component; * @param in_w Value to use for W component. */ _vec4(float in_x, float in_y, float in_z, float in_w) { x = in_x; y = in_y; z = in_z; w = in_w; } /** Compares all components of _vec4 instance with * another instance, using == operator. * * @return true if all components match, false otherwise. **/ bool operator==(const _vec4& in) const { return (x == in.x) && (y == in.y) && (z == in.z) && (w == in.w); } /** Implements inequality operator. * * @return true if any of the compared components * do not match, false otherwise. **/ bool operator!=(const _vec4& in) const { return !(*this == in); } } _vec4; /** Defines a set of tessellation inner+outer levels */ typedef struct _tessellation_levels { float inner[2]; float outer[4]; _tessellation_levels() { memset(inner, 0, sizeof(inner)); memset(outer, 0, sizeof(outer)); } } _tessellation_levels; /* Defines a vector of tessellation levels */ typedef std::vector<_tessellation_levels> _tessellation_levels_set; typedef _tessellation_levels_set::const_iterator _tessellation_levels_set_const_iterator; typedef _tessellation_levels_set::iterator _tessellation_levels_set_iterator; /* Determines condition that returned level sets should meet in order to be returned * by TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode() . */ typedef enum { /********* General modes: do not use these values in conjugation *********/ /* All combinations of values from the set {-1, 1, GL_MAX_TESS_GEN_LEVEL_EXT / 2, * GL_MAX_TESS_GEN_LEVEL_EXT} will be used for inner/outer tesselelation * levels relevant to user-specified primitive mode. * An important exception is that the negative value will be SKIPPED for * outer tessellation levels (because otherwise no geometry will be generated * by the tessellator) **/ TESSELLATION_LEVEL_SET_FILTER_ALL_COMBINATIONS = 0x1, /* Only combinations where: * * - inner tessellation levels use different values (inner[0] != inner[1]) * - outer tessellation levels use different values (outer[0] != outer[1] != * != outer[2] != outer[3]); * * are allowed. */ TESSELLATION_LEVEL_SET_FILTER_INNER_AND_OUTER_LEVELS_USE_DIFFERENT_VALUES = 0x2, /* All inner/outer tessellation level use the same base value */ TESSELLATION_LEVEL_SET_FILTER_ALL_LEVELS_USE_THE_SAME_VALUE = 0x4, /********* Flags: can be combined with above general mode values *********/ TESSELLATION_LEVEL_SET_FILTER_EXCLUDE_NEGATIVE_BASE_VALUE = 0x8 } _tessellation_level_set_filter; /* Represents primitive modes supported by GL_EXT_tessellation_shader */ typedef enum { TESSELLATION_SHADER_PRIMITIVE_MODE_FIRST = 0, TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES = TESSELLATION_SHADER_PRIMITIVE_MODE_FIRST, TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES, TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS, TESSELLATION_SHADER_PRIMITIVE_MODE_COUNT, TESSELLATION_SHADER_PRIMITIVE_MODE_UNKNOWN = TESSELLATION_SHADER_PRIMITIVE_MODE_COUNT } _tessellation_primitive_mode; /** Represents vertex ordering modes supported by GL_EXT_tessellation_shader */ typedef enum { TESSELLATION_SHADER_VERTEX_ORDERING_CCW, TESSELLATION_SHADER_VERTEX_ORDERING_CW, TESSELLATION_SHADER_VERTEX_ORDERING_DEFAULT, TESSELLATION_SHADER_VERTEX_ORDERING_UNKNOWN } _tessellation_shader_vertex_ordering; /** Represents vertex spacing modes supported by GL_EXT_tessellation_shader */ typedef enum { TESSELLATION_SHADER_VERTEX_SPACING_FIRST, TESSELLATION_SHADER_VERTEX_SPACING_EQUAL = TESSELLATION_SHADER_VERTEX_SPACING_FIRST, TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_EVEN, TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD, TESSELLATION_SHADER_VERTEX_SPACING_DEFAULT, TESSELLATION_SHADER_VERTEX_SPACING_COUNT, TESSELLATION_SHADER_VERTEX_SPACING_UNKNOWN = TESSELLATION_SHADER_VERTEX_SPACING_COUNT } _tessellation_shader_vertex_spacing; /** Defines what tesellation stages should be tested for a given test pass. */ typedef enum { TESSELLATION_TEST_TYPE_FIRST, TESSELLATION_TEST_TYPE_TCS_TES = TESSELLATION_TEST_TYPE_FIRST, /* tcs + tes stages defined */ TESSELLATION_TEST_TYPE_TES, /* only tes stage defined */ /* Always last */ TESSELLATION_TEST_TYPE_COUNT, TESSELLATION_TEST_TYPE_UNKNOWN = TESSELLATION_TEST_TYPE_COUNT } _tessellation_test_type; /* Stores various helper functions used across multiple tessellation shader tests */ class TessellationShaderUtils { public: /* Public methods */ TessellationShaderUtils(const glw::Functions& gl, glcts::TestCaseBase* parentTest); ~TessellationShaderUtils(); void compileShaders(glw::GLint n_shaders, const glw::GLuint* shaders, bool should_succeed); static void convertBarycentricCoordinatesToCartesian(const float* barycentric_coordinates, float* out_cartesian_coordinates); static void convertCartesianCoordinatesToBarycentric(const float* cartesian_coordinates, float* out_barycentric_coordinates); unsigned int getAmountOfVerticesGeneratedByTessellator(_tessellation_primitive_mode primitive_mode, const float* inner_tessellation_level, const float* outer_tessellation_level, _tessellation_shader_vertex_spacing vertex_spacing, bool is_point_mode_enabled); std::vector getDataGeneratedByTessellator(const float* inner, bool point_mode, _tessellation_primitive_mode primitive_mode, _tessellation_shader_vertex_ordering vertex_ordering, _tessellation_shader_vertex_spacing vertex_spacing, const float* outer); static std::string getESTokenForPrimitiveMode(_tessellation_primitive_mode primitive_mode); static std::string getESTokenForVertexOrderingMode(_tessellation_shader_vertex_ordering vertex_ordering); static std::string getESTokenForVertexSpacingMode(_tessellation_shader_vertex_spacing vertex_spacing); static std::string getGenericTCCode(unsigned int n_patch_vertices, bool should_use_glInvocationID_indexed_input); static std::string getGenericTECode(_tessellation_shader_vertex_spacing vertex_spacing, _tessellation_primitive_mode primitive_mode, _tessellation_shader_vertex_ordering vertex_ordering, bool point_mode); static glw::GLint getPatchVerticesForPrimitiveMode(_tessellation_primitive_mode primitive_mode); static void getTessellationLevelAfterVertexSpacing(_tessellation_shader_vertex_spacing vertex_spacing, float level, glw::GLint gl_max_tess_gen_level_value, float* out_clamped, float* out_clamped_and_rounded); static _tessellation_levels_set getTessellationLevelSetForPrimitiveMode(_tessellation_primitive_mode primitive_mode, glw::GLint gl_max_tess_gen_level_value, _tessellation_level_set_filter filter); static glw::GLenum getTFModeForPrimitiveMode(_tessellation_primitive_mode primitive_mode, bool is_point_mode); static bool isOuterEdgeVertex(_tessellation_primitive_mode primitive_mode, const float* tessellated_vertex_data); static bool isTriangleDefined(const float* triangle_vertex_data, const float* vertex_data); private: /* Private type definitions */ /** Defines a single counter program */ typedef struct _tessellation_vertex_counter_program { /* Properties */ float inner_tess_level[2]; bool is_point_mode_enabled; glw::GLint n_patch_vertices; float outer_tess_level[4]; _tessellation_primitive_mode primitive_mode; _tessellation_shader_vertex_spacing vertex_spacing; std::vector m_data; unsigned int n_data_vertices; glw::GLint po_id; glw::GLint tc_id; glw::GLint te_id; glw::GLint tess_level_inner_uniform_location; glw::GLint tess_level_outer_uniform_location; const glw::Functions& m_gl; _tessellation_vertex_counter_program(const glw::Functions& gl) : m_gl(gl) { memset(inner_tess_level, 0, sizeof(inner_tess_level)); memset(outer_tess_level, 0, sizeof(outer_tess_level)); is_point_mode_enabled = false; n_patch_vertices = 0; po_id = 0; primitive_mode = TESSELLATION_SHADER_PRIMITIVE_MODE_UNKNOWN; tc_id = 0; te_id = 0; vertex_spacing = TESSELLATION_SHADER_VERTEX_SPACING_UNKNOWN; n_data_vertices = 0; tess_level_inner_uniform_location = -1; tess_level_outer_uniform_location = -1; } ~_tessellation_vertex_counter_program() { if (po_id != 0) { m_gl.deleteProgram(po_id); po_id = 0; } if (tc_id != 0) { m_gl.deleteShader(tc_id); tc_id = 0; } if (te_id != 0) { m_gl.deleteShader(te_id); te_id = 0; } } } _tessellation_vertex_counter_program; /* A vector of counter programs */ typedef std::vector<_tessellation_vertex_counter_program> _programs; typedef _programs::const_iterator _programs_const_iterator; typedef _programs::iterator _programs_iterator; /* Private methods */ void captureTessellationData(_tessellation_vertex_counter_program& program); void deinit(); void init(); void initTessellationVertexCounterProgram(const float* inner_tess_level, const float* outer_tess_level, glw::GLint n_patch_vertices, _tessellation_shader_vertex_spacing vertex_spacing, _tessellation_primitive_mode primitive_mode, bool is_point_mode_enabled, _tessellation_vertex_counter_program& result_descriptor); /* Private variables */ const glw::Functions& m_gl; glw::GLuint m_bo_id; glw::GLuint m_fs_id; glw::GLuint m_qo_pg_id; glw::GLuint m_vs_id; glcts::TestCaseBase* m_parent_test; }; } // namespace glcts #endif // _ESEXTCTESSELLATIONSHADERUTILS_HPP