| /*------------------------------------------------------------------------- |
| * OpenGL Conformance Test Suite |
| * ----------------------------- |
| * |
| * Copyright (c) 2015-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 |
| */ /*-------------------------------------------------------------------*/ |
| |
| /** |
| * \file gl4cEnhancedLayoutsTests.cpp |
| * \brief Implements conformance tests for "Enhanced Layouts" functionality. |
| */ /*-------------------------------------------------------------------*/ |
| |
| #include "gl4cEnhancedLayoutsTests.hpp" |
| |
| #include "gluContextInfo.hpp" |
| #include "gluDefs.hpp" |
| #include "gluShaderUtil.hpp" |
| #include "gluStrUtil.hpp" |
| #include "glwEnums.hpp" |
| #include "glwFunctions.hpp" |
| #include "tcuTestLog.hpp" |
| |
| #include <algorithm> |
| #include <iomanip> |
| #include <string> |
| #include <vector> |
| |
| /* DEBUG */ |
| #define USE_NSIGHT 0 |
| #define DEBUG_ENBALE_MESSAGE_CALLBACK 0 |
| #define DEBUG_NEG_LOG_ERROR 0 |
| #define DEBUG_NEG_REMOVE_ERROR 0 |
| #define DEBUG_REPLACE_TOKEN 0 |
| #define DEBUG_REPEAT_TEST_CASE 0 |
| #define DEBUG_REPEATED_TEST_CASE 0 |
| |
| /* Texture test base */ |
| #define DEBUG_TTB_VERIFICATION_SNIPPET_STAGE 0 |
| #define DEBUG_TTB_VERIFICATION_SNIPPET_VARIABLE 0 |
| |
| /* Tests */ |
| #define DEBUG_VERTEX_ATTRIB_LOCATIONS_TEST_VARIABLE 0 |
| |
| /* WORKAROUNDS */ |
| #define WRKARD_UNIFORMBLOCKMEMBEROFFSETANDALIGNTEST 0 |
| #define WRKARD_UNIFORMBLOCKMEMBERALIGNNONPOWEROF2TEST 0 |
| #define WRKARD_UNIFORMBLOCKALIGNMENT 0 |
| #define WRKARD_VARYINGLOCATIONSTEST 0 |
| |
| using namespace glw; |
| |
| namespace gl4cts |
| { |
| namespace EnhancedLayouts |
| { |
| namespace Utils |
| { |
| /** Constants used by "random" generators **/ |
| static const GLuint s_rand_start = 3; |
| static const GLuint s_rand_max = 16; |
| static const GLuint s_rand_max_half = s_rand_max / 2; |
| |
| /** Seed used by "random" generators **/ |
| static GLuint s_rand = s_rand_start; |
| |
| /** Get "random" unsigned int value |
| * |
| * @return Value |
| **/ |
| static GLuint GetRandUint() |
| { |
| const GLuint rand = s_rand++; |
| |
| if (s_rand_max <= s_rand) |
| { |
| s_rand = s_rand_start; |
| } |
| |
| return rand; |
| } |
| |
| /** Get "random" int value |
| * |
| * @return Value |
| **/ |
| GLint GetRandInt() |
| { |
| const GLint rand = GetRandUint() - s_rand_max_half; |
| |
| return rand; |
| } |
| |
| /** Get "random" double value |
| * |
| * @return Value |
| **/ |
| GLdouble GetRandDouble() |
| { |
| const GLint rand = GetRandInt(); |
| |
| GLdouble result = (GLfloat)rand / (GLdouble)s_rand_max_half; |
| |
| return result; |
| } |
| |
| /** Get "random" float value |
| * |
| * @return Value |
| **/ |
| GLfloat GetRandFloat() |
| { |
| const GLint rand = GetRandInt(); |
| |
| GLfloat result = (GLfloat)rand / (GLfloat)s_rand_max_half; |
| |
| return result; |
| } |
| |
| /** String used by list routines **/ |
| static const GLchar* const g_list = "LIST"; |
| |
| /** Type constants **/ |
| const Type Type::_double = Type::GetType(Type::Double, 1, 1); |
| const Type Type::dmat2 = Type::GetType(Type::Double, 2, 2); |
| const Type Type::dmat2x3 = Type::GetType(Type::Double, 2, 3); |
| const Type Type::dmat2x4 = Type::GetType(Type::Double, 2, 4); |
| const Type Type::dmat3x2 = Type::GetType(Type::Double, 3, 2); |
| const Type Type::dmat3 = Type::GetType(Type::Double, 3, 3); |
| const Type Type::dmat3x4 = Type::GetType(Type::Double, 3, 4); |
| const Type Type::dmat4x2 = Type::GetType(Type::Double, 4, 2); |
| const Type Type::dmat4x3 = Type::GetType(Type::Double, 4, 3); |
| const Type Type::dmat4 = Type::GetType(Type::Double, 4, 4); |
| const Type Type::dvec2 = Type::GetType(Type::Double, 1, 2); |
| const Type Type::dvec3 = Type::GetType(Type::Double, 1, 3); |
| const Type Type::dvec4 = Type::GetType(Type::Double, 1, 4); |
| const Type Type::_int = Type::GetType(Type::Int, 1, 1); |
| const Type Type::ivec2 = Type::GetType(Type::Int, 1, 2); |
| const Type Type::ivec3 = Type::GetType(Type::Int, 1, 3); |
| const Type Type::ivec4 = Type::GetType(Type::Int, 1, 4); |
| const Type Type::_float = Type::GetType(Type::Float, 1, 1); |
| const Type Type::mat2 = Type::GetType(Type::Float, 2, 2); |
| const Type Type::mat2x3 = Type::GetType(Type::Float, 2, 3); |
| const Type Type::mat2x4 = Type::GetType(Type::Float, 2, 4); |
| const Type Type::mat3x2 = Type::GetType(Type::Float, 3, 2); |
| const Type Type::mat3 = Type::GetType(Type::Float, 3, 3); |
| const Type Type::mat3x4 = Type::GetType(Type::Float, 3, 4); |
| const Type Type::mat4x2 = Type::GetType(Type::Float, 4, 2); |
| const Type Type::mat4x3 = Type::GetType(Type::Float, 4, 3); |
| const Type Type::mat4 = Type::GetType(Type::Float, 4, 4); |
| const Type Type::vec2 = Type::GetType(Type::Float, 1, 2); |
| const Type Type::vec3 = Type::GetType(Type::Float, 1, 3); |
| const Type Type::vec4 = Type::GetType(Type::Float, 1, 4); |
| const Type Type::uint = Type::GetType(Type::Uint, 1, 1); |
| const Type Type::uvec2 = Type::GetType(Type::Uint, 1, 2); |
| const Type Type::uvec3 = Type::GetType(Type::Uint, 1, 3); |
| const Type Type::uvec4 = Type::GetType(Type::Uint, 1, 4); |
| |
| /** Generate data for type. This routine follows STD140 rules |
| * |
| * @return Vector of bytes filled with data |
| **/ |
| std::vector<GLubyte> Type::GenerateData() const |
| { |
| const GLuint alignment = GetActualAlignment(0, false); |
| |
| std::vector<GLubyte> data; |
| data.resize(alignment * m_n_columns); |
| |
| for (GLuint column = 0; column < m_n_columns; ++column) |
| { |
| GLvoid* ptr = (GLvoid*)&data[column * alignment]; |
| |
| switch (m_basic_type) |
| { |
| case Double: |
| { |
| GLdouble* d_ptr = (GLdouble*)ptr; |
| |
| for (GLuint i = 0; i < m_n_rows; ++i) |
| { |
| d_ptr[i] = GetRandDouble(); |
| } |
| } |
| break; |
| case Float: |
| { |
| GLfloat* f_ptr = (GLfloat*)ptr; |
| |
| for (GLuint i = 0; i < m_n_rows; ++i) |
| { |
| f_ptr[i] = GetRandFloat(); |
| } |
| } |
| break; |
| case Int: |
| { |
| GLint* i_ptr = (GLint*)ptr; |
| |
| for (GLuint i = 0; i < m_n_rows; ++i) |
| { |
| i_ptr[i] = GetRandInt(); |
| } |
| } |
| break; |
| case Uint: |
| { |
| GLuint* ui_ptr = (GLuint*)ptr; |
| |
| for (GLuint i = 0; i < m_n_rows; ++i) |
| { |
| ui_ptr[i] = GetRandUint(); |
| } |
| } |
| break; |
| } |
| } |
| |
| return data; |
| } |
| |
| /** Generate data for type. This routine packs data tightly. |
| * |
| * @return Vector of bytes filled with data |
| **/ |
| std::vector<GLubyte> Type::GenerateDataPacked() const |
| { |
| const GLuint basic_size = GetTypeSize(m_basic_type); |
| const GLuint n_elements = m_n_columns * m_n_rows; |
| const GLuint size = basic_size * n_elements; |
| |
| std::vector<GLubyte> data; |
| data.resize(size); |
| |
| GLvoid* ptr = (GLvoid*)&data[0]; |
| |
| switch (m_basic_type) |
| { |
| case Double: |
| { |
| GLdouble* d_ptr = (GLdouble*)ptr; |
| |
| for (GLuint i = 0; i < n_elements; ++i) |
| { |
| d_ptr[i] = GetRandDouble(); |
| } |
| } |
| break; |
| case Float: |
| { |
| GLfloat* f_ptr = (GLfloat*)ptr; |
| |
| for (GLuint i = 0; i < n_elements; ++i) |
| { |
| f_ptr[i] = GetRandFloat(); |
| } |
| } |
| break; |
| case Int: |
| { |
| GLint* i_ptr = (GLint*)ptr; |
| |
| for (GLuint i = 0; i < n_elements; ++i) |
| { |
| i_ptr[i] = GetRandInt(); |
| } |
| } |
| break; |
| case Uint: |
| { |
| GLuint* ui_ptr = (GLuint*)ptr; |
| |
| for (GLuint i = 0; i < n_elements; ++i) |
| { |
| ui_ptr[i] = GetRandUint(); |
| } |
| } |
| break; |
| } |
| |
| return data; |
| } |
| |
| /** Calculate "actual alignment". It work under assumption that align value is valid |
| * |
| * @param align Requested alignment, eg with "align" qualifier |
| * @param is_array Selects if an array of type or single instance should be considered |
| * |
| * @return Calculated value |
| **/ |
| GLuint Type::GetActualAlignment(GLuint align, bool is_array) const |
| { |
| const GLuint base_alignment = GetBaseAlignment(is_array); |
| |
| return std::max(align, base_alignment); |
| } |
| |
| /** Align given ofset with specified alignment |
| * |
| * @param offset Offset |
| * @param alignment Alignment |
| * |
| * @return Calculated value |
| **/ |
| GLuint align(GLuint offset, GLuint alignment) |
| { |
| const GLuint rest = offset % alignment; |
| |
| if (0 != rest) |
| { |
| GLuint missing = alignment - rest; |
| offset += missing; |
| } |
| |
| return offset; |
| } |
| |
| /** Calculate "actual offset" |
| * |
| * @param start_offset Requested offset |
| * @param actual_alignment Actual alignemnt |
| * |
| * @return Calculated value |
| **/ |
| GLuint Type::GetActualOffset(GLuint start_offset, GLuint actual_alignment) |
| { |
| GLuint offset = align(start_offset, actual_alignment); |
| |
| return offset; |
| } |
| |
| /** Calculate "base alignment" for given type |
| * |
| * @param is_array Select if array or single instance should be considered |
| * |
| * @return Calculated value |
| **/ |
| GLuint Type::GetBaseAlignment(bool is_array) const |
| { |
| GLuint elements = 1; |
| |
| switch (m_n_rows) |
| { |
| case 2: |
| elements = 2; |
| break; |
| case 3: |
| case 4: |
| elements = 4; |
| break; |
| default: |
| break; |
| } |
| |
| GLuint N = GetTypeSize(m_basic_type); |
| GLuint alignment = N * elements; |
| |
| if ((true == is_array) || (1 != m_n_columns)) |
| { |
| alignment = align(alignment, 16 /* vec4 alignment */); |
| } |
| |
| return alignment; |
| } |
| |
| /** Returns string representing GLSL constructor of type with arguments provided in data |
| * |
| * @param data Array of values that will be used as construcotr arguments. |
| * It is interpreted as tightly packed array of type matching this type. |
| * |
| * @return String in form "Type(args)" |
| **/ |
| std::string Type::GetGLSLConstructor(const GLvoid* data) const |
| { |
| const GLchar* type = GetGLSLTypeName(); |
| |
| std::stringstream stream; |
| |
| stream << type << "("; |
| |
| /* Scalar or vector */ |
| if (1 == m_n_columns) |
| { |
| for (GLuint row = 0; row < m_n_rows; ++row) |
| { |
| switch (m_basic_type) |
| { |
| case Double: |
| stream << ((GLdouble*)data)[row]; |
| break; |
| case Float: |
| stream << ((GLfloat*)data)[row]; |
| break; |
| case Int: |
| stream << ((GLint*)data)[row]; |
| break; |
| case Uint: |
| stream << ((GLuint*)data)[row]; |
| break; |
| } |
| |
| if (row + 1 != m_n_rows) |
| { |
| stream << ", "; |
| } |
| } |
| } |
| else /* Matrix: mat(vec(), vec() .. ) */ |
| { |
| const GLuint basic_size = GetTypeSize(m_basic_type); |
| // Very indescoverable defect, the column stride should be calculated by rows, such as mat2x3, which is 2, columns 3 rows, its column stride should be 3 * sizeof(float) |
| const GLuint column_stride = m_n_rows * basic_size; |
| const Type column_type = GetType(m_basic_type, 1, m_n_rows); |
| |
| for (GLuint column = 0; column < m_n_columns; ++column) |
| { |
| const GLuint column_offset = column * column_stride; |
| const GLvoid* column_data = (GLubyte*)data + column_offset; |
| |
| stream << column_type.GetGLSLConstructor(column_data); |
| |
| if (column + 1 != m_n_columns) |
| { |
| stream << ", "; |
| } |
| } |
| } |
| |
| stream << ")"; |
| |
| return stream.str(); |
| } |
| |
| /** Get glsl name of the type |
| * |
| * @return Name of glsl type |
| **/ |
| const glw::GLchar* Type::GetGLSLTypeName() const |
| { |
| static const GLchar* float_lut[4][4] = { |
| { "float", "vec2", "vec3", "vec4" }, |
| { 0, "mat2", "mat2x3", "mat2x4" }, |
| { 0, "mat3x2", "mat3", "mat3x4" }, |
| { 0, "mat4x2", "mat4x3", "mat4" }, |
| }; |
| |
| static const GLchar* double_lut[4][4] = { |
| { "double", "dvec2", "dvec3", "dvec4" }, |
| { 0, "dmat2", "dmat2x3", "dmat2x4" }, |
| { 0, "dmat3x2", "dmat3", "dmat3x4" }, |
| { 0, "dmat4x2", "dmat4x3", "dmat4" }, |
| }; |
| |
| static const GLchar* int_lut[4] = { "int", "ivec2", "ivec3", "ivec4" }; |
| |
| static const GLchar* uint_lut[4] = { "uint", "uvec2", "uvec3", "uvec4" }; |
| |
| const GLchar* result = 0; |
| |
| if ((1 > m_n_columns) || (1 > m_n_rows) || (4 < m_n_columns) || (4 < m_n_rows)) |
| { |
| return 0; |
| } |
| |
| switch (m_basic_type) |
| { |
| case Float: |
| result = float_lut[m_n_columns - 1][m_n_rows - 1]; |
| break; |
| case Double: |
| result = double_lut[m_n_columns - 1][m_n_rows - 1]; |
| break; |
| case Int: |
| result = int_lut[m_n_rows - 1]; |
| break; |
| case Uint: |
| result = uint_lut[m_n_rows - 1]; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| return result; |
| } |
| |
| /** Get number of locations required for the type |
| * |
| * @return Number of columns times: |
| * - 2 when type is double with 3 or 4 rows, |
| * - 1 otherwise or if it's a vertex shader input. |
| **/ |
| GLuint Type::GetLocations(bool is_vs_input) const |
| { |
| GLuint n_loc_per_column; |
| |
| /* 1 or 2 doubles any for rest */ |
| if ((2 >= m_n_rows) || (Double != m_basic_type) || is_vs_input) |
| { |
| n_loc_per_column = 1; |
| } |
| else |
| { |
| /* 3 and 4 doubles */ |
| n_loc_per_column = 2; |
| } |
| |
| return n_loc_per_column * m_n_columns; |
| } |
| |
| /** Get size of the type in bytes. |
| * Note that this routine doesn't consider arrays and assumes |
| * column_major matrices. |
| * |
| * @return Formula: |
| * - If std140 packaging and matrix; number of columns * base alignment |
| * - Otherwise; number of elements * sizeof(base_type) |
| **/ |
| GLuint Type::GetSize(const bool is_std140) const |
| { |
| const GLuint basic_type_size = GetTypeSize(m_basic_type); |
| const GLuint n_elements = m_n_columns * m_n_rows; |
| |
| if (is_std140 && m_n_columns > 1) |
| { |
| return m_n_columns * GetBaseAlignment(false); |
| } |
| |
| return basic_type_size * n_elements; |
| } |
| |
| /** Get GLenum representing the type |
| * |
| * @return GLenum |
| **/ |
| GLenum Type::GetTypeGLenum() const |
| { |
| static const GLenum float_lut[4][4] = { |
| { GL_FLOAT, GL_FLOAT_VEC2, GL_FLOAT_VEC3, GL_FLOAT_VEC4 }, |
| { 0, GL_FLOAT_MAT2, GL_FLOAT_MAT2x3, GL_FLOAT_MAT2x4 }, |
| { 0, GL_FLOAT_MAT3x2, GL_FLOAT_MAT3, GL_FLOAT_MAT3x4 }, |
| { 0, GL_FLOAT_MAT4x2, GL_FLOAT_MAT4x3, GL_FLOAT_MAT4 }, |
| }; |
| |
| static const GLenum double_lut[4][4] = { |
| { GL_DOUBLE, GL_DOUBLE_VEC2, GL_DOUBLE_VEC3, GL_DOUBLE_VEC4 }, |
| { 0, GL_DOUBLE_MAT2, GL_DOUBLE_MAT2x3, GL_DOUBLE_MAT2x4 }, |
| { 0, GL_DOUBLE_MAT3x2, GL_DOUBLE_MAT3, GL_DOUBLE_MAT3x4 }, |
| { 0, GL_DOUBLE_MAT4x2, GL_DOUBLE_MAT4x3, GL_DOUBLE_MAT4 }, |
| }; |
| |
| static const GLenum int_lut[4] = { GL_INT, GL_INT_VEC2, GL_INT_VEC3, GL_INT_VEC4 }; |
| |
| static const GLenum uint_lut[4] = { GL_UNSIGNED_INT, GL_UNSIGNED_INT_VEC2, GL_UNSIGNED_INT_VEC3, |
| GL_UNSIGNED_INT_VEC4 }; |
| |
| GLenum result = 0; |
| |
| if ((1 > m_n_columns) || (1 > m_n_rows) || (4 < m_n_columns) || (4 < m_n_rows)) |
| { |
| return 0; |
| } |
| |
| switch (m_basic_type) |
| { |
| case Float: |
| result = float_lut[m_n_columns - 1][m_n_rows - 1]; |
| break; |
| case Double: |
| result = double_lut[m_n_columns - 1][m_n_rows - 1]; |
| break; |
| case Int: |
| result = int_lut[m_n_rows - 1]; |
| break; |
| case Uint: |
| result = uint_lut[m_n_rows - 1]; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| return result; |
| } |
| |
| /** Calculate the number of components consumed by a type |
| * according to 11.1.2.1 Output Variables |
| * |
| * @return Calculated number of components for the type |
| **/ |
| GLuint Type::GetNumComponents() const |
| { |
| // Rule 3 of Section 7.6.2.2 |
| // If the member is a three-component vector with components consuming N |
| // basic machine units, the base alignment is 4N. |
| GLuint num_components = (m_n_rows == 3 ? 4 : m_n_rows) * m_n_columns; |
| |
| if (m_basic_type == Double) |
| { |
| num_components *= 2; |
| } |
| |
| return num_components; |
| } |
| |
| /** Calculate the valid values to use with the component qualifier |
| * |
| * @return Vector with the valid values, in growing order, or empty if |
| * the component qualifier is not allowed |
| **/ |
| std::vector<GLuint> Type::GetValidComponents() const |
| { |
| const GLuint component_size = Utils::Type::Double == m_basic_type ? 2 : 1; |
| const GLuint n_components_per_location = Utils::Type::Double == m_basic_type ? 2 : 4; |
| const GLuint n_req_components = m_n_rows; |
| const GLint max_valid_component = (GLint)n_components_per_location - (GLint)n_req_components; |
| std::vector<GLuint> data; |
| |
| /* The component qualifier cannot be used for matrices */ |
| if (1 != m_n_columns) |
| { |
| return data; |
| } |
| |
| /* The component qualifier cannot be used for dvec3/dvec4 */ |
| if (max_valid_component < 0) |
| { |
| return data; |
| } |
| |
| for (GLuint i = 0; i <= (GLuint)max_valid_component; ++i) |
| { |
| data.push_back(i * component_size); |
| } |
| |
| return data; |
| } |
| |
| /** Calculate stride for the type according to std140 rules |
| * |
| * @param alignment Alignment of type |
| * @param n_columns Number of columns |
| * @param n_array_elements Number of elements in array |
| * |
| * @return Calculated value |
| **/ |
| GLuint Type::CalculateStd140Stride(GLuint alignment, GLuint n_columns, GLuint n_array_elements) |
| { |
| GLuint stride = alignment * n_columns; |
| if (0 != n_array_elements) |
| { |
| stride *= n_array_elements; |
| } |
| |
| return stride; |
| } |
| |
| /** Check if glsl support matrices for specific basic type |
| * |
| * @param type Basic type |
| * |
| * @return true if matrices of <type> are supported, false otherwise |
| **/ |
| bool Type::DoesTypeSupportMatrix(TYPES type) |
| { |
| bool result = false; |
| |
| switch (type) |
| { |
| case Float: |
| case Double: |
| result = true; |
| break; |
| case Int: |
| case Uint: |
| result = false; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| return result; |
| } |
| |
| /** Creates instance of Type |
| * |
| * @param basic_type Select basic type of instance |
| * @param n_columns Number of columns |
| * @param n_rows Number of rows |
| * |
| * @return Type instance |
| **/ |
| Type Type::GetType(TYPES basic_type, glw::GLuint n_columns, glw::GLuint n_rows) |
| { |
| Type type = { basic_type, n_columns, n_rows }; |
| |
| return type; |
| } |
| |
| /** Get Size of given type in bytes |
| * |
| * @param type |
| * |
| * @return Size of type |
| **/ |
| GLuint Type::GetTypeSize(TYPES type) |
| { |
| GLuint result = 0; |
| |
| switch (type) |
| { |
| case Float: |
| result = sizeof(GLfloat); |
| break; |
| case Double: |
| result = sizeof(GLdouble); |
| break; |
| case Int: |
| result = sizeof(GLint); |
| break; |
| case Uint: |
| result = sizeof(GLuint); |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| return result; |
| } |
| |
| /** Get GLenum representing given type |
| * |
| * @param type |
| * |
| * @return GLenum value |
| **/ |
| GLenum Type::GetTypeGLenum(TYPES type) |
| { |
| GLenum result = 0; |
| |
| switch (type) |
| { |
| case Float: |
| result = GL_FLOAT; |
| break; |
| case Double: |
| result = GL_DOUBLE; |
| break; |
| case Int: |
| result = GL_INT; |
| break; |
| case Uint: |
| result = GL_UNSIGNED_INT; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| return result; |
| } |
| |
| /** Check if two types can share the same location, based on the underlying numerical type and bit width |
| * |
| * @param first First type to compare |
| * @param second Second type to compare |
| * |
| * @return true if the types can share the same location |
| **/ |
| bool Type::CanTypesShareLocation(TYPES first, TYPES second) |
| { |
| if (first == second) |
| { |
| return true; |
| } |
| |
| if (Float == first || Float == second || Double == first || Double == second) |
| { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| /** Get proper glUniformNdv routine for vectors with specified number of rows |
| * |
| * @param gl GL functions |
| * @param n_rows Number of rows |
| * |
| * @return Function address |
| **/ |
| uniformNdv getUniformNdv(const glw::Functions& gl, glw::GLuint n_rows) |
| { |
| uniformNdv result = 0; |
| |
| switch (n_rows) |
| { |
| case 1: |
| result = gl.uniform1dv; |
| break; |
| case 2: |
| result = gl.uniform2dv; |
| break; |
| case 3: |
| result = gl.uniform3dv; |
| break; |
| case 4: |
| result = gl.uniform4dv; |
| break; |
| default: |
| TCU_FAIL("Invalid number of rows"); |
| } |
| |
| return result; |
| } |
| |
| /** Get proper glUniformNfv routine for vectors with specified number of rows |
| * |
| * @param gl GL functions |
| * @param n_rows Number of rows |
| * |
| * @return Function address |
| **/ |
| uniformNfv getUniformNfv(const glw::Functions& gl, glw::GLuint n_rows) |
| { |
| uniformNfv result = 0; |
| |
| switch (n_rows) |
| { |
| case 1: |
| result = gl.uniform1fv; |
| break; |
| case 2: |
| result = gl.uniform2fv; |
| break; |
| case 3: |
| result = gl.uniform3fv; |
| break; |
| case 4: |
| result = gl.uniform4fv; |
| break; |
| default: |
| TCU_FAIL("Invalid number of rows"); |
| } |
| |
| return result; |
| } |
| |
| /** Get proper glUniformNiv routine for vectors with specified number of rows |
| * |
| * @param gl GL functions |
| * @param n_rows Number of rows |
| * |
| * @return Function address |
| **/ |
| uniformNiv getUniformNiv(const glw::Functions& gl, glw::GLuint n_rows) |
| { |
| uniformNiv result = 0; |
| |
| switch (n_rows) |
| { |
| case 1: |
| result = gl.uniform1iv; |
| break; |
| case 2: |
| result = gl.uniform2iv; |
| break; |
| case 3: |
| result = gl.uniform3iv; |
| break; |
| case 4: |
| result = gl.uniform4iv; |
| break; |
| default: |
| TCU_FAIL("Invalid number of rows"); |
| } |
| |
| return result; |
| } |
| |
| /** Get proper glUniformNuiv routine for vectors with specified number of rows |
| * |
| * @param gl GL functions |
| * @param n_rows Number of rows |
| * |
| * @return Function address |
| **/ |
| uniformNuiv getUniformNuiv(const glw::Functions& gl, glw::GLuint n_rows) |
| { |
| uniformNuiv result = 0; |
| |
| switch (n_rows) |
| { |
| case 1: |
| result = gl.uniform1uiv; |
| break; |
| case 2: |
| result = gl.uniform2uiv; |
| break; |
| case 3: |
| result = gl.uniform3uiv; |
| break; |
| case 4: |
| result = gl.uniform4uiv; |
| break; |
| default: |
| TCU_FAIL("Invalid number of rows"); |
| } |
| |
| return result; |
| } |
| |
| /** Get proper glUniformMatrixNdv routine for matrix with specified number of columns and rows |
| * |
| * @param gl GL functions |
| * @param n_rows Number of rows |
| * |
| * @return Function address |
| **/ |
| uniformMatrixNdv getUniformMatrixNdv(const glw::Functions& gl, glw::GLuint n_columns, glw::GLuint n_rows) |
| { |
| uniformMatrixNdv result = 0; |
| |
| switch (n_columns) |
| { |
| case 2: |
| switch (n_rows) |
| { |
| case 2: |
| result = gl.uniformMatrix2dv; |
| break; |
| case 3: |
| result = gl.uniformMatrix2x3dv; |
| break; |
| case 4: |
| result = gl.uniformMatrix2x4dv; |
| break; |
| default: |
| TCU_FAIL("Invalid number of rows"); |
| } |
| break; |
| case 3: |
| switch (n_rows) |
| { |
| case 2: |
| result = gl.uniformMatrix3x2dv; |
| break; |
| case 3: |
| result = gl.uniformMatrix3dv; |
| break; |
| case 4: |
| result = gl.uniformMatrix3x4dv; |
| break; |
| default: |
| TCU_FAIL("Invalid number of rows"); |
| } |
| break; |
| case 4: |
| switch (n_rows) |
| { |
| case 2: |
| result = gl.uniformMatrix4x2dv; |
| break; |
| case 3: |
| result = gl.uniformMatrix4x3dv; |
| break; |
| case 4: |
| result = gl.uniformMatrix4dv; |
| break; |
| default: |
| TCU_FAIL("Invalid number of rows"); |
| } |
| break; |
| default: |
| TCU_FAIL("Invalid number of columns"); |
| } |
| |
| return result; |
| } |
| |
| /** Get proper glUniformMatrixNfv routine for vectors with specified number of columns and rows |
| * |
| * @param gl GL functions |
| * @param n_rows Number of rows |
| * |
| * @return Function address |
| **/ |
| uniformMatrixNfv getUniformMatrixNfv(const glw::Functions& gl, glw::GLuint n_columns, glw::GLuint n_rows) |
| { |
| uniformMatrixNfv result = 0; |
| |
| switch (n_columns) |
| { |
| case 2: |
| switch (n_rows) |
| { |
| case 2: |
| result = gl.uniformMatrix2fv; |
| break; |
| case 3: |
| result = gl.uniformMatrix2x3fv; |
| break; |
| case 4: |
| result = gl.uniformMatrix2x4fv; |
| break; |
| default: |
| TCU_FAIL("Invalid number of rows"); |
| } |
| break; |
| case 3: |
| switch (n_rows) |
| { |
| case 2: |
| result = gl.uniformMatrix3x2fv; |
| break; |
| case 3: |
| result = gl.uniformMatrix3fv; |
| break; |
| case 4: |
| result = gl.uniformMatrix3x4fv; |
| break; |
| default: |
| TCU_FAIL("Invalid number of rows"); |
| } |
| break; |
| case 4: |
| switch (n_rows) |
| { |
| case 2: |
| result = gl.uniformMatrix4x2fv; |
| break; |
| case 3: |
| result = gl.uniformMatrix4x3fv; |
| break; |
| case 4: |
| result = gl.uniformMatrix4fv; |
| break; |
| default: |
| TCU_FAIL("Invalid number of rows"); |
| } |
| break; |
| default: |
| TCU_FAIL("Invalid number of columns"); |
| } |
| |
| return result; |
| } |
| |
| bool verifyVarying(Program& program, const std::string& parent_name, const Variable::Descriptor& desc, |
| std::stringstream& stream, bool is_input) |
| { |
| GLint component = 0; |
| GLuint index = 0; |
| GLenum interface = GL_PROGRAM_INPUT; |
| GLint location = 0; |
| |
| if (false == is_input) |
| { |
| interface = GL_PROGRAM_OUTPUT; |
| } |
| |
| const std::string& name = Utils::Variable::GetReference(parent_name, desc, Utils::Variable::BASIC, 0); |
| |
| try |
| { |
| index = program.GetResourceIndex(name, interface); |
| |
| program.GetResource(interface, index, GL_LOCATION, 1 /* size */, &location); |
| program.GetResource(interface, index, GL_LOCATION_COMPONENT, 1 /* size */, &component); |
| } |
| catch (std::exception& exc) |
| { |
| stream << "Failed to query program for varying: " << desc.m_name << ". Reason: " << exc.what() << "\n"; |
| |
| return false; |
| } |
| |
| bool result = true; |
| |
| if (location != desc.m_expected_location) |
| { |
| stream << "Attribute: " << desc.m_name << " - invalid location: " << location |
| << " expected: " << desc.m_expected_location << std::endl; |
| result = false; |
| } |
| if (component != desc.m_expected_component) |
| { |
| stream << "Attribute: " << desc.m_name << " - invalid component: " << component |
| << " expected: " << desc.m_expected_component << std::endl; |
| result = false; |
| } |
| |
| return result; |
| } |
| |
| /** Query program resource for given variable and verify that everything is as expected |
| * |
| * @param program Program object |
| * @param variable Variable object |
| * @param stream Stream that will be used to log any error |
| * @param is_input Selects if varying is input or output |
| * |
| * @return true if verification is positive, false otherwise |
| **/ |
| bool checkVarying(Program& program, Shader::STAGES stage, const Variable& variable, std::stringstream& stream, bool is_input) |
| { |
| bool result = true; |
| |
| if (variable.IsBlock()) |
| { |
| Utils::Interface* interface = variable.m_descriptor.m_interface; |
| const size_t n_members = interface->m_members.size(); |
| |
| for (size_t i = 0; i < n_members; ++i) |
| { |
| const Variable::Descriptor& member = interface->m_members[i]; |
| bool member_result = verifyVarying(program, interface->m_name, member, stream, is_input); |
| |
| if (false == member_result) |
| { |
| result = false; |
| } |
| } |
| } |
| /* |
| To query the the location of struct member by glGetProgramResource, we need pass the variable name "gs_fs_output[0].single", |
| but in original implementation, the test pass the name "Data.single", which can't get any valid result. |
| struct Data { |
| dmat2 single; |
| dmat2 array[1]; |
| }; |
| layout (location = 0) in Data gs_fs_output[1]; |
| */ |
| else if (variable.IsStruct()) |
| { |
| Utils::Interface* interface = variable.m_descriptor.m_interface; |
| const size_t n_members = interface->m_members.size(); |
| std::string structVariable = variable.m_descriptor.m_name; |
| |
| switch (Variable::GetFlavour(stage, is_input ? Variable::INPUT : Variable::OUTPUT)) |
| { |
| case Variable::ARRAY: |
| case Variable::INDEXED_BY_INVOCATION_ID: |
| structVariable.append("[0]"); |
| break; |
| default: |
| break; |
| } |
| |
| // If struct variable is an array |
| if (0 != variable.m_descriptor.m_n_array_elements) |
| { |
| for (GLuint i = 0; i < variable.m_descriptor.m_n_array_elements; i++) |
| { |
| GLchar buffer[16]; |
| sprintf(buffer, "%d", i); |
| structVariable.append("["); |
| structVariable.append(buffer); |
| structVariable.append("]"); |
| for (size_t j = 0; j < n_members; ++j) |
| { |
| const Variable::Descriptor& member = interface->m_members[j]; |
| bool member_result = verifyVarying(program, structVariable, member, stream, is_input); |
| |
| if (false == member_result) |
| { |
| result = false; |
| } |
| } |
| } |
| } |
| else |
| { |
| for (GLuint i = 0; i < n_members; ++i) |
| { |
| const Variable::Descriptor& member = interface->m_members[i]; |
| bool member_result = verifyVarying(program, structVariable, member, stream, is_input); |
| |
| if (false == member_result) |
| { |
| result = false; |
| } |
| } |
| } |
| } |
| else |
| { |
| result = verifyVarying(program, "", variable.m_descriptor, stream, is_input); |
| } |
| return result; |
| } |
| |
| /** Query program resource for given variable and verify that everything is as expected |
| * |
| * @param program Program object |
| * @param variable Variable object |
| * @param stream Stream that will be used to log any error |
| * |
| * @return true if verification is positive, false otherwise |
| **/ |
| bool checkUniform(Program& program, const Utils::Variable& variable, std::stringstream& stream) |
| { |
| bool result = true; |
| |
| if (false == variable.IsBlock()) |
| { |
| TCU_FAIL("Not implemented"); |
| } |
| else |
| { |
| Utils::Interface* interface = variable.m_descriptor.m_interface; |
| |
| size_t size = interface->m_members.size(); |
| |
| std::vector<GLuint> indices; |
| std::vector<const char*> names; |
| std::vector<std::string> names_str; |
| std::vector<GLint> offsets; |
| |
| indices.resize(size); |
| names.resize(size); |
| names_str.resize(size); |
| offsets.resize(size); |
| |
| for (size_t i = 0; i < size; ++i) |
| { |
| indices[i] = 0; |
| offsets[i] = 0; |
| |
| const std::string& name = |
| Utils::Variable::GetReference(interface->m_name, interface->m_members[i], Utils::Variable::BASIC, 0); |
| |
| if (Utils::Variable::INTERFACE == interface->m_members[i].m_type) |
| { |
| const std::string& member_name = Utils::Variable::GetReference( |
| name, interface->m_members[i].m_interface->m_members[0], Utils::Variable::BASIC, 0); |
| |
| names_str[i] = member_name; |
| } |
| else |
| { |
| names_str[i] = name; |
| } |
| |
| names[i] = names_str[i].c_str(); |
| } |
| |
| try |
| { |
| program.GetUniformIndices(static_cast<glw::GLsizei>(size), &names[0], &indices[0]); |
| program.GetActiveUniformsiv(static_cast<glw::GLsizei>(size), &indices[0], GL_UNIFORM_OFFSET, &offsets[0]); |
| } |
| catch (std::exception& exc) |
| { |
| stream << "Failed to query program for uniforms in block: " << variable.m_descriptor.m_name |
| << ". Reason: " << exc.what() << "\n"; |
| |
| return false; |
| } |
| |
| for (size_t i = 0; i < size; ++i) |
| { |
| Utils::Variable::Descriptor& desc = interface->m_members[i]; |
| |
| if (offsets[i] != (GLint)desc.m_offset) |
| { |
| stream << "Uniform: " << desc.m_name << " - invalid offset: " << offsets[i] |
| << " expected: " << desc.m_offset << std::endl; |
| result = false; |
| } |
| } |
| } |
| |
| return result; |
| } |
| |
| /** Query program resource for given variable and verify that everything is as expected |
| * |
| * @param program Program object |
| * @param variable Variable object |
| * @param stream Stream that will be used to log any error |
| * |
| * @return true if verification is positive, false otherwise |
| **/ |
| bool checkSSB(Program& program, const Utils::Variable& variable, std::stringstream& stream) |
| { |
| bool result = true; |
| |
| if (false == variable.IsBlock()) |
| { |
| TCU_FAIL("Not implemented"); |
| } |
| else |
| { |
| Utils::Interface* interface = variable.m_descriptor.m_interface; |
| |
| size_t size = interface->m_members.size(); |
| |
| for (size_t i = 0; i < size; ++i) |
| { |
| GLuint index = 0; |
| std::string name_str = ""; |
| GLint offset = 0; |
| |
| const std::string& name = |
| Utils::Variable::GetReference(interface->m_name, interface->m_members[i], Utils::Variable::BASIC, 0); |
| |
| if (Utils::Variable::INTERFACE == interface->m_members[i].m_type) |
| { |
| const std::string& member_name = Utils::Variable::GetReference( |
| name, interface->m_members[i].m_interface->m_members[0], Utils::Variable::BASIC, 0); |
| |
| name_str = member_name; |
| } |
| else |
| { |
| name_str = name; |
| } |
| |
| try |
| { |
| index = program.GetResourceIndex(name_str, GL_BUFFER_VARIABLE); |
| |
| program.GetResource(GL_BUFFER_VARIABLE, index, GL_OFFSET, 1, &offset); |
| } |
| catch (std::exception& exc) |
| { |
| stream << "Failed to query program for buffer variable: " << variable.m_descriptor.m_name |
| << ". Reason: " << exc.what() << "\n"; |
| |
| return false; |
| } |
| |
| Utils::Variable::Descriptor& desc = interface->m_members[i]; |
| |
| if (offset != (GLint)desc.m_offset) |
| { |
| stream << "Uniform: " << desc.m_name << " - invalid offset: " << offset |
| << " expected: " << desc.m_offset << std::endl; |
| result = false; |
| } |
| } |
| } |
| |
| return result; |
| } |
| |
| /** Query program resources at given stage and verifies results |
| * |
| * @param program Program object |
| * @param program_interface Definition of program interface |
| * @param stage Stage to be verified |
| * @param check_inputs Select if inputs should be verified |
| * @param check_outputs Select if output should be verified |
| * @param check_uniforms Select if uniforms should be verified |
| * @param check_ssbs Select if buffers should be verified |
| * @param stream Stream that will be used to log any error |
| * |
| * @return true if verification is positive, false otherwise |
| **/ |
| bool checkProgramStage(Program& program, const ProgramInterface& program_interface, Utils::Shader::STAGES stage, |
| bool check_inputs, bool check_outputs, bool check_uniforms, bool check_ssbs, |
| std::stringstream& stream) |
| { |
| typedef Variable::PtrVector::const_iterator const_iterator; |
| |
| const ShaderInterface& interface = program_interface.GetShaderInterface(stage); |
| |
| bool result = true; |
| |
| /* Inputs */ |
| if (true == check_inputs) |
| { |
| const Variable::PtrVector& inputs = interface.m_inputs; |
| |
| for (const_iterator it = inputs.begin(); it != inputs.end(); ++it) |
| { |
| if (false == checkVarying(program, stage, **it, stream, true)) |
| { |
| result = false; |
| } |
| } |
| } |
| |
| /* Outputs */ |
| if (true == check_outputs) |
| { |
| const Variable::PtrVector& outputs = interface.m_outputs; |
| |
| for (const_iterator it = outputs.begin(); it != outputs.end(); ++it) |
| { |
| if (false == checkVarying(program, stage, **it, stream, false)) |
| { |
| result = false; |
| } |
| } |
| } |
| |
| /* Uniforms */ |
| if (true == check_uniforms) |
| { |
| const Variable::PtrVector& uniforms = interface.m_uniforms; |
| |
| for (const_iterator it = uniforms.begin(); it != uniforms.end(); ++it) |
| { |
| if (false == checkUniform(program, **it, stream)) |
| { |
| result = false; |
| } |
| } |
| } |
| |
| /* SSBs */ |
| if (true == check_ssbs) |
| { |
| const Variable::PtrVector& ssbs = interface.m_ssb_blocks; |
| |
| for (const_iterator it = ssbs.begin(); it != ssbs.end(); ++it) |
| { |
| if (false == checkSSB(program, **it, stream)) |
| { |
| result = false; |
| } |
| } |
| } |
| |
| return result; |
| } |
| |
| /** Query resources of monolithic compute program and verifies results |
| * |
| * @param program Program object |
| * @param program_interface Definition of program interface |
| * @param stream Stream that will be used to log any error |
| * |
| * @return true if verification is positive, false otherwise |
| **/ |
| bool checkMonolithicComputeProgramInterface(Program& program, const ProgramInterface& program_interface, |
| std::stringstream& stream) |
| { |
| bool result = true; |
| |
| if (false == checkProgramStage(program, program_interface, Shader::COMPUTE, false, false, true, true, stream)) |
| { |
| result = false; |
| } |
| |
| /* Done */ |
| return result; |
| } |
| |
| /** Query resources of monolithic draw program and verifies results |
| * |
| * @param program Program object |
| * @param program_interface Definition of program interface |
| * @param stream Stream that will be used to log any error |
| * |
| * @return true if verification is positive, false otherwise |
| **/ |
| bool checkMonolithicDrawProgramInterface(Program& program, const ProgramInterface& program_interface, |
| std::stringstream& stream) |
| { |
| bool result = true; |
| |
| if (false == checkProgramStage(program, program_interface, Shader::VERTEX, true, false, true, true, stream)) |
| { |
| result = false; |
| } |
| |
| /* Done */ |
| return result; |
| } |
| |
| /** Query resources of separable draw program and verifies results |
| * |
| * @param program Program object |
| * @param program_interface Definition of program interface |
| * @param stream Stream that will be used to log any error |
| * |
| * @return true if verification is positive, false otherwise |
| **/ |
| bool checkSeparableDrawProgramInterface(Program& program, const ProgramInterface& program_interface, |
| Utils::Shader::STAGES stage, std::stringstream& stream) |
| { |
| bool result = true; |
| |
| if (false == checkProgramStage(program, program_interface, stage, true, true, true, true, stream)) |
| { |
| result = false; |
| } |
| |
| /* Done */ |
| return result; |
| } |
| |
| /** Check if extension is supported |
| * |
| * @param context Test context |
| * @param extension_name Name of extension |
| * |
| * @return true if extension is supported, false otherwise |
| **/ |
| bool isExtensionSupported(deqp::Context& context, const GLchar* extension_name) |
| { |
| const std::vector<std::string>& extensions = context.getContextInfo().getExtensions(); |
| |
| if (std::find(extensions.begin(), extensions.end(), extension_name) == extensions.end()) |
| { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| /** Check if GL context meets version requirements |
| * |
| * @param gl Functions |
| * @param required_major Minimum required MAJOR_VERSION |
| * @param required_minor Minimum required MINOR_VERSION |
| * |
| * @return true if GL context version is at least as requested, false otherwise |
| **/ |
| bool isGLVersionAtLeast(const Functions& gl, GLint required_major, GLint required_minor) |
| { |
| glw::GLint major = 0; |
| glw::GLint minor = 0; |
| |
| gl.getIntegerv(GL_MAJOR_VERSION, &major); |
| gl.getIntegerv(GL_MINOR_VERSION, &minor); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv"); |
| |
| if (major > required_major) |
| { |
| /* Major is higher than required one */ |
| return true; |
| } |
| else if (major == required_major) |
| { |
| if (minor >= required_minor) |
| { |
| /* Major is equal to required one */ |
| /* Minor is higher than or equal to required one */ |
| return true; |
| } |
| else |
| { |
| /* Major is equal to required one */ |
| /* Minor is lower than required one */ |
| return false; |
| } |
| } |
| else |
| { |
| /* Major is lower than required one */ |
| return false; |
| } |
| } |
| |
| /** Replace first occurance of <token> with <text> in <string> starting at <search_posistion> |
| * |
| * @param token Token string |
| * @param search_position Position at which find will start, it is updated to position at which replaced text ends |
| * @param text String that will be used as replacement for <token> |
| * @param string String to work on |
| **/ |
| void replaceToken(const GLchar* token, size_t& search_position, const GLchar* text, std::string& string) |
| { |
| const size_t text_length = strlen(text); |
| const size_t token_length = strlen(token); |
| const size_t token_position = string.find(token, search_position); |
| |
| #if DEBUG_REPLACE_TOKEN |
| if (std::string::npos == token_position) |
| { |
| string.append("\n\nInvalid token: "); |
| string.append(token); |
| |
| TCU_FAIL(string.c_str()); |
| } |
| #endif /* DEBUG_REPLACE_TOKEN */ |
| |
| string.replace(token_position, token_length, text, text_length); |
| |
| search_position = token_position + text_length; |
| } |
| |
| /** Replace all occurances of <token> with <text> in <string> |
| * |
| * @param token Token string |
| * @param text String that will be used as replacement for <token> |
| * @param string String to work on |
| **/ |
| void replaceAllTokens(const GLchar* token, const GLchar* text, std::string& string) |
| { |
| const size_t text_length = strlen(text); |
| const size_t token_length = strlen(token); |
| |
| size_t search_position = 0; |
| |
| while (1) |
| { |
| const size_t token_position = string.find(token, search_position); |
| |
| if (std::string::npos == token_position) |
| { |
| break; |
| } |
| |
| search_position = token_position + text_length; |
| |
| string.replace(token_position, token_length, text, text_length); |
| } |
| } |
| |
| /** Rounds up the value to the next power of 2. |
| * This routine does not work for 0, see the url for explanations. |
| * |
| * @param value Starting point |
| * |
| * @return Calculated value |
| **/ |
| glw::GLuint roundUpToPowerOf2(glw::GLuint value) |
| { |
| /* Taken from: graphics.stanford.edu/~seander/bithacks.html */ |
| --value; |
| |
| value |= value >> 1; |
| value |= value >> 2; |
| value |= value >> 4; |
| value |= value >> 8; |
| value |= value >> 16; |
| |
| ++value; |
| |
| return value; |
| } |
| |
| /** Insert elements of list into string. |
| * List in string is represented either by token "LIST" or "SEPARATORLIST". |
| * If SEPARATORLIST is available, than SEPARATOR is replaced with <separator>. |
| * LIST is replaced with <element>SEPARATORLIST |
| * |
| * @param element Element to be inserted |
| * @param separator Separator inserted between elements |
| * @param search_position Position in string, where search for list should start |
| * @param string String |
| **/ |
| void insertElementOfList(const GLchar* element, const GLchar* separator, size_t& search_position, std::string& string) |
| { |
| static const char* list = g_list; |
| static const char* sep_list = "SEPARATORLIST"; |
| |
| /* Try to get "list" positions */ |
| const size_t list_position = string.find(list, search_position); |
| const size_t sep_list_position = string.find(sep_list, search_position); |
| |
| /* There is no list in string */ |
| if (std::string::npos == list_position) |
| { |
| return; |
| } |
| |
| if (9 /* strlen(SEPARATOR) */ == list_position - sep_list_position) |
| { |
| replaceToken("SEPARATOR", search_position, separator, string); |
| } |
| |
| /* Save search_position */ |
| const size_t start_position = search_position; |
| |
| /* Prepare new element */ |
| replaceToken("LIST", search_position, "ELEMENTSEPARATORLIST", string); |
| |
| /* Restore search_position */ |
| search_position = start_position; |
| |
| /* Replace element and separator */ |
| replaceToken("ELEMENT", search_position, element, string); |
| } |
| |
| /** Close list in string. |
| * If SEPARATORLIST is available, than SEPARATOR is replaced with <separator> |
| * LIST is replaced with "" |
| * |
| * @param separator Separator inserted between elements |
| * @param search_position Position in string, where search for list should start |
| * @param string String |
| **/ |
| void endList(const glw::GLchar* separator, size_t& search_position, std::string& string) |
| { |
| const size_t sep_position = string.find("SEPARATOR", search_position); |
| if (std::string::npos != sep_position) |
| { |
| replaceToken("SEPARATOR", search_position, separator, string); |
| } |
| |
| replaceToken("LIST", search_position, "", string); |
| } |
| |
| /* Buffer constants */ |
| const GLuint Buffer::m_invalid_id = -1; |
| |
| /** Constructor. |
| * |
| * @param context CTS context. |
| **/ |
| Buffer::Buffer(deqp::Context& context) : m_id(m_invalid_id), m_buffer(Array), m_context(context) |
| { |
| } |
| |
| /** Destructor |
| * |
| **/ |
| Buffer::~Buffer() |
| { |
| Release(); |
| } |
| |
| /** Initialize buffer instance |
| * |
| * @param buffer Buffer type |
| * @param usage Buffer usage enum |
| * @param size <size> parameter |
| * @param data <data> parameter |
| **/ |
| void Buffer::Init(BUFFERS buffer, USAGE usage, GLsizeiptr size, GLvoid* data) |
| { |
| /* Delete previous buffer instance */ |
| Release(); |
| |
| m_buffer = buffer; |
| |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| Generate(gl, m_id); |
| Bind(gl, m_id, m_buffer); |
| Data(gl, m_buffer, usage, size, data); |
| } |
| |
| /** Release buffer instance |
| * |
| **/ |
| void Buffer::Release() |
| { |
| if (m_invalid_id != m_id) |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| gl.deleteBuffers(1, &m_id); |
| m_id = m_invalid_id; |
| } |
| } |
| |
| /** Binds buffer to its target |
| * |
| **/ |
| void Buffer::Bind() const |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| Bind(gl, m_id, m_buffer); |
| } |
| |
| /** Binds indexed buffer |
| * |
| * @param index <index> parameter |
| **/ |
| void Buffer::BindBase(GLuint index) const |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| BindBase(gl, m_id, m_buffer, index); |
| } |
| |
| /** Binds range of buffer |
| * |
| * @param index <index> parameter |
| * @param offset <offset> parameter |
| * @param size <size> parameter |
| **/ |
| void Buffer::BindRange(GLuint index, GLintptr offset, GLsizeiptr size) const |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| BindRange(gl, m_id, m_buffer, index, offset, size); |
| } |
| |
| /** Allocate memory for buffer and sends initial content |
| * |
| * @param usage Buffer usage enum |
| * @param size <size> parameter |
| * @param data <data> parameter |
| **/ |
| void Buffer::Data(USAGE usage, glw::GLsizeiptr size, glw::GLvoid* data) |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| Data(gl, m_buffer, usage, size, data); |
| } |
| |
| /** Maps contents of buffer into CPU space |
| * |
| * @param access Requested access |
| * |
| * @return Pointer to memory region available for CPU |
| **/ |
| GLvoid* Buffer::Map(ACCESS access) |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| return Map(gl, m_buffer, access); |
| } |
| |
| /** Allocate memory for buffer and sends initial content |
| * |
| * @param offset Offset in buffer |
| * @param size <size> parameter |
| * @param data <data> parameter |
| **/ |
| void Buffer::SubData(glw::GLintptr offset, glw::GLsizeiptr size, glw::GLvoid* data) |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| SubData(gl, m_buffer, offset, size, data); |
| } |
| |
| /** Maps contents of buffer into CPU space |
| **/ |
| void Buffer::UnMap() |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| return UnMap(gl, m_buffer); |
| } |
| |
| /** Bind buffer to given target |
| * |
| * @param gl GL functions |
| * @param id Id of buffer |
| * @param buffer Buffer enum |
| **/ |
| void Buffer::Bind(const Functions& gl, GLuint id, BUFFERS buffer) |
| { |
| GLenum target = GetBufferGLenum(buffer); |
| |
| gl.bindBuffer(target, id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "BindBuffer"); |
| } |
| |
| /** Binds indexed buffer |
| * |
| * @param gl GL functions |
| * @param id Id of buffer |
| * @param buffer Buffer enum |
| * @param index <index> parameter |
| **/ |
| void Buffer::BindBase(const Functions& gl, GLuint id, BUFFERS buffer, GLuint index) |
| { |
| GLenum target = GetBufferGLenum(buffer); |
| |
| gl.bindBufferBase(target, index, id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "BindBufferBase"); |
| } |
| |
| /** Binds buffer range |
| * |
| * @param gl GL functions |
| * @param id Id of buffer |
| * @param buffer Buffer enum |
| * @param index <index> parameter |
| * @param offset <offset> parameter |
| * @param size <size> parameter |
| **/ |
| void Buffer::BindRange(const Functions& gl, GLuint id, BUFFERS buffer, GLuint index, GLintptr offset, GLsizeiptr size) |
| { |
| GLenum target = GetBufferGLenum(buffer); |
| |
| gl.bindBufferRange(target, index, id, offset, size); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "BindBufferRange"); |
| } |
| |
| /** Allocate memory for buffer and sends initial content |
| * |
| * @param gl GL functions |
| * @param buffer Buffer enum |
| * @param usage Buffer usage enum |
| * @param size <size> parameter |
| * @param data <data> parameter |
| **/ |
| void Buffer::Data(const glw::Functions& gl, BUFFERS buffer, USAGE usage, glw::GLsizeiptr size, glw::GLvoid* data) |
| { |
| GLenum target = GetBufferGLenum(buffer); |
| GLenum gl_usage = GetUsageGLenum(usage); |
| |
| gl.bufferData(target, size, data, gl_usage); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "BufferData"); |
| } |
| |
| /** Allocate memory for buffer and sends initial content |
| * |
| * @param gl GL functions |
| * @param buffer Buffer enum |
| * @param offset Offset in buffer |
| * @param size <size> parameter |
| * @param data <data> parameter |
| **/ |
| void Buffer::SubData(const glw::Functions& gl, BUFFERS buffer, glw::GLintptr offset, glw::GLsizeiptr size, |
| glw::GLvoid* data) |
| { |
| GLenum target = GetBufferGLenum(buffer); |
| |
| gl.bufferSubData(target, offset, size, data); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "BufferSubData"); |
| } |
| |
| /** Generate buffer |
| * |
| * @param gl GL functions |
| * @param out_id Id of buffer |
| **/ |
| void Buffer::Generate(const Functions& gl, GLuint& out_id) |
| { |
| GLuint id = m_invalid_id; |
| |
| gl.genBuffers(1, &id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "GenBuffers"); |
| |
| if (m_invalid_id == id) |
| { |
| TCU_FAIL("Got invalid id"); |
| } |
| |
| out_id = id; |
| } |
| |
| /** Maps buffer content |
| * |
| * @param gl GL functions |
| * @param buffer Buffer enum |
| * @param access Access rights for mapped region |
| * |
| * @return Mapped memory |
| **/ |
| void* Buffer::Map(const Functions& gl, BUFFERS buffer, ACCESS access) |
| { |
| GLenum target = GetBufferGLenum(buffer); |
| GLenum gl_access = GetAccessGLenum(access); |
| |
| void* result = gl.mapBuffer(target, gl_access); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "MapBuffer"); |
| |
| return result; |
| } |
| |
| /** Unmaps buffer |
| * |
| **/ |
| void Buffer::UnMap(const Functions& gl, BUFFERS buffer) |
| { |
| GLenum target = GetBufferGLenum(buffer); |
| |
| gl.unmapBuffer(target); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "UnmapBuffer"); |
| } |
| |
| /** Return GLenum representation of requested access |
| * |
| * @param access Requested access |
| * |
| * @return GLenum value |
| **/ |
| GLenum Buffer::GetAccessGLenum(ACCESS access) |
| { |
| GLenum result = 0; |
| |
| switch (access) |
| { |
| case ReadOnly: |
| result = GL_READ_ONLY; |
| break; |
| case WriteOnly: |
| result = GL_WRITE_ONLY; |
| break; |
| case ReadWrite: |
| result = GL_READ_WRITE; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| return result; |
| } |
| |
| /** Return GLenum representation of requested buffer type |
| * |
| * @param buffer Requested buffer type |
| * |
| * @return GLenum value |
| **/ |
| GLenum Buffer::GetBufferGLenum(BUFFERS buffer) |
| { |
| GLenum result = 0; |
| |
| switch (buffer) |
| { |
| case Array: |
| result = GL_ARRAY_BUFFER; |
| break; |
| case Element: |
| result = GL_ELEMENT_ARRAY_BUFFER; |
| break; |
| case Shader_Storage: |
| result = GL_SHADER_STORAGE_BUFFER; |
| break; |
| case Texture: |
| result = GL_TEXTURE_BUFFER; |
| break; |
| case Transform_feedback: |
| result = GL_TRANSFORM_FEEDBACK_BUFFER; |
| break; |
| case Uniform: |
| result = GL_UNIFORM_BUFFER; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| return result; |
| } |
| |
| /** Return GLenum representation of requested usage |
| * |
| * @param usage Requested usage |
| * |
| * @return GLenum value |
| **/ |
| GLenum Buffer::GetUsageGLenum(USAGE usage) |
| { |
| GLenum result = 0; |
| |
| switch (usage) |
| { |
| case DynamicCopy: |
| result = GL_DYNAMIC_COPY; |
| break; |
| case DynamicDraw: |
| result = GL_DYNAMIC_DRAW; |
| break; |
| case DynamicRead: |
| result = GL_DYNAMIC_READ; |
| break; |
| case StaticCopy: |
| result = GL_STATIC_COPY; |
| break; |
| case StaticDraw: |
| result = GL_STATIC_DRAW; |
| break; |
| case StaticRead: |
| result = GL_STATIC_READ; |
| break; |
| case StreamCopy: |
| result = GL_STREAM_COPY; |
| break; |
| case StreamDraw: |
| result = GL_STREAM_DRAW; |
| break; |
| case StreamRead: |
| result = GL_STREAM_READ; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| return result; |
| } |
| |
| /** Returns name of buffer target |
| * |
| * @param buffer Target enum |
| * |
| * @return Name of target |
| **/ |
| const GLchar* Buffer::GetBufferName(BUFFERS buffer) |
| { |
| const GLchar* name = 0; |
| |
| switch (buffer) |
| { |
| case Array: |
| name = "Array"; |
| break; |
| case Element: |
| name = "Element"; |
| break; |
| case Shader_Storage: |
| name = "Shader_Storage"; |
| break; |
| case Texture: |
| name = "Texture"; |
| break; |
| case Transform_feedback: |
| name = "Transform_feedback"; |
| break; |
| case Uniform: |
| name = "Uniform"; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| return name; |
| } |
| |
| /* Framebuffer constants */ |
| const GLuint Framebuffer::m_invalid_id = -1; |
| |
| /** Constructor |
| * |
| * @param context CTS context |
| **/ |
| Framebuffer::Framebuffer(deqp::Context& context) : m_id(m_invalid_id), m_context(context) |
| { |
| /* Nothing to be done here */ |
| } |
| |
| /** Destructor |
| * |
| **/ |
| Framebuffer::~Framebuffer() |
| { |
| Release(); |
| } |
| |
| /** Initialize framebuffer instance |
| * |
| **/ |
| void Framebuffer::Init() |
| { |
| /* Delete previous instance */ |
| Release(); |
| |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| Generate(gl, m_id); |
| } |
| |
| /** Release framebuffer instance |
| * |
| **/ |
| void Framebuffer::Release() |
| { |
| if (m_invalid_id != m_id) |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| gl.deleteFramebuffers(1, &m_id); |
| m_id = m_invalid_id; |
| } |
| } |
| |
| /** Attach texture to specified attachment |
| * |
| * @param attachment Attachment |
| * @param texture_id Texture id |
| * @param width Texture width |
| * @param height Texture height |
| **/ |
| void Framebuffer::AttachTexture(GLenum attachment, GLuint texture_id, GLuint width, GLuint height) |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| AttachTexture(gl, attachment, texture_id, width, height); |
| } |
| |
| /** Binds framebuffer to DRAW_FRAMEBUFFER |
| * |
| **/ |
| void Framebuffer::Bind() |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| Bind(gl, m_id); |
| } |
| |
| /** Clear framebuffer |
| * |
| * @param mask <mask> parameter of glClear. Decides which shall be cleared |
| **/ |
| void Framebuffer::Clear(GLenum mask) |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| Clear(gl, mask); |
| } |
| |
| /** Specifies clear color |
| * |
| * @param red Red channel |
| * @param green Green channel |
| * @param blue Blue channel |
| * @param alpha Alpha channel |
| **/ |
| void Framebuffer::ClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| ClearColor(gl, red, green, blue, alpha); |
| } |
| |
| /** Attach texture to specified attachment |
| * |
| * @param gl GL functions |
| * @param attachment Attachment |
| * @param texture_id Texture id |
| * @param width Texture width |
| * @param height Texture height |
| **/ |
| void Framebuffer::AttachTexture(const Functions& gl, GLenum attachment, GLuint texture_id, GLuint width, GLuint height) |
| { |
| gl.framebufferTexture(GL_DRAW_FRAMEBUFFER, attachment, texture_id, 0 /* level */); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "FramebufferTexture"); |
| |
| gl.viewport(0 /* x */, 0 /* y */, width, height); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Viewport"); |
| } |
| |
| /** Binds framebuffer to DRAW_FRAMEBUFFER |
| * |
| * @param gl GL functions |
| * @param id ID of framebuffer |
| **/ |
| void Framebuffer::Bind(const Functions& gl, GLuint id) |
| { |
| gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "BindFramebuffer"); |
| } |
| |
| /** Clear framebuffer |
| * |
| * @param gl GL functions |
| * @param mask <mask> parameter of glClear. Decides which shall be cleared |
| **/ |
| void Framebuffer::Clear(const Functions& gl, GLenum mask) |
| { |
| gl.clear(mask); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Clear"); |
| } |
| |
| /** Specifies clear color |
| * |
| * @param gl GL functions |
| * @param red Red channel |
| * @param green Green channel |
| * @param blue Blue channel |
| * @param alpha Alpha channel |
| **/ |
| void Framebuffer::ClearColor(const Functions& gl, GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) |
| { |
| gl.clearColor(red, green, blue, alpha); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "ClearColor"); |
| } |
| |
| /** Generate framebuffer |
| * |
| **/ |
| void Framebuffer::Generate(const Functions& gl, GLuint& out_id) |
| { |
| GLuint id = m_invalid_id; |
| |
| gl.genFramebuffers(1, &id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "GenFramebuffers"); |
| |
| if (m_invalid_id == id) |
| { |
| TCU_FAIL("Invalid id"); |
| } |
| |
| out_id = id; |
| } |
| |
| /* Shader's constants */ |
| const GLuint Shader::m_invalid_id = 0; |
| |
| /** Constructor. |
| * |
| * @param context CTS context. |
| **/ |
| Shader::Shader(deqp::Context& context) : m_id(m_invalid_id), m_context(context) |
| { |
| /* Nothing to be done here */ |
| } |
| |
| /** Destructor |
| * |
| **/ |
| Shader::~Shader() |
| { |
| Release(); |
| } |
| |
| /** Initialize shader instance |
| * |
| * @param stage Shader stage |
| * @param source Source code |
| **/ |
| void Shader::Init(STAGES stage, const std::string& source) |
| { |
| if (true == source.empty()) |
| { |
| /* No source == no shader */ |
| return; |
| } |
| |
| /* Delete any previous shader */ |
| Release(); |
| |
| /* Create, set source and compile */ |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| Create(gl, stage, m_id); |
| Source(gl, m_id, source); |
| |
| try |
| { |
| Compile(gl, m_id); |
| } |
| catch (const CompilationException& exc) |
| { |
| throw InvalidSourceException(exc.what(), source, stage); |
| } |
| } |
| |
| /** Release shader instance |
| * |
| **/ |
| void Shader::Release() |
| { |
| if (m_invalid_id != m_id) |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| gl.deleteShader(m_id); |
| m_id = m_invalid_id; |
| } |
| } |
| |
| /** Compile shader |
| * |
| * @param gl GL functions |
| * @param id Shader id |
| **/ |
| void Shader::Compile(const Functions& gl, GLuint id) |
| { |
| GLint status = GL_FALSE; |
| |
| /* Compile */ |
| gl.compileShader(id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "CompileShader"); |
| |
| /* Get compilation status */ |
| gl.getShaderiv(id, GL_COMPILE_STATUS, &status); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "GetShaderiv"); |
| |
| /* Log compilation error */ |
| if (GL_TRUE != status) |
| { |
| glw::GLint length = 0; |
| std::string message; |
| |
| /* Error log length */ |
| gl.getShaderiv(id, GL_INFO_LOG_LENGTH, &length); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "GetShaderiv"); |
| |
| /* Prepare storage */ |
| message.resize(length, 0); |
| |
| /* Get error log */ |
| gl.getShaderInfoLog(id, length, 0, &message[0]); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "GetShaderInfoLog"); |
| |
| throw CompilationException(message.c_str()); |
| } |
| } |
| |
| /** Create shader |
| * |
| * @param gl GL functions |
| * @param stage Shader stage |
| * @param out_id Shader id |
| **/ |
| void Shader::Create(const Functions& gl, STAGES stage, GLuint& out_id) |
| { |
| const GLenum shaderType = GetShaderStageGLenum(stage); |
| const GLuint id = gl.createShader(shaderType); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "CreateShader"); |
| |
| if (m_invalid_id == id) |
| { |
| TCU_FAIL("Failed to create shader"); |
| } |
| |
| out_id = id; |
| } |
| |
| /** Set shader's source code |
| * |
| * @param gl GL functions |
| * @param id Shader id |
| * @param source Shader source code |
| **/ |
| void Shader::Source(const Functions& gl, GLuint id, const std::string& source) |
| { |
| const GLchar* code = source.c_str(); |
| |
| gl.shaderSource(id, 1 /* count */, &code, 0 /* lengths */); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "ShaderSource"); |
| } |
| |
| /** Get GLenum repesenting shader stage |
| * |
| * @param stage Shader stage |
| * |
| * @return GLenum |
| **/ |
| GLenum Shader::GetShaderStageGLenum(STAGES stage) |
| { |
| GLenum result = 0; |
| |
| switch (stage) |
| { |
| case COMPUTE: |
| result = GL_COMPUTE_SHADER; |
| break; |
| case FRAGMENT: |
| result = GL_FRAGMENT_SHADER; |
| break; |
| case GEOMETRY: |
| result = GL_GEOMETRY_SHADER; |
| break; |
| case TESS_CTRL: |
| result = GL_TESS_CONTROL_SHADER; |
| break; |
| case TESS_EVAL: |
| result = GL_TESS_EVALUATION_SHADER; |
| break; |
| case VERTEX: |
| result = GL_VERTEX_SHADER; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| return result; |
| } |
| |
| /** Get string representing name of shader stage |
| * |
| * @param stage Shader stage |
| * |
| * @return String with name of shader stage |
| **/ |
| const glw::GLchar* Shader::GetStageName(STAGES stage) |
| { |
| const GLchar* result = 0; |
| |
| switch (stage) |
| { |
| case COMPUTE: |
| result = "compute"; |
| break; |
| case VERTEX: |
| result = "vertex"; |
| break; |
| case TESS_CTRL: |
| result = "tessellation control"; |
| break; |
| case TESS_EVAL: |
| result = "tessellation evaluation"; |
| break; |
| case GEOMETRY: |
| result = "geometry"; |
| break; |
| case FRAGMENT: |
| result = "fragment"; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| return result; |
| } |
| |
| /** Logs shader source |
| * |
| * @param context CTS context |
| * @param source Source of shader |
| * @param stage Shader stage |
| **/ |
| void Shader::LogSource(deqp::Context& context, const std::string& source, STAGES stage) |
| { |
| /* Skip empty shaders */ |
| if (true == source.empty()) |
| { |
| return; |
| } |
| |
| context.getTestContext().getLog() << tcu::TestLog::Message |
| << "Shader source. Stage: " << Shader::GetStageName(stage) |
| << tcu::TestLog::EndMessage << tcu::TestLog::KernelSource(source); |
| } |
| |
| /** Constructor |
| * |
| * @param message Compilation error message |
| **/ |
| Shader::CompilationException::CompilationException(const GLchar* message) |
| { |
| m_message = message; |
| } |
| |
| /** Returns error messages |
| * |
| * @return Compilation error message |
| **/ |
| const char* Shader::CompilationException::what() const throw() |
| { |
| return m_message.c_str(); |
| } |
| |
| /** Constructor |
| * |
| * @param message Compilation error message |
| **/ |
| Shader::InvalidSourceException::InvalidSourceException(const GLchar* error_message, const std::string& source, |
| STAGES stage) |
| : m_message(error_message), m_source(source), m_stage(stage) |
| { |
| } |
| |
| /** Returns error messages |
| * |
| * @return Compilation error message |
| **/ |
| const char* Shader::InvalidSourceException::what() const throw() |
| { |
| return "Compilation error"; |
| } |
| |
| /** Logs error message and shader sources **/ |
| void Shader::InvalidSourceException::log(deqp::Context& context) const |
| { |
| context.getTestContext().getLog() << tcu::TestLog::Message << "Failed to compile shader: " << m_message.c_str() |
| << tcu::TestLog::EndMessage; |
| |
| LogSource(context, m_source, m_stage); |
| } |
| |
| /* Program constants */ |
| const GLuint Pipeline::m_invalid_id = 0; |
| |
| /** Constructor. |
| * |
| * @param context CTS context. |
| **/ |
| Pipeline::Pipeline(deqp::Context& context) : m_id(m_invalid_id), m_context(context) |
| { |
| /* Nothing to be done here */ |
| } |
| |
| /** Destructor |
| * |
| **/ |
| Pipeline::~Pipeline() |
| { |
| Release(); |
| } |
| |
| /** Initialize pipline object |
| * |
| **/ |
| void Pipeline::Init() |
| { |
| Release(); |
| |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Generate */ |
| gl.genProgramPipelines(1, &m_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "GenProgramPipelines"); |
| } |
| |
| /** Release pipeline object |
| * |
| **/ |
| void Pipeline::Release() |
| { |
| if (m_invalid_id != m_id) |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Generate */ |
| gl.deleteProgramPipelines(1, &m_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "DeleteProgramPipelines"); |
| |
| m_id = m_invalid_id; |
| } |
| } |
| |
| /** Bind pipeline |
| * |
| **/ |
| void Pipeline::Bind() |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| Bind(gl, m_id); |
| } |
| |
| /** Set which stages should be active |
| * |
| * @param program_id Id of program |
| * @param stages Logical combination of enums representing stages |
| **/ |
| void Pipeline::UseProgramStages(GLuint program_id, GLenum stages) |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| UseProgramStages(gl, m_id, program_id, stages); |
| } |
| |
| /** Bind pipeline |
| * |
| * @param gl Functiions |
| * @param id Pipeline id |
| **/ |
| void Pipeline::Bind(const Functions& gl, GLuint id) |
| { |
| gl.bindProgramPipeline(id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "BindProgramPipeline"); |
| } |
| |
| /** Set which stages should be active |
| * |
| * @param gl Functiions |
| * @param id Pipeline id |
| * @param program_id Id of program |
| * @param stages Logical combination of enums representing stages |
| **/ |
| void Pipeline::UseProgramStages(const Functions& gl, GLuint id, GLuint program_id, GLenum stages) |
| { |
| gl.useProgramStages(id, stages, program_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "UseProgramStages"); |
| } |
| |
| /* Program constants */ |
| const GLuint Program::m_invalid_id = 0; |
| |
| /** Constructor. |
| * |
| * @param context CTS context. |
| **/ |
| Program::Program(deqp::Context& context) |
| : m_id(m_invalid_id) |
| , m_compute(context) |
| , m_fragment(context) |
| , m_geometry(context) |
| , m_tess_ctrl(context) |
| , m_tess_eval(context) |
| , m_vertex(context) |
| , m_context(context) |
| { |
| /* Nothing to be done here */ |
| } |
| |
| /** Destructor |
| * |
| **/ |
| Program::~Program() |
| { |
| Release(); |
| } |
| |
| /** Initialize program instance |
| * |
| * @param compute_shader Compute shader source code |
| * @param fragment_shader Fragment shader source code |
| * @param geometry_shader Geometry shader source code |
| * @param tessellation_control_shader Tessellation control shader source code |
| * @param tessellation_evaluation_shader Tessellation evaluation shader source code |
| * @param vertex_shader Vertex shader source code |
| * @param captured_varyings Vector of variables to be captured with transfrom feedback |
| * @param capture_interleaved Select mode of transform feedback (separate or interleaved) |
| * @param is_separable Selects if monolithic or separable program should be built. Defaults to false |
| **/ |
| void Program::Init(const std::string& compute_shader, const std::string& fragment_shader, |
| const std::string& geometry_shader, const std::string& tessellation_control_shader, |
| const std::string& tessellation_evaluation_shader, const std::string& vertex_shader, |
| const NameVector& captured_varyings, bool capture_interleaved, bool is_separable) |
| { |
| /* Delete previous program */ |
| Release(); |
| |
| /* GL entry points */ |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Initialize shaders */ |
| m_compute.Init(Shader::COMPUTE, compute_shader); |
| m_fragment.Init(Shader::FRAGMENT, fragment_shader); |
| m_geometry.Init(Shader::GEOMETRY, geometry_shader); |
| m_tess_ctrl.Init(Shader::TESS_CTRL, tessellation_control_shader); |
| m_tess_eval.Init(Shader::TESS_EVAL, tessellation_evaluation_shader); |
| m_vertex.Init(Shader::VERTEX, vertex_shader); |
| |
| /* Create program, set up transform feedback and attach shaders */ |
| Create(gl, m_id); |
| Capture(gl, m_id, captured_varyings, capture_interleaved); |
| Attach(gl, m_id, m_compute.m_id); |
| Attach(gl, m_id, m_fragment.m_id); |
| Attach(gl, m_id, m_geometry.m_id); |
| Attach(gl, m_id, m_tess_ctrl.m_id); |
| Attach(gl, m_id, m_tess_eval.m_id); |
| Attach(gl, m_id, m_vertex.m_id); |
| |
| /* Set separable parameter */ |
| if (true == is_separable) |
| { |
| gl.programParameteri(m_id, GL_PROGRAM_SEPARABLE, GL_TRUE); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "ProgramParameteri"); |
| } |
| |
| try |
| { |
| /* Link program */ |
| Link(gl, m_id); |
| } |
| catch (const LinkageException& exc) |
| { |
| throw BuildException(exc.what(), compute_shader, fragment_shader, geometry_shader, tessellation_control_shader, |
| tessellation_evaluation_shader, vertex_shader); |
| } |
| } |
| |
| /** Initialize program instance |
| * |
| * @param compute_shader Compute shader source code |
| * @param fragment_shader Fragment shader source code |
| * @param geometry_shader Geometry shader source code |
| * @param tessellation_control_shader Tessellation control shader source code |
| * @param tessellation_evaluation_shader Tessellation evaluation shader source code |
| * @param vertex_shader Vertex shader source code |
| * @param is_separable Selects if monolithic or separable program should be built. Defaults to false |
| **/ |
| void Program::Init(const std::string& compute_shader, const std::string& fragment_shader, |
| const std::string& geometry_shader, const std::string& tessellation_control_shader, |
| const std::string& tessellation_evaluation_shader, const std::string& vertex_shader, |
| bool is_separable) |
| { |
| NameVector captured_varying; |
| |
| Init(compute_shader, fragment_shader, geometry_shader, tessellation_control_shader, tessellation_evaluation_shader, |
| vertex_shader, captured_varying, true, is_separable); |
| } |
| |
| /** Release program instance |
| * |
| **/ |
| void Program::Release() |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| if (m_invalid_id != m_id) |
| { |
| Use(gl, m_invalid_id); |
| |
| gl.deleteProgram(m_id); |
| m_id = m_invalid_id; |
| } |
| |
| m_compute.Release(); |
| m_fragment.Release(); |
| m_geometry.Release(); |
| m_tess_ctrl.Release(); |
| m_tess_eval.Release(); |
| m_vertex.Release(); |
| } |
| |
| /** Get <pname> for a set of active uniforms |
| * |
| * @param count Number of indices |
| * @param indices Indices of uniforms |
| * @param pname Queired pname |
| * @param params Array that will be filled with values of parameters |
| **/ |
| void Program::GetActiveUniformsiv(GLsizei count, const GLuint* indices, GLenum pname, GLint* params) const |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| GetActiveUniformsiv(gl, m_id, count, indices, pname, params); |
| } |
| |
| /** Get location of attribute |
| * |
| * @param name Name of attribute |
| * |
| * @return Result of query |
| **/ |
| glw::GLint Program::GetAttribLocation(const std::string& name) const |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| return GetAttribLocation(gl, m_id, name); |
| } |
| |
| /** Query resource |
| * |
| * @param interface Interface to be queried |
| * @param index Index of resource |
| * @param property Property to be queried |
| * @param buf_size Size of <params> buffer |
| * @param params Results of query |
| **/ |
| void Program::GetResource(GLenum interface, GLuint index, GLenum property, GLsizei buf_size, GLint* params) const |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| GetResource(gl, m_id, interface, index, property, buf_size, params); |
| } |
| |
| /** Query for index of resource |
| * |
| * @param name Name of resource |
| * @param interface Interface to be queried |
| * |
| * @return Result of query |
| **/ |
| glw::GLuint Program::GetResourceIndex(const std::string& name, GLenum interface) const |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| return GetResourceIndex(gl, m_id, name, interface); |
| } |
| |
| /** Get indices for a set of uniforms |
| * |
| * @param count Count number of uniforms |
| * @param names Names of uniforms |
| * @param indices Buffer that will be filled with indices |
| **/ |
| void Program::GetUniformIndices(GLsizei count, const GLchar** names, GLuint* indices) const |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| GetUniformIndices(gl, m_id, count, names, indices); |
| } |
| |
| /** Get uniform location |
| * |
| * @param name Name of uniform |
| * |
| * @return Results of query |
| **/ |
| glw::GLint Program::GetUniformLocation(const std::string& name) const |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| return GetUniformLocation(gl, m_id, name); |
| } |
| |
| /** Set program as active |
| * |
| **/ |
| void Program::Use() const |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| Use(gl, m_id); |
| } |
| |
| /** Attach shader to program |
| * |
| * @param gl GL functions |
| * @param program_id Id of program |
| * @param shader_id Id of shader |
| **/ |
| void Program::Attach(const Functions& gl, GLuint program_id, GLuint shader_id) |
| { |
| /* Sanity checks */ |
| if ((m_invalid_id == program_id) || (Shader::m_invalid_id == shader_id)) |
| { |
| return; |
| } |
| |
| gl.attachShader(program_id, shader_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "AttachShader"); |
| } |
| |
| /** Set up captured varyings |
| * |
| * @param gl GL functions |
| * @param id Id of program |
| * @param captured_varyings Vector of varyings |
| * @param capture_interleaved Selects if interleaved or separate mode should be used |
| **/ |
| void Program::Capture(const Functions& gl, GLuint id, const NameVector& captured_varyings, bool capture_interleaved) |
| { |
| const size_t n_varyings = captured_varyings.size(); |
| |
| if (0 == n_varyings) |
| { |
| /* empty list, skip */ |
| return; |
| } |
| |
| std::vector<const GLchar*> varying_names; |
| varying_names.resize(n_varyings); |
| |
| for (size_t i = 0; i < n_varyings; ++i) |
| { |
| varying_names[i] = captured_varyings[i].c_str(); |
| } |
| |
| GLenum mode = 0; |
| if (true == capture_interleaved) |
| { |
| mode = GL_INTERLEAVED_ATTRIBS; |
| } |
| else |
| { |
| mode = GL_SEPARATE_ATTRIBS; |
| } |
| |
| gl.transformFeedbackVaryings(id, static_cast<GLsizei>(n_varyings), &varying_names[0], mode); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "TransformFeedbackVaryings"); |
| } |
| |
| /** Create program instance |
| * |
| * @param gl GL functions |
| * @param out_id Id of program |
| **/ |
| void Program::Create(const Functions& gl, GLuint& out_id) |
| { |
| const GLuint id = gl.createProgram(); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "CreateProgram"); |
| |
| if (m_invalid_id == id) |
| { |
| TCU_FAIL("Failed to create program"); |
| } |
| |
| out_id = id; |
| } |
| |
| /** Get <pname> for a set of active uniforms |
| * |
| * @param gl Functions |
| * @param program_id Id of program |
| * @param count Number of indices |
| * @param indices Indices of uniforms |
| * @param pname Queired pname |
| * @param params Array that will be filled with values of parameters |
| **/ |
| void Program::GetActiveUniformsiv(const Functions& gl, GLuint program_id, GLsizei count, const GLuint* indices, |
| GLenum pname, GLint* params) |
| { |
| gl.getActiveUniformsiv(program_id, count, indices, pname, params); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "GetActiveUniformsiv"); |
| } |
| |
| /** Get indices for a set of uniforms |
| * |
| * @param gl Functions |
| * @param program_id Id of program |
| * @param count Count number of uniforms |
| * @param names Names of uniforms |
| * @param indices Buffer that will be filled with indices |
| **/ |
| void Program::GetUniformIndices(const Functions& gl, GLuint program_id, GLsizei count, const GLchar** names, |
| GLuint* indices) |
| { |
| gl.getUniformIndices(program_id, count, names, indices); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "GetUniformIndices"); |
| } |
| |
| /** Link program |
| * |
| * @param gl GL functions |
| * @param id Id of program |
| **/ |
| void Program::Link(const Functions& gl, GLuint id) |
| { |
| GLint status = GL_FALSE; |
| |
| gl.linkProgram(id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "LinkProgram"); |
| |
| /* Get link status */ |
| gl.getProgramiv(id, GL_LINK_STATUS, &status); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramiv"); |
| |
| /* Log link error */ |
| if (GL_TRUE != status) |
| { |
| glw::GLint length = 0; |
| std::string message; |
| |
| /* Get error log length */ |
| gl.getProgramiv(id, GL_INFO_LOG_LENGTH, &length); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramiv"); |
| |
| message.resize(length, 0); |
| |
| /* Get error log */ |
| gl.getProgramInfoLog(id, length, 0, &message[0]); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramInfoLog"); |
| |
| throw LinkageException(message.c_str()); |
| } |
| } |
| |
| /** Set generic uniform |
| * |
| * @param gl Functions |
| * @param type Type of uniform |
| * @param count Length of array |
| * @param location Location of uniform |
| * @param data Data that will be used |
| **/ |
| void Program::Uniform(const Functions& gl, const Type& type, GLsizei count, GLint location, const GLvoid* data) |
| { |
| if (-1 == location) |
| { |
| TCU_FAIL("Uniform is inactive"); |
| } |
| |
| switch (type.m_basic_type) |
| { |
| case Type::Double: |
| if (1 == type.m_n_columns) |
| { |
| getUniformNdv(gl, type.m_n_rows)(location, count, (const GLdouble*)data); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "UniformNdv"); |
| } |
| else |
| { |
| getUniformMatrixNdv(gl, type.m_n_columns, type.m_n_rows)(location, count, false, (const GLdouble*)data); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "UniformMatrixNdv"); |
| } |
| break; |
| case Type::Float: |
| if (1 == type.m_n_columns) |
| { |
| getUniformNfv(gl, type.m_n_rows)(location, count, (const GLfloat*)data); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "UniformNfv"); |
| } |
| else |
| { |
| getUniformMatrixNfv(gl, type.m_n_columns, type.m_n_rows)(location, count, false, (const GLfloat*)data); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "UniformMatrixNfv"); |
| } |
| break; |
| case Type::Int: |
| getUniformNiv(gl, type.m_n_rows)(location, count, (const GLint*)data); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "UniformNiv"); |
| break; |
| case Type::Uint: |
| getUniformNuiv(gl, type.m_n_rows)(location, count, (const GLuint*)data); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "UniformNuiv"); |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| } |
| |
| /** Use program |
| * |
| * @param gl GL functions |
| * @param id Id of program |
| **/ |
| void Program::Use(const Functions& gl, GLuint id) |
| { |
| gl.useProgram(id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "UseProgram"); |
| } |
| |
| /** Get location of attribute |
| * |
| * @param gl GL functions |
| * @param id Id of program |
| * @param name Name of attribute |
| * |
| * @return Location of attribute |
| **/ |
| GLint Program::GetAttribLocation(const Functions& gl, GLuint id, const std::string& name) |
| { |
| GLint location = gl.getAttribLocation(id, name.c_str()); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "GetAttribLocation"); |
| |
| return location; |
| } |
| |
| /** Query resource |
| * |
| * @param gl GL functions |
| * @param id Id of program |
| * @param interface Interface to be queried |
| * @param index Index of resource |
| * @param property Property to be queried |
| * @param buf_size Size of <params> buffer |
| * @param params Results of query |
| **/ |
| void Program::GetResource(const Functions& gl, GLuint id, GLenum interface, GLuint index, GLenum property, |
| GLsizei buf_size, GLint* params) |
| { |
| gl.getProgramResourceiv(id, interface, index, 1 /* propCount */, &property, buf_size /* bufSize */, 0 /* length */, |
| params); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramResourceiv"); |
| } |
| |
| /** Get index of resource |
| * |
| * @param gl GL functions |
| * @param id Id of program |
| * @param name Name of resource |
| * @param interface Program interface to queried |
| * |
| * @return Location of attribute |
| **/ |
| GLuint Program::GetResourceIndex(const Functions& gl, GLuint id, const std::string& name, GLenum interface) |
| { |
| GLuint index = gl.getProgramResourceIndex(id, interface, name.c_str()); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramResourceIndex"); |
| |
| return index; |
| } |
| |
| /** Get location of attribute |
| * |
| * @param gl GL functions |
| * @param id Id of program |
| * @param name Name of attribute |
| * |
| * @return Location of uniform |
| **/ |
| GLint Program::GetUniformLocation(const Functions& gl, GLuint id, const std::string& name) |
| { |
| GLint location = gl.getUniformLocation(id, name.c_str()); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "GetUniformLocation"); |
| |
| return location; |
| } |
| |
| /** Constructor |
| * |
| * @param error_message Error message |
| * @param compute_shader Source code for compute stage |
| * @param fragment_shader Source code for fragment stage |
| * @param geometry_shader Source code for geometry stage |
| * @param tess_ctrl_shader Source code for tessellation control stage |
| * @param tess_eval_shader Source code for tessellation evaluation stage |
| * @param vertex_shader Source code for vertex stage |
| **/ |
| Program::BuildException::BuildException(const glw::GLchar* error_message, const std::string compute_shader, |
| const std::string fragment_shader, const std::string geometry_shader, |
| const std::string tess_ctrl_shader, const std::string tess_eval_shader, |
| const std::string vertex_shader) |
| : m_error_message(error_message) |
| , m_compute_shader(compute_shader) |
| , m_fragment_shader(fragment_shader) |
| , m_geometry_shader(geometry_shader) |
| , m_tess_ctrl_shader(tess_ctrl_shader) |
| , m_tess_eval_shader(tess_eval_shader) |
| , m_vertex_shader(vertex_shader) |
| { |
| } |
| |
| /** Overwrites std::exception::what method |
| * |
| * @return Message compossed from error message and shader sources |
| **/ |
| const char* Program::BuildException::what() const throw() |
| { |
| return "Failed to link program"; |
| } |
| |
| /** Logs error message and shader sources **/ |
| void Program::BuildException::log(deqp::Context& context) const |
| { |
| context.getTestContext().getLog() << tcu::TestLog::Message << "Link failure: " << m_error_message |
| << tcu::TestLog::EndMessage; |
| |
| Shader::LogSource(context, m_vertex_shader, Shader::VERTEX); |
| Shader::LogSource(context, m_tess_ctrl_shader, Shader::TESS_CTRL); |
| Shader::LogSource(context, m_tess_eval_shader, Shader::TESS_EVAL); |
| Shader::LogSource(context, m_geometry_shader, Shader::GEOMETRY); |
| Shader::LogSource(context, m_fragment_shader, Shader::FRAGMENT); |
| Shader::LogSource(context, m_compute_shader, Shader::COMPUTE); |
| } |
| |
| /** Constructor |
| * |
| * @param message Linking error message |
| **/ |
| Program::LinkageException::LinkageException(const glw::GLchar* message) : m_error_message(message) |
| { |
| /* Nothing to be done */ |
| } |
| |
| /** Returns error messages |
| * |
| * @return Linking error message |
| **/ |
| const char* Program::LinkageException::what() const throw() |
| { |
| return m_error_message.c_str(); |
| } |
| |
| /* Texture constants */ |
| const GLuint Texture::m_invalid_id = -1; |
| |
| /** Constructor. |
| * |
| * @param context CTS context. |
| **/ |
| Texture::Texture(deqp::Context& context) : m_id(m_invalid_id), m_context(context), m_type(TEX_2D) |
| { |
| /* Nothing to done here */ |
| } |
| |
| /** Destructor |
| * |
| **/ |
| Texture::~Texture() |
| { |
| Release(); |
| } |
| |
| /** Initialize texture instance |
| * |
| * @param tex_type Type of texture |
| * @param width Width of texture |
| * @param height Height of texture |
| * @param depth Depth of texture |
| * @param internal_format Internal format of texture |
| * @param format Format of texture data |
| * @param type Type of texture data |
| * @param data Texture data |
| **/ |
| void Texture::Init(TYPES tex_type, GLuint width, GLuint height, GLuint depth, GLenum internal_format, GLenum format, |
| GLenum type, GLvoid* data) |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Delete previous texture */ |
| Release(); |
| |
| m_type = tex_type; |
| |
| /* Generate, bind, allocate storage and upload data */ |
| Generate(gl, m_id); |
| Bind(gl, m_id, tex_type); |
| Storage(gl, tex_type, width, height, depth, internal_format); |
| Update(gl, tex_type, width, height, depth, format, type, data); |
| } |
| |
| /** Initialize buffer texture |
| * |
| * @param internal_format Internal format of texture |
| * @param buffer_id Id of buffer that will be used as data source |
| **/ |
| void Texture::Init(GLenum internal_format, GLuint buffer_id) |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Delete previous texture */ |
| Release(); |
| |
| m_type = TEX_BUFFER; |
| |
| /* Generate, bind and attach buffer */ |
| Generate(gl, m_id); |
| Bind(gl, m_id, TEX_BUFFER); |
| TexBuffer(gl, buffer_id, internal_format); |
| } |
| |
| /** Release texture instance |
| * |
| **/ |
| void Texture::Release() |
| { |
| if (m_invalid_id != m_id) |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| gl.deleteTextures(1, &m_id); |
| m_id = m_invalid_id; |
| } |
| } |
| |
| /** Bind texture to its target |
| * |
| **/ |
| void Texture::Bind() const |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| Bind(gl, m_id, m_type); |
| } |
| |
| /** Get texture data |
| * |
| * @param format Format of data |
| * @param type Type of data |
| * @param out_data Buffer for data |
| **/ |
| void Texture::Get(GLenum format, GLenum type, GLvoid* out_data) const |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| Bind(gl, m_id, m_type); |
| Get(gl, m_type, format, type, out_data); |
| } |
| |
| /** Bind texture to target |
| * |
| * @param gl GL functions |
| * @param id Id of texture |
| * @param tex_type Type of texture |
| **/ |
| void Texture::Bind(const Functions& gl, GLuint id, TYPES tex_type) |
| { |
| GLenum target = GetTargetGLenum(tex_type); |
| |
| gl.bindTexture(target, id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture"); |
| } |
| |
| /** Generate texture instance |
| * |
| * @param gl GL functions |
| * @param out_id Id of texture |
| **/ |
| void Texture::Generate(const Functions& gl, GLuint& out_id) |
| { |
| GLuint id = m_invalid_id; |
| |
| gl.genTextures(1, &id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "GenTextures"); |
| |
| if (m_invalid_id == id) |
| { |
| TCU_FAIL("Invalid id"); |
| } |
| |
| out_id = id; |
| } |
| |
| /** Get texture data |
| * |
| * @param gl GL functions |
| * @param format Format of data |
| * @param type Type of data |
| * @param out_data Buffer for data |
| **/ |
| void Texture::Get(const Functions& gl, TYPES tex_type, GLenum format, GLenum type, GLvoid* out_data) |
| { |
| GLenum target = GetTargetGLenum(tex_type); |
| |
| if (TEX_CUBE != tex_type) |
| { |
| gl.getTexImage(target, 0 /* level */, format, type, out_data); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "GetTexImage"); |
| } |
| else |
| { |
| GLint width; |
| GLint height; |
| |
| if ((GL_RGBA != format) && (GL_UNSIGNED_BYTE != type)) |
| { |
| TCU_FAIL("Not implemented"); |
| } |
| |
| GLuint texel_size = 4; |
| |
| gl.getTexLevelParameteriv(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0 /* level */, GL_TEXTURE_WIDTH, &width); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "GetTexLevelParameteriv"); |
| |
| gl.getTexLevelParameteriv(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0 /* level */, GL_TEXTURE_HEIGHT, &height); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "GetTexLevelParameteriv"); |
| |
| const GLuint image_size = width * height * texel_size; |
| |
| gl.getTexImage(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0 /* level */, format, type, |
| (GLvoid*)((GLchar*)out_data + (image_size * 0))); |
| gl.getTexImage(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0 /* level */, format, type, |
| (GLvoid*)((GLchar*)out_data + (image_size * 1))); |
| gl.getTexImage(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0 /* level */, format, type, |
| (GLvoid*)((GLchar*)out_data + (image_size * 2))); |
| gl.getTexImage(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0 /* level */, format, type, |
| (GLvoid*)((GLchar*)out_data + (image_size * 3))); |
| gl.getTexImage(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0 /* level */, format, type, |
| (GLvoid*)((GLchar*)out_data + (image_size * 4))); |
| gl.getTexImage(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0 /* level */, format, type, |
| (GLvoid*)((GLchar*)out_data + (image_size * 5))); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "GetTexImage"); |
| } |
| } |
| |
| /** Allocate storage for texture |
| * |
| * @param gl GL functions |
| * @param tex_type Type of texture |
| * @param width Width of texture |
| * @param height Height of texture |
| * @param depth Depth of texture |
| * @param internal_format Internal format of texture |
| **/ |
| void Texture::Storage(const Functions& gl, TYPES tex_type, GLuint width, GLuint height, GLuint depth, |
| GLenum internal_format) |
| { |
| static const GLuint levels = 1; |
| |
| GLenum target = GetTargetGLenum(tex_type); |
| |
| switch (tex_type) |
| { |
| case TEX_1D: |
| gl.texStorage1D(target, levels, internal_format, width); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "TexStorage1D"); |
| break; |
| case TEX_2D: |
| case TEX_1D_ARRAY: |
| case TEX_2D_RECT: |
| case TEX_CUBE: |
| gl.texStorage2D(target, levels, internal_format, width, height); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "TexStorage2D"); |
| break; |
| case TEX_3D: |
| case TEX_2D_ARRAY: |
| gl.texStorage3D(target, levels, internal_format, width, height, depth); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "TexStorage3D"); |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| break; |
| } |
| } |
| |
| /** Attach buffer as source of texture buffer data |
| * |
| * @param gl GL functions |
| * @param internal_format Internal format of texture |
| * @param buffer_id Id of buffer that will be used as data source |
| **/ |
| void Texture::TexBuffer(const Functions& gl, GLenum internal_format, GLuint& buffer_id) |
| { |
| gl.texBuffer(GL_TEXTURE_BUFFER, internal_format, buffer_id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "TexBuffer"); |
| } |
| |
| /** Update contents of texture |
| * |
| * @param gl GL functions |
| * @param tex_type Type of texture |
| * @param width Width of texture |
| * @param height Height of texture |
| * @param format Format of data |
| * @param type Type of data |
| * @param data Buffer with image data |
| **/ |
| void Texture::Update(const Functions& gl, TYPES tex_type, GLuint width, GLuint height, GLuint depth, GLenum format, |
| GLenum type, GLvoid* data) |
| { |
| static const GLuint level = 0; |
| |
| GLenum target = GetTargetGLenum(tex_type); |
| |
| switch (tex_type) |
| { |
| case TEX_1D: |
| gl.texSubImage1D(target, level, 0 /* x */, width, format, type, data); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "TexStorage1D"); |
| break; |
| case TEX_2D: |
| case TEX_1D_ARRAY: |
| case TEX_2D_RECT: |
| gl.texSubImage2D(target, level, 0 /* x */, 0 /* y */, width, height, format, type, data); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "TexStorage2D"); |
| break; |
| case TEX_CUBE: |
| gl.texSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, level, 0 /* x */, 0 /* y */, width, height, format, type, |
| data); |
| gl.texSubImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, level, 0 /* x */, 0 /* y */, width, height, format, type, |
| data); |
| gl.texSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, level, 0 /* x */, 0 /* y */, width, height, format, type, |
| data); |
| gl.texSubImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, level, 0 /* x */, 0 /* y */, width, height, format, type, |
| data); |
| gl.texSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, level, 0 /* x */, 0 /* y */, width, height, format, type, |
| data); |
| gl.texSubImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, level, 0 /* x */, 0 /* y */, width, height, format, type, |
| data); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "TexStorage2D"); |
| break; |
| case TEX_3D: |
| case TEX_2D_ARRAY: |
| gl.texSubImage3D(target, level, 0 /* x */, 0 /* y */, 0 /* z */, width, height, depth, format, type, data); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "TexStorage3D"); |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| break; |
| } |
| } |
| |
| /** Get target for given texture type |
| * |
| * @param type Type of texture |
| * |
| * @return Target |
| **/ |
| GLenum Texture::GetTargetGLenum(TYPES type) |
| { |
| GLenum result = 0; |
| |
| switch (type) |
| { |
| case TEX_BUFFER: |
| result = GL_TEXTURE_BUFFER; |
| break; |
| case TEX_2D: |
| result = GL_TEXTURE_2D; |
| break; |
| case TEX_2D_RECT: |
| result = GL_TEXTURE_RECTANGLE; |
| break; |
| case TEX_2D_ARRAY: |
| result = GL_TEXTURE_2D_ARRAY; |
| break; |
| case TEX_3D: |
| result = GL_TEXTURE_3D; |
| break; |
| case TEX_CUBE: |
| result = GL_TEXTURE_CUBE_MAP; |
| break; |
| case TEX_1D: |
| result = GL_TEXTURE_1D; |
| break; |
| case TEX_1D_ARRAY: |
| result = GL_TEXTURE_1D_ARRAY; |
| break; |
| } |
| |
| return result; |
| } |
| |
| /* VertexArray constants */ |
| const GLuint VertexArray::m_invalid_id = -1; |
| |
| /** Constructor. |
| * |
| * @param context CTS context. |
| **/ |
| VertexArray::VertexArray(deqp::Context& context) : m_id(m_invalid_id), m_context(context) |
| { |
| } |
| |
| /** Destructor |
| * |
| **/ |
| VertexArray::~VertexArray() |
| { |
| Release(); |
| } |
| |
| /** Initialize vertex array instance |
| * |
| **/ |
| void VertexArray::Init() |
| { |
| /* Delete previous instance */ |
| Release(); |
| |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| Generate(gl, m_id); |
| } |
| |
| /** Release vertex array object instance |
| * |
| **/ |
| void VertexArray::Release() |
| { |
| if (m_invalid_id != m_id) |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| gl.deleteVertexArrays(1, &m_id); |
| |
| m_id = m_invalid_id; |
| } |
| } |
| |
| /** Set attribute in VAO |
| * |
| * @param index Index of attribute |
| * @param type Type of attribute |
| * @param n_array_elements Arary length |
| * @param normalized Selects if values should be normalized |
| * @param stride Stride |
| * @param pointer Pointer to data, or offset in buffer |
| **/ |
| void VertexArray::Attribute(GLuint index, const Type& type, GLuint n_array_elements, GLboolean normalized, |
| GLsizei stride, const GLvoid* pointer) |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| AttribPointer(gl, index, type, n_array_elements, normalized, stride, pointer); |
| Enable(gl, index, type, n_array_elements); |
| } |
| |
| /** Binds Vertex array object |
| * |
| **/ |
| void VertexArray::Bind() |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| Bind(gl, m_id); |
| } |
| |
| /** Set attribute in VAO |
| * |
| * @param gl Functions |
| * @param index Index of attribute |
| * @param type Type of attribute |
| * @param n_array_elements Arary length |
| * @param normalized Selects if values should be normalized |
| * @param stride Stride |
| * @param pointer Pointer to data, or offset in buffer |
| **/ |
| void VertexArray::AttribPointer(const Functions& gl, GLuint index, const Type& type, GLuint n_array_elements, |
| GLboolean normalized, GLsizei stride, const GLvoid* pointer) |
| { |
| const GLuint basic_type_size = Type::GetTypeSize(type.m_basic_type); |
| const GLint size = (GLint)type.m_n_rows; |
| const GLuint column_size = (GLuint)size * basic_type_size; |
| const GLenum gl_type = Type::GetTypeGLenum(type.m_basic_type); |
| |
| GLuint offset = 0; |
| |
| /* If attribute is not an array */ |
| if (0 == n_array_elements) |
| { |
| n_array_elements = 1; |
| } |
| |
| /* For each element in array */ |
| for (GLuint element = 0; element < n_array_elements; ++element) |
| { |
| /* For each column in matrix */ |
| for (GLuint column = 1; column <= type.m_n_columns; ++column) |
| { |
| /* Calculate offset */ |
| const GLvoid* ptr = (GLubyte*)pointer + offset; |
| |
| /* Set up attribute */ |
| switch (type.m_basic_type) |
| { |
| case Type::Float: |
| gl.vertexAttribPointer(index, size, gl_type, normalized, stride, ptr); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "VertexAttribPointer"); |
| break; |
| case Type::Int: |
| case Type::Uint: |
| gl.vertexAttribIPointer(index, size, gl_type, stride, ptr); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "VertexAttribIPointer"); |
| break; |
| case Type::Double: |
| gl.vertexAttribLPointer(index, size, gl_type, stride, ptr); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "VertexAttribLPointer"); |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| /* Next location */ |
| offset += column_size; |
| index += 1; |
| } |
| } |
| } |
| |
| /** Binds Vertex array object |
| * |
| * @param gl GL functions |
| * @param id ID of vertex array object |
| **/ |
| void VertexArray::Bind(const glw::Functions& gl, glw::GLuint id) |
| { |
| gl.bindVertexArray(id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "BindVertexArray"); |
| } |
| |
| /** Disable attribute in VAO |
| * |
| * @param gl Functions |
| * @param index Index of attribute |
| * @param type Type of attribute |
| * @param n_array_elements Arary length |
| **/ |
| void VertexArray::Disable(const Functions& gl, GLuint index, const Type& type, GLuint n_array_elements) |
| { |
| /* If attribute is not an array */ |
| if (0 == n_array_elements) |
| { |
| n_array_elements = 1; |
| } |
| |
| /* For each element in array */ |
| for (GLuint element = 0; element < n_array_elements; ++element) |
| { |
| /* For each column in matrix */ |
| for (GLuint column = 1; column <= type.m_n_columns; ++column) |
| { |
| /* Enable attribute array */ |
| gl.disableVertexAttribArray(index); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "DisableVertexAttribArray"); |
| |
| /* Next location */ |
| index += 1; |
| } |
| } |
| } |
| |
| /** Set divisor for attribute |
| * |
| * @param gl Functions |
| * @param index Index of attribute |
| * @param divisor New divisor value |
| **/ |
| void VertexArray::Divisor(const Functions& gl, GLuint index, GLuint divisor) |
| { |
| gl.vertexAttribDivisor(index, divisor); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "VertexAttribDivisor"); |
| } |
| |
| /** Enables attribute in VAO |
| * |
| * @param gl Functions |
| * @param index Index of attribute |
| * @param type Type of attribute |
| * @param n_array_elements Arary length |
| **/ |
| void VertexArray::Enable(const Functions& gl, GLuint index, const Type& type, GLuint n_array_elements) |
| { |
| /* If attribute is not an array */ |
| if (0 == n_array_elements) |
| { |
| n_array_elements = 1; |
| } |
| |
| /* For each element in array */ |
| for (GLuint element = 0; element < n_array_elements; ++element) |
| { |
| /* For each column in matrix */ |
| for (GLuint column = 1; column <= type.m_n_columns; ++column) |
| { |
| /* Enable attribute array */ |
| gl.enableVertexAttribArray(index); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "EnableVertexAttribArray"); |
| |
| /* Next location */ |
| index += 1; |
| } |
| } |
| } |
| |
| /** Generates Vertex array object |
| * |
| * @param gl GL functions |
| * @param out_id ID of vertex array object |
| **/ |
| void VertexArray::Generate(const glw::Functions& gl, glw::GLuint& out_id) |
| { |
| GLuint id = m_invalid_id; |
| |
| gl.genVertexArrays(1, &id); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "GenVertexArrays"); |
| |
| if (m_invalid_id == id) |
| { |
| TCU_FAIL("Invalid id"); |
| } |
| |
| out_id = id; |
| } |
| |
| /* Constatns used by Variable */ |
| const GLint Variable::m_automatic_location = -1; |
| |
| /** Copy constructor |
| * |
| **/ |
| Variable::Variable(const Variable& var) |
| : m_data(var.m_data) |
| , m_data_size(var.m_data_size) |
| , m_descriptor(var.m_descriptor.m_name.c_str(), var.m_descriptor.m_qualifiers.c_str(), |
| var.m_descriptor.m_expected_component, var.m_descriptor.m_expected_location, |
| var.m_descriptor.m_builtin, var.m_descriptor.m_normalized, var.m_descriptor.m_n_array_elements, |
| var.m_descriptor.m_expected_stride_of_element, var.m_descriptor.m_offset) |
| , m_storage(var.m_storage) |
| { |
| m_descriptor.m_type = var.m_descriptor.m_type; |
| |
| if (BUILTIN != var.m_descriptor.m_type) |
| { |
| m_descriptor.m_interface = var.m_descriptor.m_interface; |
| } |
| } |
| |
| /** Get code that defines variable |
| * |
| * @param flavour Provides info if variable is array or not |
| * |
| * @return String with code |
| **/ |
| std::string Variable::GetDefinition(FLAVOUR flavour) const |
| { |
| return m_descriptor.GetDefinition(flavour, m_storage); |
| } |
| |
| /** Calcualtes stride of variable |
| * |
| * @return Calculated value |
| **/ |
| GLuint Variable::GetStride() const |
| { |
| GLint variable_stride = 0; |
| |
| if (0 == m_descriptor.m_n_array_elements) |
| { |
| variable_stride = m_descriptor.m_expected_stride_of_element; |
| } |
| else |
| { |
| variable_stride = m_descriptor.m_expected_stride_of_element * m_descriptor.m_n_array_elements; |
| } |
| |
| return variable_stride; |
| } |
| |
| /** Check if variable is block |
| * |
| * @return true if variable type is block, false otherwise |
| **/ |
| bool Variable::IsBlock() const |
| { |
| if (BUILTIN == m_descriptor.m_type) |
| { |
| return false; |
| } |
| |
| const Interface* interface = m_descriptor.m_interface; |
| if (0 == interface) |
| { |
| TCU_FAIL("Nullptr"); |
| } |
| |
| return (Interface::BLOCK == interface->m_type); |
| } |
| |
| /** Check if variable is struct |
| * |
| * @return true if variable type is struct, false otherwise |
| **/ |
| bool Variable::IsStruct() const |
| { |
| if (BUILTIN == m_descriptor.m_type) |
| { |
| return false; |
| } |
| |
| const Interface* interface = m_descriptor.m_interface; |
| if (0 == interface) |
| { |
| TCU_FAIL("Nullptr"); |
| } |
| |
| return (Interface::STRUCT == interface->m_type); |
| } |
| /** Get code that reference variable |
| * |
| * @param parent_name Name of parent |
| * @param variable Descriptor of variable |
| * @param flavour Provides info about how variable should be referenced |
| * @param array_index Index of array, ignored when variable is not array |
| * |
| * @return String with code |
| **/ |
| std::string Variable::GetReference(const std::string& parent_name, const Descriptor& variable, FLAVOUR flavour, |
| GLuint array_index) |
| { |
| std::string name; |
| |
| /* Prepare name */ |
| if (false == parent_name.empty()) |
| { |
| name = parent_name; |
| name.append("."); |
| name.append(variable.m_name); |
| } |
| else |
| { |
| name = variable.m_name; |
| } |
| |
| /* */ |
| switch (flavour) |
| { |
| case Utils::Variable::BASIC: |
| break; |
| |
| case Utils::Variable::ARRAY: |
| name.append("[0]"); |
| break; |
| |
| case Utils::Variable::INDEXED_BY_INVOCATION_ID: |
| name.append("[gl_InvocationID]"); |
| break; |
| } |
| |
| /* Assumption that both variables have same lengths */ |
| if (0 != variable.m_n_array_elements) |
| { |
| GLchar buffer[16]; |
| sprintf(buffer, "%d", array_index); |
| name.append("["); |
| name.append(buffer); |
| name.append("]"); |
| } |
| |
| return name; |
| } |
| |
| /** Get "flavour" of varying |
| * |
| * @param stage Stage of shader |
| * @param direction Selects if varying is in or out |
| * |
| * @return Flavour |
| **/ |
| Variable::FLAVOUR Variable::GetFlavour(Shader::STAGES stage, VARYING_DIRECTION direction) |
| { |
| FLAVOUR result = BASIC; |
| |
| switch (stage) |
| { |
| case Shader::GEOMETRY: |
| case Shader::TESS_EVAL: |
| if (INPUT == direction) |
| { |
| result = ARRAY; |
| } |
| break; |
| case Shader::TESS_CTRL: |
| result = INDEXED_BY_INVOCATION_ID; |
| break; |
| default: |
| break; |
| } |
| |
| return result; |
| } |
| |
| /** Constructor, for built-in types |
| * |
| * @param name Name |
| * @param qualifiers Qualifiers |
| * @param expected_component Expected component of variable |
| * @param expected_location Expected location |
| * @param type Type |
| * @param normalized Selects if data should be normalized |
| * @param n_array_elements Length of array |
| * @param expected_stride_of_element Expected stride of element |
| * @param offset Offset |
| **/ |
| Variable::Descriptor::Descriptor(const GLchar* name, const GLchar* qualifiers, GLint expected_component, |
| GLint expected_location, const Type& type, GLboolean normalized, |
| GLuint n_array_elements, GLint expected_stride_of_element, GLuint offset) |
| : m_expected_component(expected_component) |
| , m_expected_location(expected_location) |
| , m_expected_stride_of_element(expected_stride_of_element) |
| , m_n_array_elements(n_array_elements) |
| , m_name(name) |
| , m_normalized(normalized) |
| , m_offset(offset) |
| , m_qualifiers(qualifiers) |
| , m_type(BUILTIN) |
| , m_builtin(type) |
| { |
| } |
| |
| /** Constructor, for interface types |
| * |
| * @param name Name |
| * @param qualifiers Qualifiers |
| * @param expected_component Expected component of variable |
| * @param expected_location Expected location |
| * @param interface Interface of variable |
| * @param n_array_elements Length of array |
| * @param expected_stride_of_element Expected stride of element |
| * @param offset Offset |
| **/ |
| Variable::Descriptor::Descriptor(const GLchar* name, const GLchar* qualifiers, GLint expected_componenet, |
| GLint expected_location, Interface* interface, GLuint n_array_elements, |
| GLint expected_stride_of_element, GLuint offset) |
| : m_expected_component(expected_componenet) |
| , m_expected_location(expected_location) |
| , m_expected_stride_of_element(expected_stride_of_element) |
| , m_n_array_elements(n_array_elements) |
| , m_name(name) |
| , m_normalized(GL_FALSE) |
| , m_offset(offset) |
| , m_qualifiers(qualifiers) |
| , m_type(INTERFACE) |
| , m_interface(interface) |
| { |
| } |
| |
| /** Get definition of variable |
| * |
| * @param flavour Flavour of variable |
| * @param storage Storage used for variable |
| * |
| * @return code with defintion |
| **/ |
| std::string Variable::Descriptor::GetDefinition(FLAVOUR flavour, STORAGE storage) const |
| { |
| static const GLchar* basic_template = "QUALIFIERS STORAGETYPE NAMEARRAY;"; |
| static const GLchar* array_template = "QUALIFIERS STORAGETYPE NAME[]ARRAY;"; |
| const GLchar* storage_str = 0; |
| |
| std::string definition; |
| size_t position = 0; |
| |
| /* Select definition template */ |
| switch (flavour) |
| { |
| case BASIC: |
| definition = basic_template; |
| break; |
| case ARRAY: |
| case INDEXED_BY_INVOCATION_ID: |
| definition = array_template; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| break; |
| } |
| |
| if (BUILTIN != m_type) |
| { |
| if (0 == m_interface) |
| { |
| TCU_FAIL("Nullptr"); |
| } |
| } |
| |
| /* Qualifiers */ |
| if (true == m_qualifiers.empty()) |
| { |
| replaceToken("QUALIFIERS ", position, "", definition); |
| } |
| else |
| { |
| replaceToken("QUALIFIERS", position, m_qualifiers.c_str(), definition); |
| } |
| |
| // According to spec: int, uint, and double type must always be declared with flat qualifier |
| bool flat_qualifier = false; |
| if (m_type != BUILTIN && m_interface != NULL) |
| { |
| if (m_interface->m_members[0].m_builtin.m_basic_type == Utils::Type::Int || |
| m_interface->m_members[0].m_builtin.m_basic_type == Utils::Type::Uint || |
| m_interface->m_members[0].m_builtin.m_basic_type == Utils::Type::Double) |
| { |
| flat_qualifier = true; |
| } |
| } |
| /* Storage */ |
| switch (storage) |
| { |
| case VARYING_INPUT: |
| storage_str = flat_qualifier ? "flat in " : "in "; |
| break; |
| case VARYING_OUTPUT: |
| storage_str = "out "; |
| break; |
| case UNIFORM: |
| storage_str = "uniform "; |
| break; |
| case SSB: |
| storage_str = "buffer "; |
| break; |
| case MEMBER: |
| storage_str = ""; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| break; |
| } |
| |
| replaceToken("STORAGE", position, storage_str, definition); |
| |
| /* Type */ |
| if (BUILTIN == m_type) |
| { |
| replaceToken("TYPE", position, m_builtin.GetGLSLTypeName(), definition); |
| } |
| else |
| { |
| if (Interface::STRUCT == m_interface->m_type) |
| { |
| replaceToken("TYPE", position, m_interface->m_name.c_str(), definition); |
| } |
| else |
| { |
| const std::string& block_definition = m_interface->GetDefinition(); |
| |
| replaceToken("TYPE", position, block_definition.c_str(), definition); |
| } |
| } |
| |
| /* Name */ |
| replaceToken("NAME", position, m_name.c_str(), definition); |
| |
| /* Array size */ |
| if (0 == m_n_array_elements) |
| { |
| replaceToken("ARRAY", position, "", definition); |
| } |
| else |
| { |
| char buffer[16]; |
| sprintf(buffer, "[%d]", m_n_array_elements); |
| |
| replaceToken("ARRAY", position, buffer, definition); |
| } |
| |
| /* Done */ |
| return definition; |
| } |
| |
| /** Get definitions for variables collected in vector |
| * |
| * @param vector Collection of variables |
| * @param flavour Flavour of variables |
| * |
| * @return Code with definitions |
| **/ |
| std::string GetDefinitions(const Variable::PtrVector& vector, Variable::FLAVOUR flavour) |
| { |
| std::string list = Utils::g_list; |
| size_t position = 0; |
| |
| for (GLuint i = 0; i < vector.size(); ++i) |
| { |
| Utils::insertElementOfList(vector[i]->GetDefinition(flavour).c_str(), "\n", position, list); |
| } |
| |
| Utils::endList("", position, list); |
| |
| return list; |
| } |
| |
| /** Get definitions for interfaces collected in vector |
| * |
| * @param vector Collection of interfaces |
| * |
| * @return Code with definitions |
| **/ |
| std::string GetDefinitions(const Interface::PtrVector& vector) |
| { |
| std::string list = Utils::g_list; |
| size_t position = 0; |
| |
| for (GLuint i = 0; i < vector.size(); ++i) |
| { |
| Utils::insertElementOfList(vector[i]->GetDefinition().c_str(), "\n", position, list); |
| } |
| |
| Utils::endList("", position, list); |
| |
| return list; |
| } |
| |
| /** Constructor |
| * |
| * @param name Name |
| * @param type Type of interface |
| **/ |
| Interface::Interface(const GLchar* name, Interface::TYPE type) : m_name(name), m_type(type) |
| { |
| } |
| |
| /** Adds member to interface |
| * |
| * @param member Descriptor of new member |
| * |
| * @return Pointer to just created member |
| **/ |
| Variable::Descriptor* Interface::AddMember(const Variable::Descriptor& member) |
| { |
| m_members.push_back(member); |
| |
| return &m_members.back(); |
| } |
| |
| /** Get definition of interface |
| * |
| * @param Code with definition |
| **/ |
| std::string Interface::GetDefinition() const |
| { |
| std::string definition; |
| size_t position = 0; |
| |
| const GLchar* member_list = " MEMBER_DEFINITION\nMEMBER_LIST"; |
| |
| if (STRUCT == m_type) |
| { |
| definition = "struct NAME {\nMEMBER_LIST};"; |
| } |
| else |
| { |
| definition = "NAME {\nMEMBER_LIST}"; |
| } |
| |
| /* Name */ |
| replaceToken("NAME", position, m_name.c_str(), definition); |
| |
| /* Member list */ |
| for (GLuint i = 0; i < m_members.size(); ++i) |
| { |
| const size_t start_position = position; |
| const std::string& member_definition = m_members[i].GetDefinition(Variable::BASIC, Variable::MEMBER); |
| |
| /* Member list */ |
| replaceToken("MEMBER_LIST", position, member_list, definition); |
| |
| /* Move back position */ |
| position = start_position; |
| |
| /* Member definition */ |
| replaceToken("MEMBER_DEFINITION", position, member_definition.c_str(), definition); |
| } |
| |
| /* Remove last member list */ |
| replaceToken("MEMBER_LIST", position, "", definition); |
| |
| /* Done */ |
| return definition; |
| } |
| |
| /** Adds member of built-in type to interface |
| * |
| * @param name Name |
| * @param qualifiers Qualifiers |
| * @param expected_component Expected component of variable |
| * @param expected_location Expected location |
| * @param type Type |
| * @param normalized Selects if data should be normalized |
| * @param n_array_elements Length of array |
| * @param expected_stride_of_element Expected stride of element |
| * @param offset Offset |
| * |
| * @return Pointer to just created member |
| **/ |
| Variable::Descriptor* Interface::Member(const GLchar* name, const GLchar* qualifiers, GLint expected_component, |
| GLint expected_location, const Type& type, GLboolean normalized, |
| GLuint n_array_elements, GLint expected_stride_of_element, GLuint offset) |
| { |
| return AddMember(Variable::Descriptor(name, qualifiers, expected_component, expected_location, type, normalized, |
| n_array_elements, expected_stride_of_element, offset)); |
| } |
| |
| /** Adds member of interface type to interface |
| * |
| * @param name Name |
| * @param qualifiers Qualifiers |
| * @param expected_component Expected component of variable |
| * @param expected_location Expected location |
| * @param type Type |
| * @param normalized Selects if data should be normalized |
| * @param n_array_elements Length of array |
| * @param expected_stride_of_element Expected stride of element |
| * @param offset Offset |
| * |
| * @return Pointer to just created member |
| **/ |
| Variable::Descriptor* Interface::Member(const GLchar* name, const GLchar* qualifiers, GLint expected_component, |
| GLint expected_location, Interface* nterface, GLuint n_array_elements, |
| GLint expected_stride_of_element, GLuint offset) |
| { |
| return AddMember(Variable::Descriptor(name, qualifiers, expected_component, expected_location, nterface, |
| n_array_elements, expected_stride_of_element, offset)); |
| } |
| |
| /** Clears contents of vector of pointers |
| * |
| * @tparam T Type of elements |
| * |
| * @param vector Collection to be cleared |
| **/ |
| template <typename T> |
| void clearPtrVector(std::vector<T*>& vector) |
| { |
| for (size_t i = 0; i < vector.size(); ++i) |
| { |
| T* t = vector[i]; |
| |
| vector[i] = 0; |
| |
| if (0 != t) |
| { |
| delete t; |
| } |
| } |
| |
| vector.clear(); |
| } |
| |
| /** Constructor |
| * |
| * @param stage Stage described by that interface |
| **/ |
| ShaderInterface::ShaderInterface(Shader::STAGES stage) : m_stage(stage) |
| { |
| /* Nothing to be done */ |
| } |
| |
| /** Get definitions of globals |
| * |
| * @return Code with definitions |
| **/ |
| std::string ShaderInterface::GetDefinitionsGlobals() const |
| { |
| return m_globals; |
| } |
| |
| /** Get definitions of inputs |
| * |
| * @return Code with definitions |
| **/ |
| std::string ShaderInterface::GetDefinitionsInputs() const |
| { |
| Variable::FLAVOUR flavour = Variable::GetFlavour(m_stage, Variable::INPUT); |
| |
| return GetDefinitions(m_inputs, flavour); |
| } |
| |
| /** Get definitions of outputs |
| * |
| * @return Code with definitions |
| **/ |
| std::string ShaderInterface::GetDefinitionsOutputs() const |
| { |
| Variable::FLAVOUR flavour = Variable::GetFlavour(m_stage, Variable::OUTPUT); |
| |
| return GetDefinitions(m_outputs, flavour); |
| } |
| |
| /** Get definitions of buffers |
| * |
| * @return Code with definitions |
| **/ |
| std::string ShaderInterface::GetDefinitionsSSBs() const |
| { |
| return GetDefinitions(m_ssb_blocks, Variable::BASIC); |
| } |
| |
| /** Get definitions of uniforms |
| * |
| * @return Code with definitions |
| **/ |
| std::string ShaderInterface::GetDefinitionsUniforms() const |
| { |
| return GetDefinitions(m_uniforms, Variable::BASIC); |
| } |
| |
| /** Constructor |
| * |
| * @param in Input variable |
| * @param out Output variable |
| **/ |
| VaryingConnection::VaryingConnection(Variable* in, Variable* out) : m_in(in), m_out(out) |
| { |
| /* NBothing to be done here */ |
| } |
| |
| /** Adds new varying connection to given stage |
| * |
| * @param stage Shader stage |
| * @param in In varying |
| * @param out Out varying |
| **/ |
| void VaryingPassthrough::Add(Shader::STAGES stage, Variable* in, Variable* out) |
| { |
| VaryingConnection::Vector& vector = Get(stage); |
| |
| vector.push_back(VaryingConnection(in, out)); |
| } |
| |
| /** Get all passthrough connections for given stage |
| * |
| * @param stage Shader stage |
| * |
| * @return Vector of connections |
| **/ |
| VaryingConnection::Vector& VaryingPassthrough::Get(Shader::STAGES stage) |
| { |
| VaryingConnection::Vector* result = 0; |
| |
| switch (stage) |
| { |
| case Shader::FRAGMENT: |
| result = &m_fragment; |
| break; |
| case Shader::GEOMETRY: |
| result = &m_geometry; |
| break; |
| case Shader::TESS_CTRL: |
| result = &m_tess_ctrl; |
| break; |
| case Shader::TESS_EVAL: |
| result = &m_tess_eval; |
| break; |
| case Shader::VERTEX: |
| result = &m_vertex; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| return *result; |
| } |
| |
| /** Constructor |
| * |
| **/ |
| ProgramInterface::ProgramInterface() |
| : m_compute(Shader::COMPUTE) |
| , m_vertex(Shader::VERTEX) |
| , m_tess_ctrl(Shader::TESS_CTRL) |
| , m_tess_eval(Shader::TESS_EVAL) |
| , m_geometry(Shader::GEOMETRY) |
| , m_fragment(Shader::FRAGMENT) |
| { |
| } |
| |
| /** Destructor |
| * |
| **/ |
| ProgramInterface::~ProgramInterface() |
| { |
| clearPtrVector(m_blocks); |
| clearPtrVector(m_structures); |
| } |
| |
| /** Adds new interface |
| * |
| * @param name |
| * @param type |
| * |
| * @return Pointer to created interface |
| **/ |
| Interface* ProgramInterface::AddInterface(const GLchar* name, Interface::TYPE type) |
| { |
| Interface* interface = 0; |
| |
| if (Interface::STRUCT == type) |
| { |
| interface = new Interface(name, type); |
| |
| m_structures.push_back(interface); |
| } |
| else |
| { |
| interface = new Interface(name, type); |
| |
| m_blocks.push_back(interface); |
| } |
| |
| return interface; |
| } |
| |
| /** Adds new block interface |
| * |
| * @param name |
| * |
| * @return Pointer to created interface |
| **/ |
| Interface* ProgramInterface::Block(const GLchar* name) |
| { |
| return AddInterface(name, Interface::BLOCK); |
| } |
| |
| /** Get interface of given shader stage |
| * |
| * @param stage Shader stage |
| * |
| * @return Reference to stage interface |
| **/ |
| ShaderInterface& ProgramInterface::GetShaderInterface(Shader::STAGES stage) |
| { |
| ShaderInterface* interface = 0; |
| |
| switch (stage) |
| { |
| case Shader::COMPUTE: |
| interface = &m_compute; |
| break; |
| case Shader::FRAGMENT: |
| interface = &m_fragment; |
| break; |
| case Shader::GEOMETRY: |
| interface = &m_geometry; |
| break; |
| case Shader::TESS_CTRL: |
| interface = &m_tess_ctrl; |
| break; |
| case Shader::TESS_EVAL: |
| interface = &m_tess_eval; |
| break; |
| case Shader::VERTEX: |
| interface = &m_vertex; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| return *interface; |
| } |
| |
| /** Get interface of given shader stage |
| * |
| * @param stage Shader stage |
| * |
| * @return Reference to stage interface |
| **/ |
| const ShaderInterface& ProgramInterface::GetShaderInterface(Shader::STAGES stage) const |
| { |
| const ShaderInterface* interface = 0; |
| |
| switch (stage) |
| { |
| case Shader::COMPUTE: |
| interface = &m_compute; |
| break; |
| case Shader::FRAGMENT: |
| interface = &m_fragment; |
| break; |
| case Shader::GEOMETRY: |
| interface = &m_geometry; |
| break; |
| case Shader::TESS_CTRL: |
| interface = &m_tess_ctrl; |
| break; |
| case Shader::TESS_EVAL: |
| interface = &m_tess_eval; |
| break; |
| case Shader::VERTEX: |
| interface = &m_vertex; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| return *interface; |
| } |
| |
| /** Clone interface of Vertex shader stage to other stages |
| * It creates matching inputs, outputs, uniforms and buffers in other stages. |
| * There are no additional outputs for FRAGMENT shader generated. |
| * |
| * @param varying_passthrough Collection of varyings connections |
| **/ |
| void ProgramInterface::CloneVertexInterface(VaryingPassthrough& varying_passthrough) |
| { |
| /* VS outputs >> TCS inputs >> TCS outputs >> .. >> FS inputs */ |
| for (size_t i = 0; i < m_vertex.m_outputs.size(); ++i) |
| { |
| const Variable& vs_var = *m_vertex.m_outputs[i]; |
| const GLchar* prefix = GetStagePrefix(Shader::VERTEX, vs_var.m_storage); |
| |
| cloneVariableForStage(vs_var, Shader::TESS_CTRL, prefix, varying_passthrough); |
| cloneVariableForStage(vs_var, Shader::TESS_EVAL, prefix, varying_passthrough); |
| cloneVariableForStage(vs_var, Shader::GEOMETRY, prefix, varying_passthrough); |
| cloneVariableForStage(vs_var, Shader::FRAGMENT, prefix, varying_passthrough); |
| } |
| |
| /* Copy uniforms from VS to other stages */ |
| for (size_t i = 0; i < m_vertex.m_uniforms.size(); ++i) |
| { |
| Variable& vs_var = *m_vertex.m_uniforms[i]; |
| const GLchar* prefix = GetStagePrefix(Shader::VERTEX, vs_var.m_storage); |
| |
| cloneVariableForStage(vs_var, Shader::COMPUTE, prefix, varying_passthrough); |
| cloneVariableForStage(vs_var, Shader::TESS_CTRL, prefix, varying_passthrough); |
| cloneVariableForStage(vs_var, Shader::TESS_EVAL, prefix, varying_passthrough); |
| cloneVariableForStage(vs_var, Shader::GEOMETRY, prefix, varying_passthrough); |
| cloneVariableForStage(vs_var, Shader::FRAGMENT, prefix, varying_passthrough); |
| |
| /* Uniform blocks needs unique binding */ |
| if (true == vs_var.IsBlock()) |
| { |
| replaceBinding(vs_var, Shader::VERTEX); |
| } |
| } |
| |
| /* Copy SSBs from VS to other stages */ |
| for (size_t i = 0; i < m_vertex.m_ssb_blocks.size(); ++i) |
| { |
| Variable& vs_var = *m_vertex.m_ssb_blocks[i]; |
| const GLchar* prefix = GetStagePrefix(Shader::VERTEX, vs_var.m_storage); |
| |
| cloneVariableForStage(vs_var, Shader::COMPUTE, prefix, varying_passthrough); |
| cloneVariableForStage(vs_var, Shader::TESS_CTRL, prefix, varying_passthrough); |
| cloneVariableForStage(vs_var, Shader::TESS_EVAL, prefix, varying_passthrough); |
| cloneVariableForStage(vs_var, Shader::GEOMETRY, prefix, varying_passthrough); |
| cloneVariableForStage(vs_var, Shader::FRAGMENT, prefix, varying_passthrough); |
| |
| /* SSBs blocks needs unique binding */ |
| if (true == vs_var.IsBlock()) |
| { |
| replaceBinding(vs_var, Shader::VERTEX); |
| } |
| } |
| |
| m_compute.m_globals = m_vertex.m_globals; |
| m_fragment.m_globals = m_vertex.m_globals; |
| m_geometry.m_globals = m_vertex.m_globals; |
| m_tess_ctrl.m_globals = m_vertex.m_globals; |
| m_tess_eval.m_globals = m_vertex.m_globals; |
| } |
| |
| /** Clone variable for specific stage |
| * |
| * @param variable Variable |
| * @param stage Requested stage |
| * @param prefix Prefix used in variable name that is specific for original stage |
| * @param varying_passthrough Collection of varyings connections |
| **/ |
| void ProgramInterface::cloneVariableForStage(const Variable& variable, Shader::STAGES stage, const GLchar* prefix, |
| VaryingPassthrough& varying_passthrough) |
| { |
| switch (variable.m_storage) |
| { |
| case Variable::VARYING_OUTPUT: |
| { |
| Variable* in = cloneVariableForStage(variable, stage, Variable::VARYING_INPUT, prefix); |
| |
| if (Shader::FRAGMENT != stage) |
| { |
| Variable* out = cloneVariableForStage(variable, stage, Variable::VARYING_OUTPUT, prefix); |
| varying_passthrough.Add(stage, in, out); |
| } |
| } |
| break; |
| case Variable::UNIFORM: |
| case Variable::SSB: |
| cloneVariableForStage(variable, stage, variable.m_storage, prefix); |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| break; |
| } |
| } |
| |
| /** Clone variable for specific stage |
| * |
| * @param variable Variable |
| * @param stage Requested stage |
| * @param storage Storage used by variable |
| * @param prefix Prefix used in variable name that is specific for original stage |
| * |
| * @return New variable |
| **/ |
| Variable* ProgramInterface::cloneVariableForStage(const Variable& variable, Shader::STAGES stage, |
| Variable::STORAGE storage, const GLchar* prefix) |
| { |
| /* Initialize with original variable */ |
| Variable* var = new Variable(variable); |
| if (0 == var) |
| { |
| TCU_FAIL("Memory allocation"); |
| } |
| |
| /* Set up storage */ |
| var->m_storage = storage; |
| |
| /* Get name */ |
| std::string name = variable.m_descriptor.m_name; |
| |
| /* Prefix name with stage ID, empty means default block */ |
| if (false == name.empty()) |
| { |
| size_t position = 0; |
| const GLchar* stage_prefix = GetStagePrefix(stage, storage); |
| Utils::replaceToken(prefix, position, stage_prefix, name); |
| } |
| var->m_descriptor.m_name = name; |
| |
| /* Clone block */ |
| const bool is_block = variable.IsBlock(); |
| if (true == is_block) |
| { |
| const Interface* interface = variable.m_descriptor.m_interface; |
| |
| Interface* block = CloneBlockForStage(*interface, stage, storage, prefix); |
| |
| var->m_descriptor.m_interface = block; |
| } |
| |
| /* Store variable */ |
| ShaderInterface& si = GetShaderInterface(stage); |
| Variable* result = 0; |
| |
| switch (storage) |
| { |
| case Variable::VARYING_INPUT: |
| si.m_inputs.push_back(var); |
| result = si.m_inputs.back(); |
| break; |
| case Variable::VARYING_OUTPUT: |
| si.m_outputs.push_back(var); |
| result = si.m_outputs.back(); |
| break; |
| case Variable::UNIFORM: |
| /* Uniform blocks needs unique binding */ |
| if (true == is_block) |
| { |
| replaceBinding(*var, stage); |
| } |
| |
| si.m_uniforms.push_back(var); |
| result = si.m_uniforms.back(); |
| break; |
| case Variable::SSB: |
| /* SSBs needs unique binding */ |
| if (true == is_block) |
| { |
| replaceBinding(*var, stage); |
| } |
| |
| si.m_ssb_blocks.push_back(var); |
| result = si.m_ssb_blocks.back(); |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| break; |
| } |
| |
| return result; |
| } |
| |
| /** clone block to specific stage |
| * |
| * @param block Block to be copied |
| * @param stage Specific stage |
| * @param storage Storage used by block |
| * @param prefix Prefix used in block name |
| * |
| * @return New interface |
| **/ |
| Interface* ProgramInterface::CloneBlockForStage(const Interface& block, Shader::STAGES stage, Variable::STORAGE storage, |
| const GLchar* prefix) |
| { |
| /* Get name */ |
| std::string name = block.m_name; |
| |
| /* Prefix name with stage ID */ |
| size_t position = 0; |
| const GLchar* stage_prefix = GetStagePrefix(stage, storage); |
| Utils::replaceToken(prefix, position, stage_prefix, name); |
| |
| Interface* ptr = GetBlock(name.c_str()); |
| |
| if (0 == ptr) |
| { |
| ptr = AddInterface(name.c_str(), Interface::BLOCK); |
| } |
| |
| ptr->m_members = block.m_members; |
| |
| return ptr; |
| } |
| |
| /** Get stage specific prefix used in names |
| * |
| * @param stage Stage |
| * @param storage Storage class |
| * |
| * @return String |
| **/ |
| const GLchar* ProgramInterface::GetStagePrefix(Shader::STAGES stage, Variable::STORAGE storage) |
| { |
| static const GLchar* lut[Shader::STAGE_MAX][Variable::STORAGE_MAX] = { |
| /* IN OUT UNIFORM SSB MEMBER */ |
| /* CS */ { 0, 0, "cs_uni_", "cs_buf_", "" }, |
| /* VS */ { "in_vs_", "vs_tcs_", "vs_uni_", "vs_buf_", "" }, |
| /* TCS */ { "vs_tcs_", "tcs_tes_", "tcs_uni_", "tcs_buf_", "" }, |
| /* TES */ { "tcs_tes_", "tes_gs_", "tes_uni_", "tes_buf_", "" }, |
| /* GS */ { "tes_gs_", "gs_fs_", "gs_uni_", "gs_buf_", "" }, |
| /* FS */ { "gs_fs_", "fs_out_", "fs_uni_", "fs_buf_", "" }, |
| }; |
| |
| const GLchar* result = 0; |
| |
| result = lut[stage][storage]; |
| |
| return result; |
| } |
| |
| /** Get definitions of all structures used in program interface |
| * |
| * @return String with code |
| **/ |
| std::string ProgramInterface::GetDefinitionsStructures() const |
| { |
| return GetDefinitions(m_structures); |
| } |
| |
| /** Get interface code for stage |
| * |
| * @param stage Specific stage |
| * |
| * @return String with code |
| **/ |
| std::string ProgramInterface::GetInterfaceForStage(Shader::STAGES stage) const |
| { |
| size_t position = 0; |
| std::string interface = "/* Globals */\n" |
| "GLOBALS\n" |
| "\n" |
| "/* Structures */\n" |
| "STRUCTURES\n" |
| "\n" |
| "/* Uniforms */\n" |
| "UNIFORMS\n" |
| "\n" |
| "/* Inputs */\n" |
| "INPUTS\n" |
| "\n" |
| "/* Outputs */\n" |
| "OUTPUTS\n" |
| "\n" |
| "/* Storage */\n" |
| "STORAGE\n"; |
| |
| const ShaderInterface& si = GetShaderInterface(stage); |
| |
| const std::string& structures = GetDefinitionsStructures(); |
| |
| const std::string& globals = si.GetDefinitionsGlobals(); |
| const std::string& inputs = si.GetDefinitionsInputs(); |
| const std::string& outputs = si.GetDefinitionsOutputs(); |
| const std::string& uniforms = si.GetDefinitionsUniforms(); |
| const std::string& ssbs = si.GetDefinitionsSSBs(); |
| |
| replaceToken("GLOBALS", position, globals.c_str(), interface); |
| replaceToken("STRUCTURES", position, structures.c_str(), interface); |
| replaceToken("UNIFORMS", position, uniforms.c_str(), interface); |
| replaceToken("INPUTS", position, inputs.c_str(), interface); |
| replaceToken("OUTPUTS", position, outputs.c_str(), interface); |
| replaceToken("STORAGE", position, ssbs.c_str(), interface); |
| |
| return interface; |
| } |
| |
| /** Functional object used in find_if algorithm, in search for interface of given name |
| * |
| **/ |
| struct matchInterfaceName |
| { |
| matchInterfaceName(const GLchar* name) : m_name(name) |
| { |
| } |
| |
| bool operator()(const Interface* interface) |
| { |
| return 0 == interface->m_name.compare(m_name); |
| } |
| |
| const GLchar* m_name; |
| }; |
| |
| /** Finds interface of given name in given vector of interfaces |
| * |
| * @param vector Collection of interfaces |
| * @param name Requested name |
| * |
| * @return Pointer to interface if available, 0 otherwise |
| **/ |
| static Interface* findInterfaceByName(Interface::PtrVector& vector, const GLchar* name) |
| { |
| Interface::PtrVector::iterator it = std::find_if(vector.begin(), vector.end(), matchInterfaceName(name)); |
| |
| if (vector.end() != it) |
| { |
| return *it; |
| } |
| else |
| { |
| return 0; |
| } |
| } |
| |
| /** Search for block of given name |
| * |
| * @param name Name of block |
| * |
| * @return Pointer to block or 0 |
| **/ |
| Interface* ProgramInterface::GetBlock(const GLchar* name) |
| { |
| return findInterfaceByName(m_blocks, name); |
| } |
| |
| /** Search for structure of given name |
| * |
| * @param name Name of structure |
| * |
| * @return Pointer to structure or 0 |
| **/ |
| Interface* ProgramInterface::GetStructure(const GLchar* name) |
| { |
| return findInterfaceByName(m_structures, name); |
| } |
| |
| /** Adds new sturcture to interface |
| * |
| * @param name Name of structure |
| * |
| * @return Created structure |
| **/ |
| Interface* ProgramInterface::Structure(const GLchar* name) |
| { |
| return AddInterface(name, Interface::STRUCT); |
| } |
| |
| /** Replace "BINDING" token in qualifiers string to value specific for given stage |
| * |
| * @param variable Variable to modify |
| * @param stage Requested stage |
| **/ |
| void ProgramInterface::replaceBinding(Variable& variable, Shader::STAGES stage) |
| { |
| GLchar binding[16]; |
| sprintf(binding, "%d", stage); |
| replaceAllTokens("BINDING", binding, variable.m_descriptor.m_qualifiers); |
| } |
| } /* Utils namespace */ |
| |
| /** Debuging procedure. Logs parameters. |
| * |
| * @param source As specified in GL spec. |
| * @param type As specified in GL spec. |
| * @param id As specified in GL spec. |
| * @param severity As specified in GL spec. |
| * @param ignored |
| * @param message As specified in GL spec. |
| * @param info Pointer to instance of Context used by test. |
| */ |
| void GLW_APIENTRY debug_proc(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei /* length */, |
| const GLchar* message, void* info) |
| { |
| deqp::Context* ctx = (deqp::Context*)info; |
| |
| const GLchar* source_str = "Unknown"; |
| const GLchar* type_str = "Unknown"; |
| const GLchar* severity_str = "Unknown"; |
| |
| switch (source) |
| { |
| case GL_DEBUG_SOURCE_API: |
| source_str = "API"; |
| break; |
| case GL_DEBUG_SOURCE_APPLICATION: |
| source_str = "APP"; |
| break; |
| case GL_DEBUG_SOURCE_OTHER: |
| source_str = "OTR"; |
| break; |
| case GL_DEBUG_SOURCE_SHADER_COMPILER: |
| source_str = "COM"; |
| break; |
| case GL_DEBUG_SOURCE_THIRD_PARTY: |
| source_str = "3RD"; |
| break; |
| case GL_DEBUG_SOURCE_WINDOW_SYSTEM: |
| source_str = "WS"; |
| break; |
| default: |
| break; |
| } |
| |
| switch (type) |
| { |
| case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: |
| type_str = "DEPRECATED_BEHAVIOR"; |
| break; |
| case GL_DEBUG_TYPE_ERROR: |
| type_str = "ERROR"; |
| break; |
| case GL_DEBUG_TYPE_MARKER: |
| type_str = "MARKER"; |
| break; |
| case GL_DEBUG_TYPE_OTHER: |
| type_str = "OTHER"; |
| break; |
| case GL_DEBUG_TYPE_PERFORMANCE: |
| type_str = "PERFORMANCE"; |
| break; |
| case GL_DEBUG_TYPE_POP_GROUP: |
| type_str = "POP_GROUP"; |
| break; |
| case GL_DEBUG_TYPE_PORTABILITY: |
| type_str = "PORTABILITY"; |
| break; |
| case GL_DEBUG_TYPE_PUSH_GROUP: |
| type_str = "PUSH_GROUP"; |
| break; |
| case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: |
| type_str = "UNDEFINED_BEHAVIOR"; |
| break; |
| default: |
| break; |
| } |
| |
| switch (severity) |
| { |
| case GL_DEBUG_SEVERITY_HIGH: |
| severity_str = "H"; |
| break; |
| case GL_DEBUG_SEVERITY_LOW: |
| severity_str = "L"; |
| break; |
| case GL_DEBUG_SEVERITY_MEDIUM: |
| severity_str = "M"; |
| break; |
| case GL_DEBUG_SEVERITY_NOTIFICATION: |
| severity_str = "N"; |
| break; |
| default: |
| break; |
| } |
| |
| ctx->getTestContext().getLog() << tcu::TestLog::Message << "DEBUG_INFO: " << std::setw(3) << source_str << "|" |
| << severity_str << "|" << std::setw(18) << type_str << "|" << std::setw(12) << id |
| << ": " << message << tcu::TestLog::EndMessage; |
| } |
| |
| /** Constructor |
| * |
| * @param context Test context |
| * @param test_name Test name |
| * @param test_description Test description |
| **/ |
| TestBase::TestBase(deqp::Context& context, const GLchar* test_name, const GLchar* test_description) |
| : TestCase(context, test_name, test_description) |
| { |
| /* Nothing to be done here */ |
| } |
| |
| /** Execute test |
| * |
| * @return tcu::TestNode::STOP otherwise |
| **/ |
| tcu::TestNode::IterateResult TestBase::iterate() |
| { |
| bool test_result; |
| |
| #if DEBUG_ENBALE_MESSAGE_CALLBACK |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| gl.debugMessageCallback(debug_proc, &m_context); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "DebugMessageCallback"); |
| #endif /* DEBUG_ENBALE_MESSAGE_CALLBACK */ |
| |
| try |
| { |
| /* Execute test */ |
| test_result = test(); |
| } |
| catch (std::exception& exc) |
| { |
| TCU_FAIL(exc.what()); |
| } |
| |
| /* Set result */ |
| if (true == test_result) |
| { |
| m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| } |
| else |
| { |
| m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Fail"); |
| } |
| |
| /* Done */ |
| return tcu::TestNode::STOP; |
| } |
| |
| /** Get last input location available for given type at specific stage |
| * |
| * @param stage Shader stage |
| * @param type Input type |
| * @param array_length Length of input array |
| * |
| * @return Last location index |
| **/ |
| GLint TestBase::getLastInputLocation(Utils::Shader::STAGES stage, const Utils::Type& type, GLuint array_length, bool ignore_prev_stage) |
| { |
| GLint divide = 4; /* 4 components per location */ |
| GLint param = 0; |
| GLenum pname = 0; |
| GLint paramPrev = 0; |
| GLenum pnamePrev = 0; |
| |
| /* Select pnmae */ |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| pname = GL_MAX_FRAGMENT_INPUT_COMPONENTS; |
| pnamePrev = GL_MAX_GEOMETRY_OUTPUT_COMPONENTS; |
| break; |
| case Utils::Shader::GEOMETRY: |
| pname = GL_MAX_GEOMETRY_INPUT_COMPONENTS; |
| pnamePrev = GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| pname = GL_MAX_TESS_CONTROL_INPUT_COMPONENTS; |
| pnamePrev = GL_MAX_VERTEX_OUTPUT_COMPONENTS; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| pname = GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS; |
| pnamePrev = GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS; |
| break; |
| case Utils::Shader::VERTEX: |
| pname = GL_MAX_VERTEX_ATTRIBS; |
| divide = 1; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| break; |
| } |
| |
| /* Zero means no array, but 1 slot is required */ |
| if (0 == array_length) |
| { |
| array_length += 1; |
| } |
| |
| /* Get MAX */ |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| gl.getIntegerv(pname, ¶m); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv"); |
| |
| if (pnamePrev && !ignore_prev_stage) { |
| gl.getIntegerv(pnamePrev, ¶mPrev); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv"); |
| |
| /* Don't read from a location that doesn't exist in the previous stage */ |
| param = de::min(param, paramPrev); |
| } |
| |
| /* Calculate */ |
| #if WRKARD_VARYINGLOCATIONSTEST |
| |
| const GLint n_avl_locations = 16; |
| |
| #else |
| |
| const GLint n_avl_locations = param / divide; |
| |
| #endif |
| |
| const GLuint n_req_location = type.GetLocations(stage == Utils::Shader::VERTEX) * array_length; |
| |
| return n_avl_locations - n_req_location; /* last is max - 1 */ |
| } |
| |
| /** Get last output location available for given type at specific stage |
| * |
| * @param stage Shader stage |
| * @param type Input type |
| * @param array_length Length of input array |
| * |
| * @return Last location index |
| **/ |
| GLint TestBase::getLastOutputLocation(Utils::Shader::STAGES stage, const Utils::Type& type, GLuint array_length, bool ignore_next_stage) |
| { |
| GLint param = 0; |
| GLenum pname = 0; |
| GLint paramNext = 0; |
| GLenum pnameNext = 0; |
| |
| /* Select pname */ |
| switch (stage) |
| { |
| case Utils::Shader::GEOMETRY: |
| pname = GL_MAX_GEOMETRY_OUTPUT_COMPONENTS; |
| pnameNext = GL_MAX_FRAGMENT_INPUT_COMPONENTS; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| pname = GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS; |
| pnameNext = GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| pname = GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS; |
| pnameNext = GL_MAX_GEOMETRY_INPUT_COMPONENTS; |
| break; |
| case Utils::Shader::VERTEX: |
| pname = GL_MAX_VERTEX_OUTPUT_COMPONENTS; |
| pnameNext = GL_MAX_TESS_CONTROL_INPUT_COMPONENTS; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| break; |
| } |
| |
| /* Zero means no array, but 1 slot is required */ |
| if (0 == array_length) |
| { |
| array_length += 1; |
| } |
| |
| /* Get MAX */ |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| gl.getIntegerv(pname, ¶m); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv"); |
| |
| /* Calculate */ |
| #if WRKARD_VARYINGLOCATIONSTEST |
| |
| const GLint n_avl_locations = 16; |
| |
| #else |
| |
| /* Don't write to a location that doesn't exist in the next stage */ |
| if (!ignore_next_stage) |
| { |
| gl.getIntegerv(pnameNext, ¶mNext); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv"); |
| |
| param = de::min(param, paramNext); |
| } |
| |
| const GLint n_avl_locations = param / 4; /* 4 components per location */ |
| |
| #endif |
| |
| const GLuint n_req_location = type.GetLocations() * array_length; |
| |
| return n_avl_locations - n_req_location; /* last is max - 1 */ |
| } |
| |
| /** Basic implementation |
| * |
| * @param ignored |
| * |
| * @return Empty string |
| **/ |
| std::string TestBase::getTestCaseName(GLuint /* test_case_index */) |
| { |
| std::string result; |
| |
| return result; |
| } |
| |
| /** Basic implementation |
| * |
| * @return 1 |
| **/ |
| GLuint TestBase::getTestCaseNumber() |
| { |
| return 1; |
| } |
| |
| /** Check if flat qualifier is required for given type, stage and storage |
| * |
| * @param stage Shader stage |
| * @param type Input type |
| * @param storage Storage of variable |
| * |
| * @return Last location index |
| **/ |
| bool TestBase::isFlatRequired(Utils::Shader::STAGES stage, const Utils::Type& type, Utils::Variable::STORAGE storage, |
| const bool coherent) const |
| { |
| /* Float types do not need flat at all */ |
| if (Utils::Type::Float == type.m_basic_type) |
| { |
| return false; |
| } |
| |
| /* Inputs to fragment shader */ |
| if ((Utils::Shader::FRAGMENT == stage) && (Utils::Variable::VARYING_INPUT == storage)) |
| { |
| return true; |
| } |
| |
| /* Outputs from geometry shader |
| * |
| * This is not strictly needed since fragment shader input |
| * interpolation qualifiers will override whatever comes from the |
| * previous stage. However, if we want to have a coherent |
| * interface, let's better do it. |
| */ |
| if ((Utils::Shader::GEOMETRY == stage) && (Utils::Variable::VARYING_OUTPUT == storage) && coherent) |
| { |
| return true; |
| } |
| |
| return false; |
| } |
| |
| /** Basic implementation of testInit method |
| * |
| **/ |
| void TestBase::testInit() |
| { |
| } |
| |
| /** Calculate stride for interface |
| * |
| * @param interface Interface |
| * |
| * @return Calculated value |
| **/ |
| GLuint TestBase::calculateStride(const Utils::Interface& interface) const |
| { |
| const size_t n_members = interface.m_members.size(); |
| |
| GLuint stride = 0; |
| |
| for (size_t i = 0; i < n_members; ++i) |
| { |
| const Utils::Variable::Descriptor& member = interface.m_members[i]; |
| const GLuint member_offset = member.m_offset; |
| const GLuint member_stride = member.m_expected_stride_of_element; |
| const GLuint member_ends_at = member_offset + member_stride; |
| |
| stride = std::max(stride, member_ends_at); |
| } |
| |
| return stride; |
| } |
| |
| /** Generate data for interface. This routine is recursive |
| * |
| * @param interface Interface |
| * @param offset Offset in out_data |
| * @param out_data Buffer to be filled |
| **/ |
| void TestBase::generateData(const Utils::Interface& interface, GLuint offset, std::vector<GLubyte>& out_data) const |
| { |
| const size_t n_members = interface.m_members.size(); |
| GLubyte* ptr = &out_data[offset]; |
| |
| for (size_t i = 0; i < n_members; ++i) |
| { |
| const Utils::Variable::Descriptor& member = interface.m_members[i]; |
| const GLuint member_offset = member.m_offset; |
| const GLuint n_elements = (0 == member.m_n_array_elements) ? 1 : member.m_n_array_elements; |
| |
| for (GLuint element = 0; element < n_elements; ++element) |
| { |
| const GLuint element_offset = element * member.m_expected_stride_of_element; |
| const GLuint data_offfset = member_offset + element_offset; |
| |
| if (Utils::Variable::BUILTIN == member.m_type) |
| { |
| const std::vector<GLubyte>& data = member.m_builtin.GenerateData(); |
| |
| memcpy(ptr + data_offfset, &data[0], data.size()); |
| } |
| else |
| { |
| generateData(*member.m_interface, offset + data_offfset, out_data); |
| } |
| } |
| } |
| } |
| |
| /** Get type at index |
| * |
| * @param index Index of requested type |
| * |
| * @return Type |
| **/ |
| Utils::Type TestBase::getType(GLuint index) const |
| { |
| Utils::Type type; |
| |
| switch (index) |
| { |
| case 0: |
| type = Utils::Type::_double; |
| break; |
| case 1: |
| type = Utils::Type::dmat2; |
| break; |
| case 2: |
| type = Utils::Type::dmat2x3; |
| break; |
| case 3: |
| type = Utils::Type::dmat2x4; |
| break; |
| case 4: |
| type = Utils::Type::dmat3; |
| break; |
| case 5: |
| type = Utils::Type::dmat3x2; |
| break; |
| case 6: |
| type = Utils::Type::dmat3x4; |
| break; |
| case 7: |
| type = Utils::Type::dmat4; |
| break; |
| case 8: |
| type = Utils::Type::dmat4x2; |
| break; |
| case 9: |
| type = Utils::Type::dmat4x3; |
| break; |
| case 10: |
| type = Utils::Type::dvec2; |
| break; |
| case 11: |
| type = Utils::Type::dvec3; |
| break; |
| case 12: |
| type = Utils::Type::dvec4; |
| break; |
| case 13: |
| type = Utils::Type::_float; |
| break; |
| case 14: |
| type = Utils::Type::mat2; |
| break; |
| case 15: |
| type = Utils::Type::mat2x3; |
| break; |
| case 16: |
| type = Utils::Type::mat2x4; |
| break; |
| case 17: |
| type = Utils::Type::mat3; |
| break; |
| case 18: |
| type = Utils::Type::mat3x2; |
| break; |
| case 19: |
| type = Utils::Type::mat3x4; |
| break; |
| case 20: |
| type = Utils::Type::mat4; |
| break; |
| case 21: |
| type = Utils::Type::mat4x2; |
| break; |
| case 22: |
| type = Utils::Type::mat4x3; |
| break; |
| case 23: |
| type = Utils::Type::vec2; |
| break; |
| case 24: |
| type = Utils::Type::vec3; |
| break; |
| case 25: |
| type = Utils::Type::vec4; |
| break; |
| case 26: |
| type = Utils::Type::_int; |
| break; |
| case 27: |
| type = Utils::Type::ivec2; |
| break; |
| case 28: |
| type = Utils::Type::ivec3; |
| break; |
| case 29: |
| type = Utils::Type::ivec4; |
| break; |
| case 30: |
| type = Utils::Type::uint; |
| break; |
| case 31: |
| type = Utils::Type::uvec2; |
| break; |
| case 32: |
| type = Utils::Type::uvec3; |
| break; |
| case 33: |
| type = Utils::Type::uvec4; |
| break; |
| default: |
| TCU_FAIL("invalid enum"); |
| } |
| |
| return type; |
| } |
| |
| /** Get name of type at index |
| * |
| * @param index Index of type |
| * |
| * @return Name |
| **/ |
| std::string TestBase::getTypeName(GLuint index) const |
| { |
| std::string name = getType(index).GetGLSLTypeName(); |
| |
| return name; |
| } |
| |
| /** Get number of types |
| * |
| * @return 34 |
| **/ |
| glw::GLuint TestBase::getTypesNumber() const |
| { |
| return 34; |
| } |
| |
| /** Execute test |
| * |
| * @return true if test pass, false otherwise |
| **/ |
| bool TestBase::test() |
| { |
| bool result = true; |
| GLuint n_test_cases = 0; |
| |
| /* Prepare test */ |
| testInit(); |
| |
| /* GL entry points */ |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Tessellation patch set up */ |
| gl.patchParameteri(GL_PATCH_VERTICES, 1); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "PatchParameteri"); |
| |
| /* Get number of test cases */ |
| n_test_cases = getTestCaseNumber(); |
| |
| #if DEBUG_REPEAT_TEST_CASE |
| |
| while (1) |
| { |
| GLuint test_case = DEBUG_REPEATED_TEST_CASE; |
| |
| #else /* DEBUG_REPEAT_TEST_CASE */ |
| |
| for (GLuint test_case = 0; test_case < n_test_cases; ++test_case) |
| { |
| #endif /* DEBUG_REPEAT_TEST_CASE */ |
| |
| /* Execute case */ |
| if (!testCase(test_case)) |
| { |
| const std::string& test_case_name = getTestCaseName(test_case); |
| |
| if (false == test_case_name.empty()) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "Test case (" << test_case_name |
| << ") failed." << tcu::TestLog::EndMessage; |
| } |
| else |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "Test case (" << test_case |
| << ") failed." << tcu::TestLog::EndMessage; |
| } |
| |
| result = false; |
| } |
| } |
| |
| /* Done */ |
| return result; |
| } |
| |
| /* Constants used by BufferTestBase */ |
| const GLuint BufferTestBase::bufferDescriptor::m_non_indexed = -1; |
| |
| /** Constructor |
| * |
| * @param context Test context |
| * @param test_name Name of test |
| * @param test_description Description of test |
| **/ |
| BufferTestBase::BufferTestBase(deqp::Context& context, const GLchar* test_name, const GLchar* test_description) |
| : TestBase(context, test_name, test_description) |
| { |
| } |
| |
| /** Execute drawArrays for single vertex |
| * |
| * @param ignored |
| * |
| * @return true |
| **/ |
| bool BufferTestBase::executeDrawCall(bool tesEnabled, GLuint /* test_case_index */) |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| gl.disable(GL_RASTERIZER_DISCARD); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Disable"); |
| |
| gl.beginTransformFeedback(GL_POINTS); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "BeginTransformFeedback"); |
| |
| // Only TES is existed, glDrawArray can use the parameter GL_PATCHES |
| if (tesEnabled == false) |
| { |
| gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */); |
| } |
| else |
| { |
| gl.drawArrays(GL_PATCHES, 0 /* first */, 1 /* count */); |
| } |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays"); |
| |
| gl.endTransformFeedback(); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "EndTransformFeedback"); |
| |
| return true; |
| } |
| |
| /** Get descriptors of buffers necessary for test |
| * |
| * @param ignored |
| * @param ignored |
| **/ |
| void BufferTestBase::getBufferDescriptors(glw::GLuint /* test_case_index */, |
| bufferDescriptor::Vector& /* out_descriptors */) |
| { |
| /* Nothhing to be done */ |
| } |
| |
| /** Get list of names of varyings that will be registered with TransformFeedbackVaryings |
| * |
| * @param ignored |
| * @param ignored |
| **/ |
| void BufferTestBase::getCapturedVaryings(glw::GLuint /* test_case_index */, |
| Utils::Program::NameVector& /* captured_varyings */, |
| GLint* /* xfb_components */) |
| { |
| /* Nothing to be done */ |
| } |
| |
| /** Get body of main function for given shader stage |
| * |
| * @param ignored |
| * @param ignored |
| * @param out_assignments Set to empty |
| * @param out_calculations Set to empty |
| **/ |
| void BufferTestBase::getShaderBody(glw::GLuint /* test_case_index */, Utils::Shader::STAGES /* stage */, |
| std::string& out_assignments, std::string& out_calculations) |
| { |
| out_assignments = ""; |
| out_calculations = ""; |
| } |
| |
| /** Get interface of shader |
| * |
| * @param ignored |
| * @param ignored |
| * @param out_interface Set to "" |
| **/ |
| void BufferTestBase::getShaderInterface(glw::GLuint /* test_case_index */, Utils::Shader::STAGES /* stage */, |
| std::string& out_interface) |
| { |
| out_interface = ""; |
| } |
| |
| /** Get source code of shader |
| * |
| * @param test_case_index Index of test case |
| * @param stage Shader stage |
| * |
| * @return Source |
| **/ |
| std::string BufferTestBase::getShaderSource(glw::GLuint test_case_index, Utils::Shader::STAGES stage) |
| { |
| std::string assignments; |
| std::string calculations; |
| std::string interface; |
| |
| /* */ |
| getShaderBody(test_case_index, stage, assignments, calculations); |
| getShaderInterface(test_case_index, stage, interface); |
| |
| /* */ |
| std::string source = getShaderTemplate(stage); |
| |
| /* */ |
| size_t position = 0; |
| Utils::replaceToken("INTERFACE", position, interface.c_str(), source); |
| Utils::replaceToken("CALCULATIONS", position, calculations.c_str(), source); |
| Utils::replaceToken("ASSIGNMENTS", position, assignments.c_str(), source); |
| |
| /* */ |
| return source; |
| } |
| |
| /** Inspects program to check if all resources are as expected |
| * |
| * @param ignored |
| * @param ignored |
| * @param ignored |
| * |
| * @return true |
| **/ |
| bool BufferTestBase::inspectProgram(GLuint /* test_case_index */, Utils::Program& /* program */, |
| std::stringstream& /* out_stream */) |
| { |
| return true; |
| } |
| |
| /** Runs test case |
| * |
| * @param test_case_index Id of test case |
| * |
| * @return true if test case pass, false otherwise |
| **/ |
| bool BufferTestBase::testCase(GLuint test_case_index) |
| { |
| try |
| { |
| bufferCollection buffers; |
| Utils::Program::NameVector captured_varyings; |
| bufferDescriptor::Vector descriptors; |
| Utils::Program program(m_context); |
| Utils::VertexArray vao(m_context); |
| |
| /* Get captured varyings */ |
| GLint xfb_components; |
| getCapturedVaryings(test_case_index, captured_varyings, &xfb_components); |
| |
| /* Don't generate shaders that try to capture more XFB components than the implementation's limit */ |
| if (captured_varyings.size() > 0) |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| GLint max_xfb_components; |
| gl.getIntegerv(GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS, &max_xfb_components); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv"); |
| |
| if (xfb_components > max_xfb_components) |
| return true; |
| } |
| |
| /* Get shader sources */ |
| const std::string& fragment_shader = getShaderSource(test_case_index, Utils::Shader::FRAGMENT); |
| const std::string& geometry_shader = getShaderSource(test_case_index, Utils::Shader::GEOMETRY); |
| const std::string& tess_ctrl_shader = getShaderSource(test_case_index, Utils::Shader::TESS_CTRL); |
| const std::string& tess_eval_shader = getShaderSource(test_case_index, Utils::Shader::TESS_EVAL); |
| const std::string& vertex_shader = getShaderSource(test_case_index, Utils::Shader::VERTEX); |
| |
| /* Set up program */ |
| program.Init("" /* compute_shader */, fragment_shader, geometry_shader, tess_ctrl_shader, tess_eval_shader, |
| vertex_shader, captured_varyings, true, false /* is_separable */); |
| |
| /* Inspection */ |
| { |
| std::stringstream stream; |
| if (false == inspectProgram(test_case_index, program, stream)) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message |
| << "Program inspection failed. Test case: " << getTestCaseName(test_case_index) |
| << ". Reason: " << stream.str() << tcu::TestLog::EndMessage |
| << tcu::TestLog::KernelSource(vertex_shader) << tcu::TestLog::KernelSource(tess_ctrl_shader) |
| << tcu::TestLog::KernelSource(tess_eval_shader) << tcu::TestLog::KernelSource(geometry_shader) |
| << tcu::TestLog::KernelSource(fragment_shader); |
| |
| return false; |
| } |
| } |
| |
| program.Use(); |
| |
| /* Set up buffers */ |
| getBufferDescriptors(test_case_index, descriptors); |
| cleanBuffers(); |
| prepareBuffers(descriptors, buffers); |
| |
| /* Set up vao */ |
| vao.Init(); |
| vao.Bind(); |
| |
| /* Draw */ |
| bool result = executeDrawCall((program.m_tess_eval.m_id != 0), test_case_index); |
| |
| #if USE_NSIGHT |
| m_context.getRenderContext().postIterate(); |
| #endif |
| |
| if (false == result) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::KernelSource(vertex_shader) << tcu::TestLog::KernelSource(tess_ctrl_shader) |
| << tcu::TestLog::KernelSource(tess_eval_shader) << tcu::TestLog::KernelSource(geometry_shader) |
| << tcu::TestLog::KernelSource(fragment_shader); |
| |
| return false; |
| } |
| |
| /* Verify result */ |
| if (false == verifyBuffers(buffers)) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::KernelSource(vertex_shader) << tcu::TestLog::KernelSource(tess_ctrl_shader) |
| << tcu::TestLog::KernelSource(tess_eval_shader) << tcu::TestLog::KernelSource(geometry_shader) |
| << tcu::TestLog::KernelSource(fragment_shader); |
| |
| return false; |
| } |
| } |
| catch (Utils::Shader::InvalidSourceException& exc) |
| { |
| exc.log(m_context); |
| TCU_FAIL(exc.what()); |
| } |
| catch (Utils::Program::BuildException& exc) |
| { |
| exc.log(m_context); |
| TCU_FAIL(exc.what()); |
| } |
| |
| /* Done */ |
| return true; |
| } |
| |
| /** Verify contents of buffers |
| * |
| * @param buffers Collection of buffers to be verified |
| * |
| * @return true if everything is as expected, false otherwise |
| **/ |
| bool BufferTestBase::verifyBuffers(bufferCollection& buffers) |
| { |
| bool result = true; |
| |
| for (bufferCollection::Vector::iterator it = buffers.m_vector.begin(), end = buffers.m_vector.end(); end != it; |
| ++it) |
| { |
| bufferCollection::pair& pair = *it; |
| Utils::Buffer* buffer = pair.m_buffer; |
| bufferDescriptor* descriptor = pair.m_descriptor; |
| size_t size = descriptor->m_expected_data.size(); |
| |
| /* Skip buffers that have no expected data */ |
| if (0 == size) |
| { |
| continue; |
| } |
| |
| /* Get pointer to contents of buffer */ |
| buffer->Bind(); |
| GLvoid* buffer_data = buffer->Map(Utils::Buffer::ReadOnly); |
| |
| /* Get pointer to expected data */ |
| GLvoid* expected_data = &descriptor->m_expected_data[0]; |
| |
| /* Compare */ |
| int res = memcmp(buffer_data, expected_data, size); |
| |
| if (0 != res) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message |
| << "Invalid result. Buffer: " << Utils::Buffer::GetBufferName(descriptor->m_target) |
| << ". Index: " << descriptor->m_index << tcu::TestLog::EndMessage; |
| |
| result = false; |
| } |
| |
| /* Release buffer mapping */ |
| buffer->UnMap(); |
| } |
| |
| return result; |
| } |
| |
| /** Unbinds all uniforms and xfb |
| * |
| **/ |
| void BufferTestBase::cleanBuffers() |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| GLint max_uni = 0; |
| GLint max_xfb = 0; |
| |
| gl.getIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &max_uni); |
| gl.getIntegerv(GL_MAX_TRANSFORM_FEEDBACK_BUFFERS, &max_xfb); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv"); |
| |
| for (GLint i = 0; i < max_uni; ++i) |
| { |
| Utils::Buffer::BindBase(gl, 0, Utils::Buffer::Uniform, i); |
| } |
| |
| for (GLint i = 0; i < max_xfb; ++i) |
| { |
| Utils::Buffer::BindBase(gl, 0, Utils::Buffer::Transform_feedback, i); |
| } |
| } |
| |
| /** Get template of shader for given stage |
| * |
| * @param stage Stage |
| * |
| * @return Template of shader source |
| **/ |
| std::string BufferTestBase::getShaderTemplate(Utils::Shader::STAGES stage) |
| { |
| static const GLchar* compute_shader_template = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n" |
| "\n" |
| "writeonly uniform uimage2D uni_image;\n" |
| "\n" |
| "INTERFACE" |
| "\n" |
| "void main()\n" |
| "{\n" |
| "CALCULATIONS" |
| "\n" |
| "ASSIGNMENTS" |
| "}\n" |
| "\n"; |
| |
| static const GLchar* fragment_shader_template = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "INTERFACE" |
| "\n" |
| "void main()\n" |
| "{\n" |
| "CALCULATIONS" |
| "\n" |
| "ASSIGNMENTS" |
| "}\n" |
| "\n"; |
| |
| // max_vertices is set to 3 for the test case "xfb_vertex_streams" declares 3 streams in geometry shader, |
| // according to spec, max_vertices should be no less than 3 if there are 3 streams in GS. |
| static const GLchar* geometry_shader_template = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(points, max_vertices = 3) out;\n" |
| "\n" |
| "INTERFACE" |
| "\n" |
| "void main()\n" |
| "{\n" |
| "CALCULATIONS" |
| "\n" |
| "\n" |
| "ASSIGNMENTS" |
| " gl_Position = vec4(0, 0, 0, 1);\n" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| |
| static const GLchar* tess_ctrl_shader_template = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "INTERFACE" |
| "\n" |
| "void main()\n" |
| "{\n" |
| "CALCULATIONS" |
| "\n" |
| "ASSIGNMENTS" |
| "\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| |
| static const GLchar* tess_eval_shader_template = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(isolines, point_mode) in;\n" |
| "\n" |
| "INTERFACE" |
| "\n" |
| "void main()\n" |
| "{\n" |
| "CALCULATIONS" |
| "\n" |
| "ASSIGNMENTS" |
| "}\n" |
| "\n"; |
| |
| static const GLchar* vertex_shader_template = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "INTERFACE" |
| "\n" |
| "void main()\n" |
| "{\n" |
| "CALCULATIONS" |
| "\n" |
| "ASSIGNMENTS" |
| "}\n" |
| "\n"; |
| |
| const GLchar* result = 0; |
| |
| switch (stage) |
| { |
| case Utils::Shader::COMPUTE: |
| result = compute_shader_template; |
| break; |
| case Utils::Shader::FRAGMENT: |
| result = fragment_shader_template; |
| break; |
| case Utils::Shader::GEOMETRY: |
| result = geometry_shader_template; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| result = tess_ctrl_shader_template; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| result = tess_eval_shader_template; |
| break; |
| case Utils::Shader::VERTEX: |
| result = vertex_shader_template; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| return result; |
| } |
| |
| /** Prepare buffer according to descriptor |
| * |
| * @param buffer Buffer to prepare |
| * @param desc Descriptor |
| **/ |
| void BufferTestBase::prepareBuffer(Utils::Buffer& buffer, bufferDescriptor& desc) |
| { |
| GLsizeiptr size = 0; |
| GLvoid* data = 0; |
| |
| if (false == desc.m_initial_data.empty()) |
| { |
| size = desc.m_initial_data.size(); |
| data = &desc.m_initial_data[0]; |
| } |
| else if (false == desc.m_expected_data.empty()) |
| { |
| size = desc.m_expected_data.size(); |
| } |
| |
| buffer.Init(desc.m_target, Utils::Buffer::StaticDraw, size, data); |
| |
| if (bufferDescriptor::m_non_indexed != desc.m_index) |
| { |
| buffer.BindBase(desc.m_index); |
| } |
| else |
| { |
| buffer.Bind(); |
| } |
| } |
| |
| /** Prepare collection of buffer |
| * |
| * @param descriptors Collection of descriptors |
| * @param out_buffers Collection of buffers |
| **/ |
| void BufferTestBase::prepareBuffers(bufferDescriptor::Vector& descriptors, bufferCollection& out_buffers) |
| { |
| for (bufferDescriptor::Vector::iterator it = descriptors.begin(), end = descriptors.end(); end != it; ++it) |
| { |
| bufferCollection::pair pair; |
| |
| pair.m_buffer = new Utils::Buffer(m_context); |
| if (0 == pair.m_buffer) |
| { |
| TCU_FAIL("Memory allocation failed"); |
| } |
| |
| pair.m_descriptor = &(*it); |
| |
| prepareBuffer(*pair.m_buffer, *pair.m_descriptor); |
| |
| out_buffers.m_vector.push_back(pair); |
| } |
| } |
| |
| /** Destructor |
| * |
| **/ |
| BufferTestBase::bufferCollection::~bufferCollection() |
| { |
| for (Vector::iterator it = m_vector.begin(), end = m_vector.end(); end != it; ++it) |
| { |
| if (0 != it->m_buffer) |
| { |
| delete it->m_buffer; |
| it->m_buffer = 0; |
| } |
| } |
| } |
| |
| /** Constructor |
| * |
| * @param context Test context |
| * @param test_name Name of test |
| * @param test_description Description of test |
| **/ |
| NegativeTestBase::NegativeTestBase(deqp::Context& context, const GLchar* test_name, const GLchar* test_description) |
| : TestBase(context, test_name, test_description) |
| { |
| } |
| |
| /** Selects if "compute" stage is relevant for test |
| * |
| * @param ignored |
| * |
| * @return true |
| **/ |
| bool NegativeTestBase::isComputeRelevant(GLuint /* test_case_index */) |
| { |
| return true; |
| } |
| |
| /** Selects if compilation failure is expected result |
| * |
| * @param ignored |
| * |
| * @return true |
| **/ |
| bool NegativeTestBase::isFailureExpected(GLuint /* test_case_index */) |
| { |
| return true; |
| } |
| |
| /** Selects if the test case should use a separable program |
| * |
| * @param ignored |
| * |
| * @return false |
| **/ |
| bool NegativeTestBase::isSeparable(const GLuint /* test_case_index */) |
| { |
| return false; |
| } |
| |
| /** Runs test case |
| * |
| * @param test_case_index Id of test case |
| * |
| * @return true if test case pass, false otherwise |
| **/ |
| bool NegativeTestBase::testCase(GLuint test_case_index) |
| { |
| bool test_case_result = true; |
| |
| /* Compute */ |
| if (true == isComputeRelevant(test_case_index)) |
| { |
| const std::string& cs_source = getShaderSource(test_case_index, Utils::Shader::COMPUTE); |
| bool is_build_error = false; |
| const bool is_failure_expected = isFailureExpected(test_case_index); |
| Utils::Program program(m_context); |
| |
| try |
| { |
| program.Init(cs_source, "" /* fs */, "" /* gs */, "" /* tcs */, "" /* tes */, "" /* vs */, |
| false /* separable */); |
| } |
| catch (Utils::Shader::InvalidSourceException& exc) |
| { |
| if (false == is_failure_expected) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Unexpected error in shader compilation: " << tcu::TestLog::EndMessage; |
| exc.log(m_context); |
| } |
| |
| #if DEBUG_NEG_LOG_ERROR |
| |
| else |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Error in shader compilation was expected, logged for verification: " |
| << tcu::TestLog::EndMessage; |
| exc.log(m_context); |
| } |
| |
| #endif /* DEBUG_NEG_LOG_ERROR */ |
| |
| is_build_error = true; |
| } |
| catch (Utils::Program::BuildException& exc) |
| { |
| if (false == is_failure_expected) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Unexpected error in program linking: " << tcu::TestLog::EndMessage; |
| exc.log(m_context); |
| } |
| |
| #if DEBUG_NEG_LOG_ERROR |
| |
| else |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message |
| << "Error in program linking was expected, logged for verification: " << tcu::TestLog::EndMessage; |
| exc.log(m_context); |
| } |
| |
| #endif /* DEBUG_NEG_LOG_ERROR */ |
| |
| is_build_error = true; |
| } |
| |
| if (is_build_error != is_failure_expected) |
| { |
| if (!is_build_error) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Unexpected success: " << tcu::TestLog::EndMessage; |
| Utils::Shader::LogSource(m_context, cs_source, Utils::Shader::COMPUTE); |
| } |
| test_case_result = false; |
| } |
| } |
| else /* Draw */ |
| { |
| const std::string& fs_source = getShaderSource(test_case_index, Utils::Shader::FRAGMENT); |
| const std::string& gs_source = getShaderSource(test_case_index, Utils::Shader::GEOMETRY); |
| bool is_build_error = false; |
| const bool is_failure_expected = isFailureExpected(test_case_index); |
| Utils::Program program(m_context); |
| const std::string& tcs_source = getShaderSource(test_case_index, Utils::Shader::TESS_CTRL); |
| const std::string& tes_source = getShaderSource(test_case_index, Utils::Shader::TESS_EVAL); |
| const std::string& vs_source = getShaderSource(test_case_index, Utils::Shader::VERTEX); |
| |
| try |
| { |
| if (isSeparable(test_case_index)) |
| { |
| program.Init("" /*cs*/, fs_source, "" /*gs_source*/, "" /*tcs_source*/, "" /*tes_source*/, |
| "" /*vs_source*/, true /* separable */); |
| program.Init("" /*cs*/, "" /*fs_source*/, gs_source, "" /*tcs_source*/, "" /*tes_source*/, |
| "" /*vs_source*/, true /* separable */); |
| program.Init("" /*cs*/, "" /*fs_source*/, "" /*gs_source*/, tcs_source, "" /*tes_source*/, |
| "" /*vs_source*/, true /* separable */); |
| program.Init("" /*cs*/, "" /*fs_source*/, "" /*gs_source*/, "" /*tcs_source*/, tes_source, |
| "" /*vs_source*/, true /* separable */); |
| program.Init("" /*cs*/, "" /*fs_source*/, "" /*gs_source*/, "" /*tcs_source*/, "" /*tes_source*/, |
| vs_source, true /* separable */); |
| } |
| else |
| { |
| program.Init("" /* cs */, fs_source, gs_source, tcs_source, tes_source, vs_source, |
| false /* separable */); |
| } |
| } |
| catch (Utils::Shader::InvalidSourceException& exc) |
| { |
| if (false == is_failure_expected) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Unexpected error in shader compilation: " << tcu::TestLog::EndMessage; |
| exc.log(m_context); |
| } |
| |
| #if DEBUG_NEG_LOG_ERROR |
| |
| else |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Error in shader compilation was expected, logged for verification: " |
| << tcu::TestLog::EndMessage; |
| exc.log(m_context); |
| } |
| |
| #endif /* DEBUG_NEG_LOG_ERROR */ |
| |
| is_build_error = true; |
| } |
| catch (Utils::Program::BuildException& exc) |
| { |
| if (false == is_failure_expected) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Unexpected error in program linking: " << tcu::TestLog::EndMessage; |
| exc.log(m_context); |
| } |
| |
| #if DEBUG_NEG_LOG_ERROR |
| |
| else |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message |
| << "Error in program linking was expected, logged for verification: " << tcu::TestLog::EndMessage; |
| exc.log(m_context); |
| } |
| |
| #endif /* DEBUG_NEG_LOG_ERROR */ |
| |
| is_build_error = true; |
| } |
| |
| if (is_build_error != is_failure_expected) |
| { |
| if (!is_build_error) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Unexpected success: " << tcu::TestLog::EndMessage; |
| Utils::Shader::LogSource(m_context, vs_source, Utils::Shader::VERTEX); |
| Utils::Shader::LogSource(m_context, tcs_source, Utils::Shader::TESS_CTRL); |
| Utils::Shader::LogSource(m_context, tes_source, Utils::Shader::TESS_EVAL); |
| Utils::Shader::LogSource(m_context, gs_source, Utils::Shader::GEOMETRY); |
| Utils::Shader::LogSource(m_context, fs_source, Utils::Shader::FRAGMENT); |
| } |
| test_case_result = false; |
| } |
| } |
| |
| return test_case_result; |
| } |
| |
| /* Constants used by TextureTestBase */ |
| const glw::GLuint TextureTestBase::m_width = 16; |
| const glw::GLuint TextureTestBase::m_height = 16; |
| |
| /** Constructor |
| * |
| * @param context Test context |
| * @param test_name Name of test |
| * @param test_description Description of test |
| **/ |
| TextureTestBase::TextureTestBase(deqp::Context& context, const GLchar* test_name, const GLchar* test_description) |
| : TestBase(context, test_name, test_description) |
| { |
| } |
| |
| /** Get locations for all inputs with automatic_location |
| * |
| * @param program Program object |
| * @param program_interface Interface of program |
| **/ |
| void TextureTestBase::prepareAttribLocation(Utils::Program& program, Utils::ProgramInterface& program_interface) |
| { |
| Utils::ShaderInterface& si = program_interface.GetShaderInterface(Utils::Shader::VERTEX); |
| |
| Utils::Variable::PtrVector& inputs = si.m_inputs; |
| |
| for (Utils::Variable::PtrVector::iterator it = inputs.begin(); inputs.end() != it; ++it) |
| { |
| /* Test does not specify location, query value and set */ |
| if (Utils::Variable::m_automatic_location == (*it)->m_descriptor.m_expected_location) |
| { |
| GLuint index = program.GetResourceIndex((*it)->m_descriptor.m_name, GL_PROGRAM_INPUT); |
| GLint location = 0; |
| |
| program.GetResource(GL_PROGRAM_INPUT, index, GL_LOCATION, 1 /* size */, &location); |
| |
| (*it)->m_descriptor.m_expected_location = location; |
| } |
| } |
| } |
| |
| /** Verifies contents of drawn image |
| * |
| * @param ignored |
| * @param color_0 Verified image |
| * |
| * @return true if image is filled with 1, false otherwise |
| **/ |
| bool TextureTestBase::checkResults(glw::GLuint /* test_case_index */, Utils::Texture& color_0) |
| { |
| static const GLuint size = m_width * m_height; |
| static const GLuint expected_color = 1; |
| |
| std::vector<GLuint> data; |
| data.resize(size); |
| |
| color_0.Get(GL_RED_INTEGER, GL_UNSIGNED_INT, &data[0]); |
| |
| for (GLuint i = 0; i < size; ++i) |
| { |
| const GLuint color = data[i]; |
| |
| if (expected_color != color) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "R32UI[" << i << "]:" << color |
| << tcu::TestLog::EndMessage; |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| /** Execute dispatch compute for 16x16x1 |
| * |
| * @param ignored |
| **/ |
| void TextureTestBase::executeDispatchCall(GLuint /* test_case_index */) |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| gl.dispatchCompute(16 /* x */, 16 /* y */, 1 /* z */); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute"); |
| } |
| |
| /** Execute drawArrays for single vertex |
| * |
| * @param ignored |
| **/ |
| void TextureTestBase::executeDrawCall(GLuint /* test_case_index */) |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| gl.drawArrays(GL_PATCHES, 0 /* first */, 1 /* count */); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays"); |
| } |
| |
| /** Prepare code snippet that will pass in variables to out variables |
| * |
| * @param ignored |
| * @param varying_passthrough Collection of connections between in and out variables |
| * @param stage Shader stage |
| * |
| * @return Code that pass in variables to next stage |
| **/ |
| std::string TextureTestBase::getPassSnippet(GLuint /* test_case_index */, |
| Utils::VaryingPassthrough& varying_passthrough, Utils::Shader::STAGES stage) |
| { |
| static const GLchar* separator = "\n "; |
| |
| /* Skip for compute shader */ |
| if (Utils::Shader::COMPUTE == stage) |
| { |
| return ""; |
| } |
| |
| Utils::VaryingConnection::Vector& vector = varying_passthrough.Get(stage); |
| |
| std::string result = Utils::g_list; |
| size_t position = 0; |
| |
| for (GLuint i = 0; i < vector.size(); ++i) |
| { |
| |
| Utils::VaryingConnection& connection = vector[i]; |
| |
| Utils::Variable* in = connection.m_in; |
| Utils::Variable* out = connection.m_out; |
| |
| Utils::Variable::FLAVOUR in_flavour = Utils::Variable::GetFlavour(stage, Utils::Variable::INPUT); |
| Utils::Variable::FLAVOUR out_flavour = Utils::Variable::GetFlavour(stage, Utils::Variable::OUTPUT); |
| |
| const std::string passthrough = |
| getVariablePassthrough("", in->m_descriptor, in_flavour, "", out->m_descriptor, out_flavour); |
| |
| Utils::insertElementOfList(passthrough.c_str(), separator, position, result); |
| } |
| |
| Utils::endList("", position, result); |
| |
| return result; |
| } |
| |
| /** Basic implementation of method getProgramInterface |
| * |
| * @param ignored |
| * @param ignored |
| * @param ignored |
| **/ |
| void TextureTestBase::getProgramInterface(GLuint /* test_case_index */, |
| Utils::ProgramInterface& /* program_interface */, |
| Utils::VaryingPassthrough& /* varying_passthrough */) |
| { |
| } |
| |
| /** Prepare code snippet that will verify in and uniform variables |
| * |
| * @param ignored |
| * @param program_interface Interface of program |
| * @param stage Shader stage |
| * |
| * @return Code that verify variables |
| **/ |
| std::string TextureTestBase::getVerificationSnippet(GLuint /* test_case_index */, |
| Utils::ProgramInterface& program_interface, |
| Utils::Shader::STAGES stage) |
| { |
| static const GLchar* separator = " ||\n "; |
| |
| std::string verification = "if (LIST)\n" |
| " {\n" |
| " result = 0u;\n" |
| " }\n"; |
| |
| /* Get flavour of in and out variables */ |
| Utils::Variable::FLAVOUR in_flavour = Utils::Variable::GetFlavour(stage, Utils::Variable::INPUT); |
| |
| /* Get interface for shader stage */ |
| Utils::ShaderInterface& si = program_interface.GetShaderInterface(stage); |
| |
| /* There are no varialbes to verify */ |
| if ((0 == si.m_inputs.size()) && (0 == si.m_uniforms.size()) && (0 == si.m_ssb_blocks.size())) |
| { |
| return ""; |
| } |
| |
| /* For each in variable insert verification code */ |
| size_t position = 0; |
| |
| for (GLuint i = 0; i < si.m_inputs.size(); ++i) |
| { |
| const Utils::Variable& var = *si.m_inputs[i]; |
| const std::string& var_verification = getVariableVerification("", var.m_data, var.m_descriptor, in_flavour); |
| |
| Utils::insertElementOfList(var_verification.c_str(), separator, position, verification); |
| } |
| |
| /* For each unifrom variable insert verification code */ |
| for (GLuint i = 0; i < si.m_uniforms.size(); ++i) |
| { |
| const Utils::Variable& var = *si.m_uniforms[i]; |
| const std::string& var_verification = |
| getVariableVerification("", var.m_data, var.m_descriptor, Utils::Variable::BASIC); |
| |
| Utils::insertElementOfList(var_verification.c_str(), separator, position, verification); |
| } |
| |
| /* For each ssb variable insert verification code */ |
| for (GLuint i = 0; i < si.m_ssb_blocks.size(); ++i) |
| { |
| const Utils::Variable& var = *si.m_ssb_blocks[i]; |
| const std::string& var_verification = |
| getVariableVerification("", var.m_data, var.m_descriptor, Utils::Variable::BASIC); |
| |
| Utils::insertElementOfList(var_verification.c_str(), separator, position, verification); |
| } |
| |
| Utils::endList("", position, verification); |
| |
| #if DEBUG_TTB_VERIFICATION_SNIPPET_STAGE |
| |
| { |
| GLchar buffer[16]; |
| sprintf(buffer, "%d", stage + 10); |
| Utils::replaceToken("0u", position, buffer, verification); |
| } |
| |
| #elif DEBUG_TTB_VERIFICATION_SNIPPET_VARIABLE |
| |
| if (Utils::Shader::VERTEX == stage) |
| { |
| Utils::replaceToken("0u", position, "in_vs_first.x", verification); |
| } |
| else |
| { |
| Utils::replaceToken("0u", position, "31u", verification); |
| } |
| |
| #endif |
| |
| /* Done */ |
| return verification; |
| } |
| |
| /** Selects if "compute" stage is relevant for test |
| * |
| * @param ignored |
| * |
| * @return true |
| **/ |
| bool TextureTestBase::isComputeRelevant(GLuint /* test_case_index */) |
| { |
| return true; |
| } |
| |
| /** Selects if "draw" stages are relevant for test |
| * |
| * @param ignored |
| * |
| * @return true |
| **/ |
| bool TextureTestBase::isDrawRelevant(GLuint /* test_case_index */) |
| { |
| return true; |
| } |
| |
| /** Prepare code that will do assignment of single in to single out |
| * |
| * @param in_parent_name Name of parent in variable |
| * @param in_variable Descriptor of in variable |
| * @param in_flavour Flavoud of in variable |
| * @param out_parent_name Name of parent out variable |
| * @param out_variable Descriptor of out variable |
| * @param out_flavour Flavoud of out variable |
| * |
| * @return Code that does OUT = IN |
| **/ |
| std::string TextureTestBase::getVariablePassthrough(const std::string& in_parent_name, |
| const Utils::Variable::Descriptor& in_variable, |
| Utils::Variable::FLAVOUR in_flavour, |
| const std::string& out_parent_name, |
| const Utils::Variable::Descriptor& out_variable, |
| Utils::Variable::FLAVOUR out_flavour) |
| { |
| bool done = false; |
| GLuint index = 0; |
| GLuint member_index = 0; |
| size_t position = 0; |
| std::string result = Utils::g_list; |
| static const GLchar* separator = ";\n "; |
| |
| /* For each member of each array element */ |
| do |
| { |
| const std::string in_name = Utils::Variable::GetReference(in_parent_name, in_variable, in_flavour, index); |
| const std::string out_name = Utils::Variable::GetReference(out_parent_name, out_variable, out_flavour, index); |
| std::string passthrough; |
| |
| /* Prepare verification */ |
| if (Utils::Variable::BUILTIN == in_variable.m_type) |
| { |
| size_t pass_position = 0; |
| |
| passthrough = "OUT = IN;"; |
| |
| Utils::replaceToken("OUT", pass_position, out_name.c_str(), passthrough); |
| Utils::replaceToken("IN", pass_position, in_name.c_str(), passthrough); |
| |
| /* Increment index */ |
| ++index; |
| } |
| else |
| { |
| const Utils::Interface* in_interface = in_variable.m_interface; |
| const Utils::Interface* out_interface = out_variable.m_interface; |
| |
| if ((0 == in_interface) || (0 == out_interface)) |
| { |
| TCU_FAIL("Nullptr"); |
| } |
| |
| const Utils::Variable::Descriptor& in_member = in_interface->m_members[member_index]; |
| const Utils::Variable::Descriptor& out_member = out_interface->m_members[member_index]; |
| |
| passthrough = getVariablePassthrough(in_name, in_member, Utils::Variable::BASIC, out_name, out_member, |
| Utils::Variable::BASIC); |
| |
| /* Increment member_index */ |
| ++member_index; |
| |
| /* Increment index and reset member_index if all members were processed */ |
| if (in_interface->m_members.size() == member_index) |
| { |
| ++index; |
| member_index = 0; |
| } |
| } |
| |
| /* Check if loop should end */ |
| if ((index >= in_variable.m_n_array_elements) && (0 == member_index)) |
| { |
| done = true; |
| } |
| |
| Utils::insertElementOfList(passthrough.c_str(), separator, position, result); |
| |
| } while (true != done); |
| |
| Utils::endList("", position, result); |
| |
| /* Done */ |
| return result; |
| } |
| |
| /** Get verification of single variable |
| * |
| * @param parent_name Name of parent variable |
| * @param data Data that should be used as EXPECTED |
| * @param variable Descriptor of variable |
| * @param flavour Flavour of variable |
| * |
| * @return Code that does (EXPECTED != VALUE) || |
| **/ |
| std::string TextureTestBase::getVariableVerification(const std::string& parent_name, const GLvoid* data, |
| const Utils::Variable::Descriptor& variable, |
| Utils::Variable::FLAVOUR flavour) |
| { |
| static const GLchar* logic_op = " ||\n "; |
| const GLuint n_elements = (0 == variable.m_n_array_elements) ? 1 : variable.m_n_array_elements; |
| size_t position = 0; |
| std::string result = Utils::g_list; |
| GLint stride = variable.m_expected_stride_of_element; |
| |
| /* For each each array element */ |
| for (GLuint element = 0; element < n_elements; ++element) |
| { |
| const std::string name = Utils::Variable::GetReference(parent_name, variable, flavour, element); |
| |
| /* Calculate data pointer */ |
| GLvoid* data_ptr = (GLvoid*)((GLubyte*)data + element * stride); |
| |
| /* Prepare verification */ |
| if (Utils::Variable::BUILTIN == variable.m_type) |
| { |
| const std::string& expected = variable.m_builtin.GetGLSLConstructor(data_ptr); |
| std::string verification; |
| size_t verification_position = 0; |
| |
| verification = "(EXPECTED != NAME)"; |
| |
| Utils::replaceToken("EXPECTED", verification_position, expected.c_str(), verification); |
| Utils::replaceToken("NAME", verification_position, name.c_str(), verification); |
| |
| Utils::insertElementOfList(verification.c_str(), logic_op, position, result); |
| } |
| else |
| { |
| const Utils::Interface* interface = variable.m_interface; |
| |
| if (0 == interface) |
| { |
| TCU_FAIL("Nullptr"); |
| } |
| |
| const GLuint n_members = static_cast<GLuint>(interface->m_members.size()); |
| |
| /* for each member */ |
| for (GLuint member_index = 0; member_index < n_members; ++member_index) |
| { |
| const Utils::Variable::Descriptor& member = interface->m_members[member_index]; |
| |
| /* Get verification of member */ |
| const std::string& verification = |
| getVariableVerification(name, (GLubyte*)data_ptr + member.m_offset, member, Utils::Variable::BASIC); |
| |
| Utils::insertElementOfList(verification.c_str(), logic_op, position, result); |
| } |
| } |
| } |
| |
| Utils::endList("", position, result); |
| |
| return result; |
| } |
| |
| /** Prepare attributes, vertex array object and array buffer |
| * |
| * @param test_case_index Index of test case |
| * @param program_interface Interface of program |
| * @param buffer Array buffer |
| * @param vao Vertex array object |
| **/ |
| void TextureTestBase::prepareAttributes(GLuint test_case_index, Utils::ProgramInterface& program_interface, |
| Utils::Buffer& buffer, Utils::VertexArray& vao) |
| { |
| const bool use_component_qualifier = useComponentQualifier(test_case_index); |
| |
| /* Get shader interface */ |
| const Utils::ShaderInterface& si = program_interface.GetShaderInterface(Utils::Shader::VERTEX); |
| |
| /* Bind vao and buffer */ |
| vao.Bind(); |
| buffer.Bind(); |
| |
| /* Skip if there are no input variables in vertex shader */ |
| if (0 == si.m_inputs.size()) |
| { |
| return; |
| } |
| |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Calculate vertex stride and check */ |
| GLint max_inputs; |
| gl.getIntegerv(GL_MAX_VERTEX_ATTRIBS, &max_inputs); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv"); |
| |
| /* dvec3/4 vertex inputs use a single location but require 2x16B slots */ |
| const GLuint max_slots = max_inputs * 2; |
| |
| /* Compute used slots */ |
| std::vector<GLuint> slot_sizes(max_slots, 0); |
| for (GLuint i = 0; i < si.m_inputs.size(); ++i) |
| { |
| const Utils::Variable& variable = *si.m_inputs[i]; |
| |
| const GLuint variable_size = static_cast<GLuint>(variable.m_data_size); |
| |
| const GLuint base_slot = variable.m_descriptor.m_expected_location + variable.m_descriptor.m_offset / 16; |
| const GLuint ends_at = variable.m_descriptor.m_offset % 16 + variable_size; |
| |
| const GLuint array_length = std::max(1u, variable.m_descriptor.m_n_array_elements); |
| for (GLuint loc = 0; loc < array_length; loc++) |
| { |
| const GLuint slot = base_slot + loc; |
| slot_sizes[slot] = std::max(slot_sizes[slot], ends_at); |
| } |
| } |
| |
| /* Compute the offsets where we need to put vertex buffer data for each slot */ |
| std::vector<GLint> slot_offsets(max_slots, -1); |
| GLuint buffer_size = 0; |
| for (GLuint i = 0; i < max_slots; i++) |
| { |
| if (slot_sizes[i] == 0) |
| continue; |
| slot_offsets[i] = buffer_size; |
| buffer_size += slot_sizes[i]; |
| } |
| |
| /* Prepare buffer data and set up vao */ |
| std::vector<GLubyte> buffer_data(buffer_size); |
| |
| GLubyte* ptr = &buffer_data[0]; |
| |
| for (GLuint i = 0; i < si.m_inputs.size(); ++i) |
| { |
| const Utils::Variable& variable = *si.m_inputs[i]; |
| |
| const GLuint base_slot = variable.m_descriptor.m_expected_location + variable.m_descriptor.m_offset / 16; |
| const GLuint variable_offset = variable.m_descriptor.m_offset % 16; |
| const GLuint array_length = std::max(1u, variable.m_descriptor.m_n_array_elements); |
| for (GLuint loc = 0; loc < array_length; loc++) |
| { |
| const GLuint slot = base_slot + loc; |
| memcpy(ptr + slot_offsets[slot] + variable_offset, variable.m_data, variable.m_data_size); |
| } |
| |
| if (!use_component_qualifier) |
| { |
| vao.Attribute(variable.m_descriptor.m_expected_location, variable.m_descriptor.m_builtin, |
| variable.m_descriptor.m_n_array_elements, variable.m_descriptor.m_normalized, |
| variable.GetStride(), (GLvoid*)(intptr_t)(slot_offsets[base_slot] + variable_offset)); |
| } |
| else if (0 == variable.m_descriptor.m_expected_component) |
| { |
| /* Components can only be applied to types not surpassing |
| * the bounds of a single slot. Therefore, we calculate |
| * the amount of used components in the varying based on |
| * the calculated slot sizes. |
| */ |
| const GLuint n_component_size = Utils::Type::Double == variable.m_descriptor.m_builtin.m_basic_type ? 8 : 4; |
| const GLuint n_rows = slot_sizes[base_slot] / n_component_size; |
| |
| const Utils::Type& type = Utils::Type::GetType(variable.m_descriptor.m_builtin.m_basic_type, |
| 1 /* n_columns */, n_rows /* n_rows */); |
| |
| vao.Attribute(variable.m_descriptor.m_expected_location, type, variable.m_descriptor.m_n_array_elements, |
| variable.m_descriptor.m_normalized, variable.GetStride(), |
| (GLvoid*)(intptr_t)(slot_offsets[base_slot] + variable_offset)); |
| } |
| } |
| |
| /* Update buffer */ |
| buffer.Data(Utils::Buffer::StaticDraw, buffer_size, ptr); |
| } |
| |
| /** Get locations for all outputs with automatic_location |
| * |
| * @param program Program object |
| * @param program_interface Interface of program |
| **/ |
| void TextureTestBase::prepareFragmentDataLoc(Utils::Program& program, Utils::ProgramInterface& program_interface) |
| { |
| Utils::ShaderInterface& si = program_interface.GetShaderInterface(Utils::Shader::FRAGMENT); |
| Utils::Variable::PtrVector& outputs = si.m_outputs; |
| |
| for (Utils::Variable::PtrVector::iterator it = outputs.begin(); outputs.end() != it; ++it) |
| { |
| /* Test does not specify location, query value and set */ |
| if (Utils::Variable::m_automatic_location == (*it)->m_descriptor.m_expected_location) |
| { |
| GLuint index = program.GetResourceIndex((*it)->m_descriptor.m_name, GL_PROGRAM_OUTPUT); |
| GLint location = 0; |
| |
| program.GetResource(GL_PROGRAM_OUTPUT, index, GL_LOCATION, 1 /* size */, &location); |
| |
| (*it)->m_descriptor.m_expected_location = location; |
| } |
| } |
| } |
| |
| /** Prepare framebuffer with single texture as color attachment |
| * |
| * @param framebuffer Framebuffer |
| * @param color_0_texture Texture that will used as color attachment |
| **/ |
| void TextureTestBase::prepareFramebuffer(Utils::Framebuffer& framebuffer, Utils::Texture& color_0_texture) |
| { |
| /* Prepare data */ |
| std::vector<GLuint> texture_data; |
| texture_data.resize(m_width * m_height); |
| |
| for (GLuint i = 0; i < texture_data.size(); ++i) |
| { |
| texture_data[i] = 0x20406080; |
| } |
| |
| /* Prepare texture */ |
| color_0_texture.Init(Utils::Texture::TEX_2D, m_width, m_height, 0, GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT, |
| &texture_data[0]); |
| |
| /* Prepare framebuffer */ |
| framebuffer.Init(); |
| framebuffer.Bind(); |
| framebuffer.AttachTexture(GL_COLOR_ATTACHMENT0, color_0_texture.m_id, m_width, m_height); |
| |
| framebuffer.ClearColor(0.0f, 0.0f, 0.0f, 0.0f); |
| framebuffer.Clear(GL_COLOR_BUFFER_BIT); |
| } |
| |
| /** Prepare iamge unit for compute shader |
| * |
| * @param location Uniform location |
| * @param image_texture Texture that will used as color attachment |
| **/ |
| void TextureTestBase::prepareImage(GLint location, Utils::Texture& image_texture) const |
| { |
| static const GLuint image_unit = 0; |
| |
| std::vector<GLuint> texture_data; |
| texture_data.resize(m_width * m_height); |
| |
| for (GLuint i = 0; i < texture_data.size(); ++i) |
| { |
| texture_data[i] = 0x20406080; |
| } |
| |
| image_texture.Init(Utils::Texture::TEX_2D, m_width, m_height, 0, GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT, |
| &texture_data[0]); |
| |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| gl.bindImageTexture(image_unit, image_texture.m_id, 0 /* level */, GL_FALSE /* layered */, 0 /* Layer */, |
| GL_WRITE_ONLY, GL_R32UI); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture"); |
| |
| Utils::Program::Uniform(gl, Utils::Type::_int, 1 /* count */, location, &image_unit); |
| } |
| |
| /** Basic implementation |
| * |
| * @param ignored |
| * @param si Shader interface |
| * @param program Program |
| * @param cs_buffer Buffer for ssb blocks |
| **/ |
| void TextureTestBase::prepareSSBs(GLuint /* test_case_index */, Utils::ShaderInterface& si, Utils::Program& program, |
| Utils::Buffer& buffer) |
| { |
| /* Skip if there are no input variables in vertex shader */ |
| if (0 == si.m_ssb_blocks.size()) |
| { |
| return; |
| } |
| |
| /* Calculate vertex stride */ |
| GLint ssbs_stride = 0; |
| |
| for (GLuint i = 0; i < si.m_ssb_blocks.size(); ++i) |
| { |
| Utils::Variable& variable = *si.m_ssb_blocks[i]; |
| |
| if (false == variable.IsBlock()) |
| { |
| continue; |
| } |
| |
| GLint variable_stride = variable.GetStride(); |
| |
| GLint ends_at = variable_stride + variable.m_descriptor.m_offset; |
| |
| ssbs_stride = std::max(ssbs_stride, ends_at); |
| } |
| |
| /* Set active program */ |
| program.Use(); |
| |
| /* Allocate */ |
| buffer.Bind(); |
| buffer.Data(Utils::Buffer::StaticDraw, ssbs_stride, 0); |
| |
| /* Set up uniforms */ |
| for (GLuint i = 0; i < si.m_ssb_blocks.size(); ++i) |
| { |
| Utils::Variable& variable = *si.m_ssb_blocks[i]; |
| |
| /* prepareUnifor should work fine for ssb blocks */ |
| prepareUniform(program, variable, buffer); |
| } |
| } |
| |
| /** Basic implementation |
| * |
| * @param test_case_index Test case index |
| * @param program_interface Program interface |
| * @param program Program |
| * @param cs_buffer Buffer for compute shader stage |
| **/ |
| void TextureTestBase::prepareSSBs(GLuint test_case_index, Utils::ProgramInterface& program_interface, |
| Utils::Program& program, Utils::Buffer& cs_buffer) |
| { |
| cs_buffer.Init(Utils::Buffer::Shader_Storage, Utils::Buffer::StaticDraw, 0, 0); |
| |
| Utils::ShaderInterface& cs = program_interface.GetShaderInterface(Utils::Shader::COMPUTE); |
| |
| prepareSSBs(test_case_index, cs, program, cs_buffer); |
| |
| cs_buffer.BindBase(Utils::Shader::COMPUTE); |
| } |
| |
| /** Basic implementation |
| * |
| * @param test_case_index Test case index |
| * @param program_interface Program interface |
| * @param program Program |
| * @param fs_buffer Buffer for fragment shader stage |
| * @param gs_buffer Buffer for geometry shader stage |
| * @param tcs_buffer Buffer for tessellation control shader stage |
| * @param tes_buffer Buffer for tessellation evaluation shader stage |
| * @param vs_buffer Buffer for vertex shader stage |
| **/ |
| void TextureTestBase::prepareSSBs(GLuint test_case_index, Utils::ProgramInterface& program_interface, |
| Utils::Program& program, Utils::Buffer& fs_buffer, Utils::Buffer& gs_buffer, |
| Utils::Buffer& tcs_buffer, Utils::Buffer& tes_buffer, Utils::Buffer& vs_buffer) |
| { |
| fs_buffer.Init(Utils::Buffer::Shader_Storage, Utils::Buffer::StaticDraw, 0, 0); |
| gs_buffer.Init(Utils::Buffer::Shader_Storage, Utils::Buffer::StaticDraw, 0, 0); |
| tcs_buffer.Init(Utils::Buffer::Shader_Storage, Utils::Buffer::StaticDraw, 0, 0); |
| tes_buffer.Init(Utils::Buffer::Shader_Storage, Utils::Buffer::StaticDraw, 0, 0); |
| vs_buffer.Init(Utils::Buffer::Shader_Storage, Utils::Buffer::StaticDraw, 0, 0); |
| |
| Utils::ShaderInterface& fs = program_interface.GetShaderInterface(Utils::Shader::FRAGMENT); |
| Utils::ShaderInterface& gs = program_interface.GetShaderInterface(Utils::Shader::GEOMETRY); |
| Utils::ShaderInterface& tcs = program_interface.GetShaderInterface(Utils::Shader::TESS_CTRL); |
| Utils::ShaderInterface& tes = program_interface.GetShaderInterface(Utils::Shader::TESS_EVAL); |
| Utils::ShaderInterface& vs = program_interface.GetShaderInterface(Utils::Shader::VERTEX); |
| |
| prepareSSBs(test_case_index, fs, program, fs_buffer); |
| prepareSSBs(test_case_index, gs, program, gs_buffer); |
| prepareSSBs(test_case_index, tcs, program, tcs_buffer); |
| prepareSSBs(test_case_index, tes, program, tes_buffer); |
| prepareSSBs(test_case_index, vs, program, vs_buffer); |
| |
| fs_buffer.BindBase(Utils::Shader::FRAGMENT); |
| gs_buffer.BindBase(Utils::Shader::GEOMETRY); |
| tcs_buffer.BindBase(Utils::Shader::TESS_CTRL); |
| tes_buffer.BindBase(Utils::Shader::TESS_EVAL); |
| vs_buffer.BindBase(Utils::Shader::VERTEX); |
| } |
| |
| /** Updates buffer data with variable |
| * |
| * @param program Program object |
| * @param variable Variable |
| * @param buffer Buffer |
| **/ |
| void TextureTestBase::prepareUniform(Utils::Program& program, Utils::Variable& variable, Utils::Buffer& buffer) |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| GLsizei count = variable.m_descriptor.m_n_array_elements; |
| if (0 == count) |
| { |
| count = 1; |
| } |
| |
| if (Utils::Variable::BUILTIN == variable.m_descriptor.m_type) |
| { |
| program.Uniform(gl, variable.m_descriptor.m_builtin, count, variable.m_descriptor.m_expected_location, |
| variable.m_data); |
| } |
| else |
| { |
| const bool is_block = variable.IsBlock(); |
| |
| if (false == is_block) |
| { |
| TCU_FAIL("Not implemented"); |
| } |
| else |
| { |
| buffer.SubData(variable.m_descriptor.m_offset, variable.m_descriptor.m_expected_stride_of_element * count, |
| variable.m_data); |
| } |
| } |
| } |
| |
| /** Basic implementation |
| * |
| * @param ignored |
| * @param si Shader interface |
| * @param program Program |
| * @param cs_buffer Buffer for uniform blocks |
| **/ |
| void TextureTestBase::prepareUniforms(GLuint /* test_case_index */, Utils::ShaderInterface& si, Utils::Program& program, |
| Utils::Buffer& buffer) |
| { |
| /* Skip if there are no input variables in vertex shader */ |
| if (0 == si.m_uniforms.size()) |
| { |
| return; |
| } |
| |
| /* Calculate vertex stride */ |
| GLint uniforms_stride = 0; |
| |
| for (GLuint i = 0; i < si.m_uniforms.size(); ++i) |
| { |
| Utils::Variable& variable = *si.m_uniforms[i]; |
| |
| if (false == variable.IsBlock()) |
| { |
| continue; |
| } |
| |
| GLint variable_stride = variable.GetStride(); |
| |
| GLint ends_at = variable_stride + variable.m_descriptor.m_offset; |
| |
| uniforms_stride = std::max(uniforms_stride, ends_at); |
| } |
| |
| /* Set active program */ |
| program.Use(); |
| |
| /* Allocate */ |
| buffer.Bind(); |
| buffer.Data(Utils::Buffer::StaticDraw, uniforms_stride, 0); |
| |
| /* Set up uniforms */ |
| for (GLuint i = 0; i < si.m_uniforms.size(); ++i) |
| { |
| Utils::Variable& variable = *si.m_uniforms[i]; |
| |
| prepareUniform(program, variable, buffer); |
| } |
| } |
| |
| /** Basic implementation |
| * |
| * @param test_case_index Test case index |
| * @param program_interface Program interface |
| * @param program Program |
| * @param cs_buffer Buffer for compute shader stage |
| **/ |
| void TextureTestBase::prepareUniforms(GLuint test_case_index, Utils::ProgramInterface& program_interface, |
| Utils::Program& program, Utils::Buffer& cs_buffer) |
| { |
| cs_buffer.Init(Utils::Buffer::Uniform, Utils::Buffer::StaticDraw, 0, 0); |
| |
| Utils::ShaderInterface& cs = program_interface.GetShaderInterface(Utils::Shader::COMPUTE); |
| |
| prepareUniforms(test_case_index, cs, program, cs_buffer); |
| |
| cs_buffer.BindBase(Utils::Shader::COMPUTE); |
| } |
| |
| /** Basic implementation |
| * |
| * @param test_case_index Test case index |
| * @param program_interface Program interface |
| * @param program Program |
| * @param fs_buffer Buffer for fragment shader stage |
| * @param gs_buffer Buffer for geometry shader stage |
| * @param tcs_buffer Buffer for tessellation control shader stage |
| * @param tes_buffer Buffer for tessellation evaluation shader stage |
| * @param vs_buffer Buffer for vertex shader stage |
| **/ |
| void TextureTestBase::prepareUniforms(GLuint test_case_index, Utils::ProgramInterface& program_interface, |
| Utils::Program& program, Utils::Buffer& fs_buffer, Utils::Buffer& gs_buffer, |
| Utils::Buffer& tcs_buffer, Utils::Buffer& tes_buffer, Utils::Buffer& vs_buffer) |
| { |
| fs_buffer.Init(Utils::Buffer::Uniform, Utils::Buffer::StaticDraw, 0, 0); |
| gs_buffer.Init(Utils::Buffer::Uniform, Utils::Buffer::StaticDraw, 0, 0); |
| tcs_buffer.Init(Utils::Buffer::Uniform, Utils::Buffer::StaticDraw, 0, 0); |
| tes_buffer.Init(Utils::Buffer::Uniform, Utils::Buffer::StaticDraw, 0, 0); |
| vs_buffer.Init(Utils::Buffer::Uniform, Utils::Buffer::StaticDraw, 0, 0); |
| |
| Utils::ShaderInterface& fs = program_interface.GetShaderInterface(Utils::Shader::FRAGMENT); |
| Utils::ShaderInterface& gs = program_interface.GetShaderInterface(Utils::Shader::GEOMETRY); |
| Utils::ShaderInterface& tcs = program_interface.GetShaderInterface(Utils::Shader::TESS_CTRL); |
| Utils::ShaderInterface& tes = program_interface.GetShaderInterface(Utils::Shader::TESS_EVAL); |
| Utils::ShaderInterface& vs = program_interface.GetShaderInterface(Utils::Shader::VERTEX); |
| |
| prepareUniforms(test_case_index, fs, program, fs_buffer); |
| prepareUniforms(test_case_index, gs, program, gs_buffer); |
| prepareUniforms(test_case_index, tcs, program, tcs_buffer); |
| prepareUniforms(test_case_index, tes, program, tes_buffer); |
| prepareUniforms(test_case_index, vs, program, vs_buffer); |
| |
| fs_buffer.BindBase(Utils::Shader::FRAGMENT); |
| gs_buffer.BindBase(Utils::Shader::GEOMETRY); |
| tcs_buffer.BindBase(Utils::Shader::TESS_CTRL); |
| tes_buffer.BindBase(Utils::Shader::TESS_EVAL); |
| vs_buffer.BindBase(Utils::Shader::VERTEX); |
| } |
| |
| /** Basic implementation |
| * |
| * @param test_case_index Test case index |
| * @param program_interface Program interface |
| * @param program Program |
| * @param fs_buffer Buffer for fragment shader stage |
| * @param gs_buffer Buffer for geometry shader stage |
| * @param tcs_buffer Buffer for tessellation control shader stage |
| * @param tes_buffer Buffer for tessellation evaluation shader stage |
| * @param vs_buffer Buffer for vertex shader stage |
| **/ |
| void TextureTestBase::prepareUniforms(GLuint test_case_index, Utils::ProgramInterface& program_interface, |
| Utils::Program& fs_program, Utils::Program& gs_program, |
| Utils::Program& tcs_program, Utils::Program& tes_program, |
| Utils::Program& vs_program, Utils::Buffer& fs_buffer, Utils::Buffer& gs_buffer, |
| Utils::Buffer& tcs_buffer, Utils::Buffer& tes_buffer, Utils::Buffer& vs_buffer) |
| { |
| fs_buffer.Init(Utils::Buffer::Uniform, Utils::Buffer::StaticDraw, 0, 0); |
| gs_buffer.Init(Utils::Buffer::Uniform, Utils::Buffer::StaticDraw, 0, 0); |
| tcs_buffer.Init(Utils::Buffer::Uniform, Utils::Buffer::StaticDraw, 0, 0); |
| tes_buffer.Init(Utils::Buffer::Uniform, Utils::Buffer::StaticDraw, 0, 0); |
| vs_buffer.Init(Utils::Buffer::Uniform, Utils::Buffer::StaticDraw, 0, 0); |
| |
| Utils::ShaderInterface& fs = program_interface.GetShaderInterface(Utils::Shader::FRAGMENT); |
| Utils::ShaderInterface& gs = program_interface.GetShaderInterface(Utils::Shader::GEOMETRY); |
| Utils::ShaderInterface& tcs = program_interface.GetShaderInterface(Utils::Shader::TESS_CTRL); |
| Utils::ShaderInterface& tes = program_interface.GetShaderInterface(Utils::Shader::TESS_EVAL); |
| Utils::ShaderInterface& vs = program_interface.GetShaderInterface(Utils::Shader::VERTEX); |
| |
| prepareUniforms(test_case_index, fs, fs_program, fs_buffer); |
| fs_buffer.BindBase(Utils::Shader::FRAGMENT); |
| |
| prepareUniforms(test_case_index, gs, gs_program, gs_buffer); |
| gs_buffer.BindBase(Utils::Shader::GEOMETRY); |
| |
| prepareUniforms(test_case_index, tcs, tcs_program, tcs_buffer); |
| tcs_buffer.BindBase(Utils::Shader::TESS_CTRL); |
| |
| prepareUniforms(test_case_index, tes, tes_program, tes_buffer); |
| tes_buffer.BindBase(Utils::Shader::TESS_EVAL); |
| |
| prepareUniforms(test_case_index, vs, vs_program, vs_buffer); |
| vs_buffer.BindBase(Utils::Shader::VERTEX); |
| } |
| |
| /** Prepare source for shader |
| * |
| * @param test_case_index Index of test case |
| * @param program_interface Interface of program |
| * @param varying_passthrough Collection of connection between in and out variables |
| * @param stage Shader stage |
| * |
| * @return Source of shader |
| **/ |
| std::string TextureTestBase::getShaderSource(GLuint test_case_index, Utils::ProgramInterface& program_interface, |
| Utils::VaryingPassthrough& varying_passthrough, |
| Utils::Shader::STAGES stage) |
| { |
| /* Get strings */ |
| const GLchar* shader_template = getShaderTemplate(stage); |
| glu::GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType()); |
| const char* shader_version = glu::getGLSLVersionDeclaration(glslVersion); |
| const std::string& shader_interface = program_interface.GetInterfaceForStage(stage); |
| const std::string& verification = getVerificationSnippet(test_case_index, program_interface, stage); |
| const std::string& passthrough = getPassSnippet(test_case_index, varying_passthrough, stage); |
| |
| const GLchar* per_vertex = ""; |
| |
| std::string source = shader_template; |
| size_t position = 0; |
| |
| Utils::replaceToken("VERSION", position, shader_version, source); |
| |
| /* Replace tokens in template */ |
| if (Utils::Shader::GEOMETRY == stage) |
| { |
| if (false == useMonolithicProgram(test_case_index)) |
| { |
| per_vertex = "out gl_PerVertex {\n" |
| "vec4 gl_Position;\n" |
| "};\n" |
| "\n"; |
| } |
| |
| Utils::replaceToken("PERVERTEX", position, per_vertex, source); |
| } |
| |
| Utils::replaceToken("INTERFACE", position, shader_interface.c_str(), source); |
| Utils::replaceToken("VERIFICATION", position, verification.c_str(), source); |
| |
| if (false == verification.empty()) |
| { |
| Utils::replaceAllTokens("ELSE", " else ", source); |
| } |
| else |
| { |
| Utils::replaceAllTokens("ELSE", "", source); |
| } |
| |
| Utils::replaceAllTokens("PASSTHROUGH", passthrough.c_str(), source); |
| |
| /* Done */ |
| return source; |
| } |
| |
| /** Returns template of shader for given stage |
| * |
| * @param stage Shade stage |
| * |
| * @return Proper template |
| **/ |
| const GLchar* TextureTestBase::getShaderTemplate(Utils::Shader::STAGES stage) |
| { |
| |
| static const GLchar* compute_shader_template = |
| "VERSION\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n" |
| "\n" |
| "writeonly uniform uimage2D uni_image;\n" |
| "\n" |
| "INTERFACE" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " uint result = 1u;\n" |
| "\n" |
| " VERIFICATION" |
| "\n" |
| " imageStore(uni_image, ivec2(gl_GlobalInvocationID.xy), uvec4(result, 0, 0, 0));\n" |
| "}\n" |
| "\n"; |
| |
| static const GLchar* fragment_shader_template = "VERSION\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "flat in uint gs_fs_result;\n" |
| " out uint fs_out_result;\n" |
| "\n" |
| "INTERFACE" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " uint result = 1u;\n" |
| "\n" |
| " if (1u != gs_fs_result)\n" |
| " {\n" |
| " result = gs_fs_result;\n" |
| " }\n" |
| "ELSEVERIFICATION" |
| "\n" |
| " fs_out_result = result;\n" |
| " PASSTHROUGH\n" |
| "}\n" |
| "\n"; |
| |
| static const GLchar* geometry_shader_template = |
| "VERSION\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| " in uint tes_gs_result[];\n" |
| " flat out uint gs_fs_result;\n" |
| "\n" |
| "PERVERTEX" /* Separable programs require explicit declaration of gl_PerVertex */ |
| "INTERFACE" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " uint result = 1u;\n" |
| "\n" |
| " if (1u != tes_gs_result[0])\n" |
| " {\n" |
| " result = tes_gs_result[0];\n" |
| " }\n" |
| "ELSEVERIFICATION" |
| "\n" |
| " gs_fs_result = result;\n" |
| " PASSTHROUGH\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs_result = result;\n" |
| " PASSTHROUGH\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs_result = result;\n" |
| " PASSTHROUGH\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs_result = result;\n" |
| " PASSTHROUGH\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| |
| static const GLchar* tess_ctrl_shader_template = "VERSION\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "in uint vs_tcs_result[];\n" |
| "out uint tcs_tes_result[];\n" |
| "\n" |
| "INTERFACE" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " uint result = 1u;\n" |
| "\n" |
| " if (1u != vs_tcs_result[gl_InvocationID])\n" |
| " {\n" |
| " result = vs_tcs_result[gl_InvocationID];\n" |
| " }\n" |
| "ELSEVERIFICATION" |
| "\n" |
| " tcs_tes_result[gl_InvocationID] = result;\n" |
| "\n" |
| " PASSTHROUGH\n" |
| "\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| |
| static const GLchar* tess_eval_shader_template = "VERSION\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(isolines, point_mode) in;\n" |
| "\n" |
| "in uint tcs_tes_result[];\n" |
| "out uint tes_gs_result;\n" |
| "\n" |
| "INTERFACE" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " uint result = 1u;\n" |
| "\n" |
| " if (1u != tcs_tes_result[0])\n" |
| " {\n" |
| " result = tcs_tes_result[0];\n" |
| " }\n" |
| "ELSEVERIFICATION" |
| "\n" |
| " tes_gs_result = result;\n" |
| "\n" |
| " PASSTHROUGH\n" |
| "}\n" |
| "\n"; |
| |
| static const GLchar* vertex_shader_template = "VERSION\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "out uint vs_tcs_result;\n" |
| "\n" |
| "INTERFACE" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " uint result = 1u;\n" |
| "\n" |
| " VERIFICATION\n" |
| "\n" |
| " vs_tcs_result = result;\n" |
| "\n" |
| " PASSTHROUGH\n" |
| "}\n" |
| "\n"; |
| |
| const GLchar* result = 0; |
| |
| switch (stage) |
| { |
| case Utils::Shader::COMPUTE: |
| result = compute_shader_template; |
| break; |
| case Utils::Shader::FRAGMENT: |
| result = fragment_shader_template; |
| break; |
| case Utils::Shader::GEOMETRY: |
| result = geometry_shader_template; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| result = tess_ctrl_shader_template; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| result = tess_eval_shader_template; |
| break; |
| case Utils::Shader::VERTEX: |
| result = vertex_shader_template; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| return result; |
| } |
| |
| /** Runs test case |
| * |
| * @param test_case_index Id of test case |
| * |
| * @return true if test case pass, false otherwise |
| **/ |
| bool TextureTestBase::testCase(GLuint test_case_index) |
| { |
| try |
| { |
| if (true == useMonolithicProgram(test_case_index)) |
| { |
| return testMonolithic(test_case_index); |
| } |
| else |
| { |
| return testSeparable(test_case_index); |
| } |
| } |
| catch (Utils::Shader::InvalidSourceException& exc) |
| { |
| exc.log(m_context); |
| TCU_FAIL(exc.what()); |
| } |
| catch (Utils::Program::BuildException& exc) |
| { |
| exc.log(m_context); |
| TCU_FAIL(exc.what()); |
| } |
| } |
| |
| /** Runs "draw" test with monolithic program |
| * |
| * @param test_case_index Id of test case |
| **/ |
| bool TextureTestBase::testMonolithic(GLuint test_case_index) |
| { |
| Utils::ProgramInterface program_interface; |
| Utils::VaryingPassthrough varying_passthrough; |
| |
| /* */ |
| const std::string& test_name = getTestCaseName(test_case_index); |
| |
| /* */ |
| getProgramInterface(test_case_index, program_interface, varying_passthrough); |
| |
| bool result = true; |
| /* Draw */ |
| if (true == isDrawRelevant(test_case_index)) |
| { |
| Utils::Buffer buffer_attr(m_context); |
| Utils::Buffer buffer_ssb_fs(m_context); |
| Utils::Buffer buffer_ssb_gs(m_context); |
| Utils::Buffer buffer_ssb_tcs(m_context); |
| Utils::Buffer buffer_ssb_tes(m_context); |
| Utils::Buffer buffer_ssb_vs(m_context); |
| Utils::Buffer buffer_u_fs(m_context); |
| Utils::Buffer buffer_u_gs(m_context); |
| Utils::Buffer buffer_u_tcs(m_context); |
| Utils::Buffer buffer_u_tes(m_context); |
| Utils::Buffer buffer_u_vs(m_context); |
| Utils::Framebuffer framebuffer(m_context); |
| Utils::Program program(m_context); |
| Utils::Texture texture_fb(m_context); |
| Utils::VertexArray vao(m_context); |
| |
| /* */ |
| const std::string& fragment_shader = |
| getShaderSource(test_case_index, program_interface, varying_passthrough, Utils::Shader::FRAGMENT); |
| const std::string& geometry_shader = |
| getShaderSource(test_case_index, program_interface, varying_passthrough, Utils::Shader::GEOMETRY); |
| const std::string& tess_ctrl_shader = |
| getShaderSource(test_case_index, program_interface, varying_passthrough, Utils::Shader::TESS_CTRL); |
| const std::string& tess_eval_shader = |
| getShaderSource(test_case_index, program_interface, varying_passthrough, Utils::Shader::TESS_EVAL); |
| const std::string& vertex_shader = |
| getShaderSource(test_case_index, program_interface, varying_passthrough, Utils::Shader::VERTEX); |
| |
| program.Init("" /* compute_shader */, fragment_shader, geometry_shader, tess_ctrl_shader, tess_eval_shader, |
| vertex_shader, false /* is_separable */); |
| |
| /* */ |
| prepareAttribLocation(program, program_interface); |
| prepareFragmentDataLoc(program, program_interface); |
| |
| /* */ |
| std::stringstream stream; |
| if (false == Utils::checkMonolithicDrawProgramInterface(program, program_interface, stream)) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "FAILURE. Test case: " << test_name |
| << ". Inspection of draw program interface failed:\n" |
| << stream.str() << tcu::TestLog::EndMessage << tcu::TestLog::KernelSource(vertex_shader) |
| << tcu::TestLog::KernelSource(tess_ctrl_shader) << tcu::TestLog::KernelSource(tess_eval_shader) |
| << tcu::TestLog::KernelSource(geometry_shader) << tcu::TestLog::KernelSource(fragment_shader); |
| |
| return false; |
| } |
| |
| /* */ |
| program.Use(); |
| |
| /* */ |
| buffer_attr.Init(Utils::Buffer::Array, Utils::Buffer::StaticDraw, 0, 0); |
| vao.Init(); |
| prepareAttributes(test_case_index, program_interface, buffer_attr, vao); |
| |
| /* */ |
| prepareUniforms(test_case_index, program_interface, program, buffer_u_fs, buffer_u_gs, buffer_u_tcs, |
| buffer_u_tes, buffer_u_vs); |
| |
| prepareSSBs(test_case_index, program_interface, program, buffer_ssb_fs, buffer_ssb_gs, buffer_ssb_tcs, |
| buffer_ssb_tes, buffer_ssb_vs); |
| |
| /* */ |
| prepareFramebuffer(framebuffer, texture_fb); |
| |
| /* Draw */ |
| executeDrawCall(test_case_index); |
| |
| #if USE_NSIGHT |
| m_context.getRenderContext().postIterate(); |
| #endif |
| |
| /* Check results */ |
| if (false == checkResults(test_case_index, texture_fb)) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "FAILURE. Test case: " << test_name << ". Draw - invalid results." |
| << tcu::TestLog::EndMessage << tcu::TestLog::KernelSource(vertex_shader) |
| << tcu::TestLog::KernelSource(tess_ctrl_shader) << tcu::TestLog::KernelSource(tess_eval_shader) |
| << tcu::TestLog::KernelSource(geometry_shader) << tcu::TestLog::KernelSource(fragment_shader); |
| |
| result = false; |
| } |
| } |
| |
| /* Compute */ |
| if (true == isComputeRelevant(test_case_index)) |
| { |
| Utils::Buffer buffer_ssb_cs(m_context); |
| Utils::Buffer buffer_u_cs(m_context); |
| Utils::Program program(m_context); |
| Utils::Texture texture_im(m_context); |
| Utils::VertexArray vao(m_context); |
| |
| /* */ |
| const std::string& compute_shader = |
| getShaderSource(test_case_index, program_interface, varying_passthrough, Utils::Shader::COMPUTE); |
| |
| program.Init(compute_shader, "" /* fragment_shader */, "" /* geometry_shader */, "" /* tess_ctrl_shader */, |
| "" /* tess_eval_shader */, "" /* vertex_shader */, false /* is_separable */); |
| |
| /* */ |
| { |
| std::stringstream stream; |
| |
| if (false == Utils::checkMonolithicComputeProgramInterface(program, program_interface, stream)) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "FAILURE. Test case: " << test_name |
| << ". Inspection of compute program interface failed:\n" |
| << stream.str() << tcu::TestLog::EndMessage; |
| |
| return false; |
| } |
| } |
| |
| /* */ |
| program.Use(); |
| |
| /* */ |
| vao.Init(); |
| vao.Bind(); |
| |
| /* */ |
| prepareUniforms(test_case_index, program_interface, program, buffer_u_cs); |
| |
| prepareSSBs(test_case_index, program_interface, program, buffer_ssb_cs); |
| |
| /* */ |
| GLint image_location = program.GetUniformLocation("uni_image"); |
| prepareImage(image_location, texture_im); |
| |
| /* Draw */ |
| executeDispatchCall(test_case_index); |
| |
| #if USE_NSIGHT |
| m_context.getRenderContext().postIterate(); |
| #endif |
| |
| /* Check results */ |
| if (false == checkResults(test_case_index, texture_im)) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "FAILURE. Test case: " << test_name |
| << ". Compute - invalid results." << tcu::TestLog::EndMessage |
| << tcu::TestLog::KernelSource(compute_shader); |
| |
| result = false; |
| } |
| } |
| |
| return result; |
| } |
| |
| /** Runs "draw" test with separable program |
| * |
| * @param test_case_index Id of test case |
| **/ |
| bool TextureTestBase::testSeparable(GLuint test_case_index) |
| { |
| Utils::ProgramInterface program_interface; |
| Utils::VaryingPassthrough varying_passthrough; |
| |
| /* */ |
| const std::string& test_name = getTestCaseName(test_case_index); |
| |
| /* */ |
| getProgramInterface(test_case_index, program_interface, varying_passthrough); |
| |
| bool result = true; |
| /* Draw */ |
| if (true == isDrawRelevant(test_case_index)) |
| { |
| Utils::Buffer buffer_attr(m_context); |
| Utils::Buffer buffer_u_fs(m_context); |
| Utils::Buffer buffer_u_gs(m_context); |
| Utils::Buffer buffer_u_tcs(m_context); |
| Utils::Buffer buffer_u_tes(m_context); |
| Utils::Buffer buffer_u_vs(m_context); |
| Utils::Framebuffer framebuffer(m_context); |
| Utils::Pipeline pipeline(m_context); |
| Utils::Program program_fs(m_context); |
| Utils::Program program_gs(m_context); |
| Utils::Program program_tcs(m_context); |
| Utils::Program program_tes(m_context); |
| Utils::Program program_vs(m_context); |
| Utils::Texture texture_fb(m_context); |
| Utils::VertexArray vao(m_context); |
| |
| /* */ |
| const std::string& fs = |
| getShaderSource(test_case_index, program_interface, varying_passthrough, Utils::Shader::FRAGMENT); |
| const std::string& gs = |
| getShaderSource(test_case_index, program_interface, varying_passthrough, Utils::Shader::GEOMETRY); |
| const std::string& tcs = |
| getShaderSource(test_case_index, program_interface, varying_passthrough, Utils::Shader::TESS_CTRL); |
| const std::string& tes = |
| getShaderSource(test_case_index, program_interface, varying_passthrough, Utils::Shader::TESS_EVAL); |
| const std::string& vs = |
| getShaderSource(test_case_index, program_interface, varying_passthrough, Utils::Shader::VERTEX); |
| |
| program_fs.Init("" /*cs*/, fs, "" /*gs*/, "" /*tcs*/, "" /*tes*/, "" /*vs*/, true /* is_separable */); |
| program_gs.Init("" /*cs*/, "" /*fs*/, gs, "" /*tcs*/, "" /*tes*/, "" /*vs*/, true /* is_separable */); |
| program_tcs.Init("" /*cs*/, "" /*fs*/, "" /*gs*/, tcs, "" /*tes*/, "" /*vs*/, true /* is_separable */); |
| program_tes.Init("" /*cs*/, "" /*fs*/, "" /*gs*/, "" /*tcs*/, tes, "" /*vs*/, true /* is_separable */); |
| program_vs.Init("" /*cs*/, "" /*fs*/, "" /*gs*/, "" /*tcs*/, "" /*tes*/, vs, true /* is_separable */); |
| |
| /* */ |
| prepareAttribLocation(program_vs, program_interface); |
| prepareFragmentDataLoc(program_vs, program_interface); |
| |
| /* */ |
| std::stringstream stream; |
| if ((false == |
| Utils::checkSeparableDrawProgramInterface(program_vs, program_interface, Utils::Shader::VERTEX, stream)) || |
| (false == Utils::checkSeparableDrawProgramInterface(program_fs, program_interface, Utils::Shader::FRAGMENT, |
| stream)) || |
| (false == Utils::checkSeparableDrawProgramInterface(program_gs, program_interface, Utils::Shader::GEOMETRY, |
| stream)) || |
| (false == Utils::checkSeparableDrawProgramInterface(program_tcs, program_interface, |
| Utils::Shader::TESS_CTRL, stream)) || |
| (false == Utils::checkSeparableDrawProgramInterface(program_tes, program_interface, |
| Utils::Shader::TESS_EVAL, stream))) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "FAILURE. Test case: " << test_name |
| << ". Inspection of separable draw program interface failed:\n" |
| << stream.str() << tcu::TestLog::EndMessage |
| << tcu::TestLog::KernelSource(vs) << tcu::TestLog::KernelSource(tcs) |
| << tcu::TestLog::KernelSource(tes) << tcu::TestLog::KernelSource(gs) |
| << tcu::TestLog::KernelSource(fs); |
| |
| return false; |
| } |
| |
| /* */ |
| pipeline.Init(); |
| pipeline.UseProgramStages(program_fs.m_id, GL_FRAGMENT_SHADER_BIT); |
| pipeline.UseProgramStages(program_gs.m_id, GL_GEOMETRY_SHADER_BIT); |
| pipeline.UseProgramStages(program_tcs.m_id, GL_TESS_CONTROL_SHADER_BIT); |
| pipeline.UseProgramStages(program_tes.m_id, GL_TESS_EVALUATION_SHADER_BIT); |
| pipeline.UseProgramStages(program_vs.m_id, GL_VERTEX_SHADER_BIT); |
| pipeline.Bind(); |
| |
| /* */ |
| |
| buffer_attr.Init(Utils::Buffer::Array, Utils::Buffer::StaticDraw, 0, 0); |
| vao.Init(); |
| prepareAttributes(test_case_index, program_interface, buffer_attr, vao); |
| |
| /* */ |
| prepareUniforms(test_case_index, program_interface, program_fs, program_gs, program_tcs, program_tes, |
| program_vs, buffer_u_fs, buffer_u_gs, buffer_u_tcs, buffer_u_tes, buffer_u_vs); |
| |
| Utils::Program::Use(m_context.getRenderContext().getFunctions(), Utils::Program::m_invalid_id); |
| |
| /* */ |
| prepareFramebuffer(framebuffer, texture_fb); |
| |
| /* Draw */ |
| executeDrawCall(test_case_index); |
| |
| #if USE_NSIGHT |
| m_context.getRenderContext().postIterate(); |
| #endif |
| |
| /* Check results */ |
| if (false == checkResults(test_case_index, texture_fb)) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "FAILURE. Test case: " << test_name << ". Draw - invalid results." |
| << tcu::TestLog::EndMessage << tcu::TestLog::KernelSource(vs) << tcu::TestLog::KernelSource(tcs) |
| << tcu::TestLog::KernelSource(tes) << tcu::TestLog::KernelSource(gs) << tcu::TestLog::KernelSource(fs); |
| |
| result = false; |
| } |
| else |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Success." << tcu::TestLog::EndMessage << tcu::TestLog::KernelSource(vs) |
| << tcu::TestLog::KernelSource(tcs) << tcu::TestLog::KernelSource(tes) << tcu::TestLog::KernelSource(gs) |
| << tcu::TestLog::KernelSource(fs); |
| } |
| } |
| |
| /* Compute */ |
| if (true == isComputeRelevant(test_case_index)) |
| { |
| Utils::Buffer buffer_u_cs(m_context); |
| Utils::Program program(m_context); |
| Utils::Texture texture_im(m_context); |
| Utils::VertexArray vao(m_context); |
| |
| /* */ |
| const std::string& compute_shader = |
| getShaderSource(test_case_index, program_interface, varying_passthrough, Utils::Shader::COMPUTE); |
| |
| program.Init(compute_shader, "" /* fragment_shader */, "" /* geometry_shader */, "" /* tess_ctrl_shader */, |
| "" /* tess_eval_shader */, "" /* vertex_shader */, false /* is_separable */); |
| |
| /* */ |
| { |
| std::stringstream stream; |
| |
| if (false == Utils::checkMonolithicComputeProgramInterface(program, program_interface, stream)) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "FAILURE. Test case: " << test_name |
| << ". Inspection of compute program interface failed:\n" |
| << stream.str() << tcu::TestLog::EndMessage; |
| |
| return false; |
| } |
| } |
| |
| /* */ |
| program.Use(); |
| |
| /* */ |
| vao.Init(); |
| vao.Bind(); |
| |
| /* */ |
| prepareUniforms(test_case_index, program_interface, program, buffer_u_cs); |
| |
| /* */ |
| GLint image_location = program.GetUniformLocation("uni_image"); |
| prepareImage(image_location, texture_im); |
| |
| /* Draw */ |
| executeDispatchCall(test_case_index); |
| |
| #if USE_NSIGHT |
| m_context.getRenderContext().postIterate(); |
| #endif |
| |
| /* Check results */ |
| if (false == checkResults(test_case_index, texture_im)) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "FAILURE. Test case: " << test_name |
| << ". Compute - invalid results." << tcu::TestLog::EndMessage |
| << tcu::TestLog::KernelSource(compute_shader); |
| |
| result = false; |
| } |
| } |
| |
| return result; |
| } |
| |
| /** Basic implementation |
| * |
| * @param ignored |
| * |
| * @return false |
| **/ |
| bool TextureTestBase::useComponentQualifier(glw::GLuint /* test_case_index */) |
| { |
| return false; |
| } |
| |
| /** Basic implementation |
| * |
| * @param ignored |
| * |
| * @return true |
| **/ |
| bool TextureTestBase::useMonolithicProgram(GLuint /* test_case_index */) |
| { |
| return true; |
| } |
| |
| /** Constructor |
| * |
| * @param context Test framework context |
| **/ |
| APIConstantValuesTest::APIConstantValuesTest(deqp::Context& context) |
| : TestCase(context, "api_constant_values", "Test verifies values of api constants") |
| { |
| /* Nothing to be done here */ |
| } |
| |
| /** Execute test |
| * |
| * @return tcu::TestNode::STOP otherwise |
| **/ |
| tcu::TestNode::IterateResult APIConstantValuesTest::iterate() |
| { |
| static const GLuint expected_comp = 64; |
| static const GLuint expected_xfb = 4; |
| static const GLuint expected_sep = 4; |
| GLint max_comp = 0; |
| GLint max_xfb = 0; |
| GLint max_sep = 0; |
| bool test_result = true; |
| |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| gl.getIntegerv(GL_MAX_TRANSFORM_FEEDBACK_BUFFERS, &max_xfb); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv"); |
| gl.getIntegerv(GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS, &max_comp); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv"); |
| gl.getIntegerv(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS, &max_sep); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv"); |
| |
| if (expected_xfb > (GLuint)max_xfb) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message |
| << "Invalid GL_MAX_TRANSFORM_FEEDBACK_BUFFERS. Got " << max_xfb |
| << " Expected at least " << expected_xfb << tcu::TestLog::EndMessage; |
| |
| test_result = false; |
| } |
| |
| if (expected_comp > (GLuint)max_comp) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Invalid GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS. Got " << max_comp |
| << " Expected at least " << expected_comp << tcu::TestLog::EndMessage; |
| |
| test_result = false; |
| } |
| |
| if (expected_sep > (GLuint)max_sep) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message |
| << "Invalid GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS. Got " << max_comp |
| << " Expected at least " << expected_comp << tcu::TestLog::EndMessage; |
| |
| test_result = false; |
| } |
| |
| /* Set result */ |
| if (true == test_result) |
| { |
| m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| } |
| else |
| { |
| m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Fail"); |
| } |
| |
| /* Done */ |
| return tcu::TestNode::STOP; |
| } |
| |
| /** Constructor |
| * |
| * @param context Test framework context |
| **/ |
| APIErrorsTest::APIErrorsTest(deqp::Context& context) |
| : TestCase(context, "api_errors", "Test verifies errors reeturned by api") |
| { |
| /* Nothing to be done here */ |
| } |
| |
| /** Execute test |
| * |
| * @return tcu::TestNode::STOP otherwise |
| **/ |
| tcu::TestNode::IterateResult APIErrorsTest::iterate() |
| { |
| GLint length = 0; |
| GLchar name[64]; |
| GLint param = 0; |
| Utils::Program program(m_context); |
| bool test_result = true; |
| |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| try |
| { |
| program.Init("" /* cs */, "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 vs_fs;\n" |
| "out vec4 fs_out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " fs_out = vs_fs;\n" |
| "}\n" |
| "\n" /* fs */, |
| "" /* gs */, "" /* tcs */, "" /* tes */, "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 in_vs;\n" |
| "layout (xfb_offset = 16) out vec4 vs_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vs_fs = in_vs;\n" |
| "}\n" |
| "\n" /* vs */, |
| false /* separable */); |
| } |
| catch (Utils::Shader::InvalidSourceException& exc) |
| { |
| exc.log(m_context); |
| TCU_FAIL(exc.what()); |
| } |
| catch (Utils::Program::BuildException& exc) |
| { |
| TCU_FAIL(exc.what()); |
| } |
| |
| /* |
| * - GetProgramInterfaceiv should generate INVALID_OPERATION when |
| * <programInterface> is TRANSFORM_FEEDBACK_BUFFER and <pname> is one of the |
| * following: |
| * * MAX_NAME_LENGTH, |
| * * MAX_NUM_ACTIVE_VARIABLES; |
| */ |
| gl.getProgramInterfaceiv(program.m_id, GL_TRANSFORM_FEEDBACK_BUFFER, GL_MAX_NAME_LENGTH, ¶m); |
| checkError(GL_INVALID_OPERATION, "GetProgramInterfaceiv(GL_TRANSFORM_FEEDBACK_BUFFER, GL_MAX_NAME_LENGTH)", |
| test_result); |
| |
| /* |
| * - GetProgramResourceIndex should generate INVALID_ENUM when |
| * <programInterface> is TRANSFORM_FEEDBACK_BUFFER; |
| */ |
| gl.getProgramResourceIndex(program.m_id, GL_TRANSFORM_FEEDBACK_BUFFER, "0"); |
| checkError(GL_INVALID_ENUM, "GetProgramResourceIndex(GL_TRANSFORM_FEEDBACK_BUFFER)", test_result); |
| /* |
| * - GetProgramResourceName should generate INVALID_ENUM when |
| * <programInterface> is TRANSFORM_FEEDBACK_BUFFER; |
| */ |
| gl.getProgramResourceName(program.m_id, GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, 64 /* bufSize */, &length, |
| name); |
| checkError(GL_INVALID_ENUM, "GetProgramResourceName(GL_TRANSFORM_FEEDBACK_BUFFER)", test_result); |
| |
| /* Set result */ |
| if (true == test_result) |
| { |
| m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| } |
| else |
| { |
| m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Fail"); |
| } |
| |
| /* Done */ |
| return tcu::TestNode::STOP; |
| } |
| |
| /** Check if error is the expected one. |
| * |
| * @param expected_error Expected error |
| * @param message Message to log in case of error |
| * @param test_result Test result, set to false in case of invalid error |
| **/ |
| void APIErrorsTest::checkError(GLenum expected_error, const GLchar* message, bool& test_result) |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| GLenum error = gl.getError(); |
| |
| if (error != expected_error) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Failure. Invalid error. Got " << glu::getErrorStr(error) << " expected " |
| << glu::getErrorStr(expected_error) << " Msg: " << message << tcu::TestLog::EndMessage; |
| |
| test_result = false; |
| } |
| } |
| |
| /** Constructor |
| * |
| * @param context Test framework context |
| **/ |
| GLSLContantImmutablityTest::GLSLContantImmutablityTest(deqp::Context& context) |
| : NegativeTestBase(context, "glsl_contant_immutablity", "Test verifies that glsl constants cannot be modified") |
| { |
| /* Nothing to be done here */ |
| } |
| |
| /** Source for given test case and stage |
| * |
| * @param test_case_index Index of test case |
| * @param stage Shader stage |
| * |
| * @return Shader source |
| **/ |
| std::string GLSLContantImmutablityTest::getShaderSource(GLuint test_case_index, Utils::Shader::STAGES stage) |
| { |
| static const GLchar* cs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n" |
| "\n" |
| "writeonly uniform uimage2D uni_image;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " uint result = 1u;\n" |
| " CONSTANT = 3;\n" |
| "\n" |
| " imageStore(uni_image, ivec2(gl_GlobalInvocationID.xy), uvec4(result, 0, 0, 0));\n" |
| "}\n" |
| "\n"; |
| static const GLchar* fs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 gs_fs;\n" |
| "out vec4 fs_out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| "ASSIGNMENT" |
| " fs_out = gs_fs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* gs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| "in vec4 tes_gs[];\n" |
| "out vec4 gs_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| "ASSIGNMENT" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tcs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "in vec4 vs_tcs[];\n" |
| "out vec4 tcs_tes[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| "\n" |
| "ASSIGNMENT" |
| " tcs_tes[gl_InvocationID] = vs_tcs[gl_InvocationID];\n" |
| "\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tes = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(isolines, point_mode) in;\n" |
| "\n" |
| "in vec4 tcs_tes[];\n" |
| "out vec4 tes_gs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| "ASSIGNMENT" |
| " tes_gs = tcs_tes[0];\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 vs_tcs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| "ASSIGNMENT" |
| " vs_tcs = in_vs;\n" |
| "}\n" |
| "\n"; |
| |
| std::string source; |
| testCase& test_case = m_test_cases[test_case_index]; |
| |
| if (Utils::Shader::COMPUTE == test_case.m_stage) |
| { |
| size_t position = 0; |
| |
| source = cs; |
| |
| Utils::replaceToken("CONSTANT", position, getConstantName(test_case.m_constant), source); |
| } |
| else |
| { |
| std::string assignment = " CONSTANT = 3;\n"; |
| size_t position = 0; |
| |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs; |
| break; |
| case Utils::Shader::GEOMETRY: |
| source = gs; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| source = tcs; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| source = tes; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| if (test_case.m_stage == stage) |
| { |
| Utils::replaceToken("CONSTANT", position, getConstantName(test_case.m_constant), assignment); |
| } |
| else |
| { |
| assignment = ""; |
| } |
| |
| position = 0; |
| Utils::replaceToken("ASSIGNMENT", position, assignment.c_str(), source); |
| } |
| |
| return source; |
| } |
| |
| /** Get description of test case |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return Constant name |
| **/ |
| std::string GLSLContantImmutablityTest::getTestCaseName(GLuint test_case_index) |
| { |
| std::string result = getConstantName(m_test_cases[test_case_index].m_constant); |
| |
| return result; |
| } |
| |
| /** Get number of test cases |
| * |
| * @return Number of test cases |
| **/ |
| GLuint GLSLContantImmutablityTest::getTestCaseNumber() |
| { |
| return static_cast<GLuint>(m_test_cases.size()); |
| } |
| |
| /** Selects if "compute" stage is relevant for test |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return true when tested stage is compute |
| **/ |
| bool GLSLContantImmutablityTest::isComputeRelevant(GLuint test_case_index) |
| { |
| return (Utils::Shader::COMPUTE == m_test_cases[test_case_index].m_stage); |
| } |
| |
| /** Prepare all test cases |
| * |
| **/ |
| void GLSLContantImmutablityTest::testInit() |
| { |
| for (GLuint constant = 0; constant < CONSTANTS_MAX; ++constant) |
| { |
| for (GLuint stage = 0; stage < Utils::Shader::STAGE_MAX; ++stage) |
| { |
| testCase test_case = { (CONSTANTS)constant, (Utils::Shader::STAGES)stage }; |
| |
| m_test_cases.push_back(test_case); |
| } |
| } |
| } |
| |
| /** Get name of glsl constant |
| * |
| * @param Constant id |
| * |
| * @return Name of constant used in GLSL |
| **/ |
| const GLchar* GLSLContantImmutablityTest::getConstantName(CONSTANTS constant) |
| { |
| const GLchar* name = ""; |
| |
| switch (constant) |
| { |
| case GL_ARB_ENHANCED_LAYOUTS: |
| name = "GL_ARB_enhanced_layouts"; |
| break; |
| case GL_MAX_XFB: |
| name = "gl_MaxTransformFeedbackBuffers"; |
| break; |
| case GL_MAX_XFB_INT_COMP: |
| name = "gl_MaxTransformFeedbackInterleavedComponents"; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| return name; |
| } |
| |
| /** Constructor |
| * |
| * @param context Test framework context |
| **/ |
| GLSLContantValuesTest::GLSLContantValuesTest(deqp::Context& context) |
| : TextureTestBase(context, "glsl_contant_values", "Test verifies values of constant symbols") |
| { |
| } |
| |
| /** Selects if "compute" stage is relevant for test |
| * |
| * @param ignored |
| * |
| * @return false |
| **/ |
| bool GLSLContantValuesTest::isComputeRelevant(GLuint /* test_case_index */) |
| { |
| return false; |
| } |
| |
| /** Prepare code snippet that will verify in and uniform variables |
| * |
| * @param ignored |
| * @param ignored |
| * @param stage Shader stage |
| * |
| * @return Code that verify variables |
| **/ |
| std::string GLSLContantValuesTest::getVerificationSnippet(GLuint /* test_case_index */, |
| Utils::ProgramInterface& /* program_interface */, |
| Utils::Shader::STAGES stage) |
| { |
| /* Get constants */ |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| GLint max_transform_feedback_buffers = 0; |
| GLint max_transform_feedback_interleaved_components = 0; |
| |
| gl.getIntegerv(GL_MAX_TRANSFORM_FEEDBACK_BUFFERS, &max_transform_feedback_buffers); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv"); |
| gl.getIntegerv(GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS, &max_transform_feedback_interleaved_components); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv"); |
| |
| std::string verification; |
| |
| if (Utils::Shader::VERTEX == stage) |
| { |
| verification = "if (1 != GL_ARB_enhanced_layouts)\n" |
| " {\n" |
| " result = 0;\n" |
| " }\n" |
| " else if (MAX_TRANSFORM_FEEDBACK_BUFFERS\n" |
| " != gl_MaxTransformFeedbackBuffers)\n" |
| " {\n" |
| " result = 0;\n" |
| " }\n" |
| " else if (MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS \n" |
| " != gl_MaxTransformFeedbackInterleavedComponents)\n" |
| " {\n" |
| " result = 0;\n" |
| " }\n"; |
| |
| size_t position = 0; |
| GLchar buffer[16]; |
| |
| sprintf(buffer, "%d", max_transform_feedback_buffers); |
| Utils::replaceToken("MAX_TRANSFORM_FEEDBACK_BUFFERS", position, buffer, verification); |
| |
| sprintf(buffer, "%d", max_transform_feedback_interleaved_components); |
| Utils::replaceToken("MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS", position, buffer, verification); |
| } |
| else |
| { |
| verification = ""; |
| } |
| |
| return verification; |
| } |
| |
| /** Constructor |
| * |
| * @param context Test framework context |
| **/ |
| GLSLConstantIntegralExpressionTest::GLSLConstantIntegralExpressionTest(deqp::Context& context) |
| : TextureTestBase(context, "glsl_constant_integral_expression", |
| "Test verifies that symbols can be used as constant integral expressions") |
| { |
| } |
| |
| /** Get interface of program |
| * |
| * @param ignored |
| * @param program_interface Interface of program |
| * @param ignored |
| **/ |
| void GLSLConstantIntegralExpressionTest::getProgramInterface(GLuint /* test_case_index */, |
| Utils::ProgramInterface& program_interface, |
| Utils::VaryingPassthrough& /* varying_passthrough */) |
| { |
| /* Get constants */ |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| GLint max_transform_feedback_buffers = 0; |
| GLint max_transform_feedback_interleaved_components = 0; |
| |
| gl.getIntegerv(GL_MAX_TRANSFORM_FEEDBACK_BUFFERS, &max_transform_feedback_buffers); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv"); |
| gl.getIntegerv(GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS, &max_transform_feedback_interleaved_components); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv"); |
| |
| GLuint gohan_div = std::max(1, max_transform_feedback_buffers / 16); |
| GLuint goten_div = std::max(1, max_transform_feedback_interleaved_components / 16); |
| |
| m_gohan_length = max_transform_feedback_buffers / gohan_div; |
| m_goten_length = max_transform_feedback_interleaved_components / goten_div; |
| |
| /* Globals */ |
| std::string globals = "uniform uint goku [GL_ARB_enhanced_layouts / 1];\n" |
| "uniform uint gohan[gl_MaxTransformFeedbackBuffers / GOHAN_DIV];\n" |
| "uniform uint goten[gl_MaxTransformFeedbackInterleavedComponents / GOTEN_DIV];\n"; |
| |
| size_t position = 0; |
| GLchar buffer[16]; |
| |
| sprintf(buffer, "%d", gohan_div); |
| Utils::replaceToken("GOHAN_DIV", position, buffer, globals); |
| |
| sprintf(buffer, "%d", goten_div); |
| Utils::replaceToken("GOTEN_DIV", position, buffer, globals); |
| |
| program_interface.m_vertex.m_globals = globals; |
| program_interface.m_tess_ctrl.m_globals = globals; |
| program_interface.m_tess_eval.m_globals = globals; |
| program_interface.m_geometry.m_globals = globals; |
| program_interface.m_fragment.m_globals = globals; |
| program_interface.m_compute.m_globals = globals; |
| } |
| |
| /** Prepare code snippet that will verify in and uniform variables |
| * |
| * @param ignored |
| * @param ignored |
| * @param ignored |
| * |
| * @return Code that verify variables |
| **/ |
| std::string GLSLConstantIntegralExpressionTest::getVerificationSnippet(GLuint /* test_case_index */, |
| Utils::ProgramInterface& /* program_interface */, |
| Utils::Shader::STAGES /* stage */) |
| { |
| std::string verification = "{\n" |
| " uint goku_sum = 0;\n" |
| " uint gohan_sum = 0;\n" |
| " uint goten_sum = 0;\n" |
| "\n" |
| " for (uint i = 0u; i < goku.length(); ++i)\n" |
| " {\n" |
| " goku_sum += goku[i];\n" |
| " }\n" |
| "\n" |
| " for (uint i = 0u; i < gohan.length(); ++i)\n" |
| " {\n" |
| " gohan_sum += gohan[i];\n" |
| " }\n" |
| "\n" |
| " for (uint i = 0u; i < goten.length(); ++i)\n" |
| " {\n" |
| " goten_sum += goten[i];\n" |
| " }\n" |
| "\n" |
| " if ( (1u != goku_sum) &&\n" |
| " (EXPECTED_GOHAN_SUMu != gohan_sum) ||\n" |
| " (EXPECTED_GOTEN_SUMu != goten_sum) )\n" |
| " {\n" |
| " result = 0u;\n" |
| " }\n" |
| " }\n"; |
| |
| size_t position = 0; |
| GLchar buffer[16]; |
| |
| sprintf(buffer, "%d", m_gohan_length); |
| Utils::replaceToken("EXPECTED_GOHAN_SUM", position, buffer, verification); |
| |
| sprintf(buffer, "%d", m_goten_length); |
| Utils::replaceToken("EXPECTED_GOTEN_SUM", position, buffer, verification); |
| |
| return verification; |
| } |
| |
| /** Prepare unifroms |
| * |
| * @param ignored |
| * @param ignored |
| * @param program Program object |
| * @param ignored |
| **/ |
| void GLSLConstantIntegralExpressionTest::prepareUniforms(GLuint /* test_case_index */, |
| Utils::ProgramInterface& /* program_interface */, |
| Utils::Program& program, Utils::Buffer& /* cs_buffer */) |
| { |
| static const GLuint uniform_data[16] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; |
| |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| GLint goku_location = program.GetUniformLocation("goku"); |
| GLint gohan_location = program.GetUniformLocation("gohan"); |
| GLint goten_location = program.GetUniformLocation("goten"); |
| |
| program.Uniform(gl, Utils::Type::uint, 1 /* count */, goku_location, uniform_data); |
| program.Uniform(gl, Utils::Type::uint, m_gohan_length, gohan_location, uniform_data); |
| program.Uniform(gl, Utils::Type::uint, m_goten_length, goten_location, uniform_data); |
| } |
| |
| /** Prepare unifroms |
| * |
| * @param test_case_index Pass as param to first implemetnation |
| * @param program_interface Pass as param to first implemetnation |
| * @param program Pass as param to first implemetnation |
| * @param ignored |
| * @param ignored |
| * @param ignored |
| * @param ignored |
| * @param vs_buffer Pass as param to first implemetnation |
| **/ |
| void GLSLConstantIntegralExpressionTest::prepareUniforms(GLuint test_case_index, |
| Utils::ProgramInterface& program_interface, |
| Utils::Program& program, Utils::Buffer& /* fs_buffer */, |
| Utils::Buffer& /* gs_buffer */, |
| Utils::Buffer& /* tcs_buffer */, |
| Utils::Buffer& /* tes_buffer */, Utils::Buffer& vs_buffer) |
| { |
| /* Call first implementation */ |
| prepareUniforms(test_case_index, program_interface, program, vs_buffer); |
| } |
| |
| /** Constructor |
| * |
| * @param context Test framework context |
| **/ |
| UniformBlockMemberOffsetAndAlignTest::UniformBlockMemberOffsetAndAlignTest(deqp::Context& context) |
| : TextureTestBase(context, "uniform_block_member_offset_and_align", |
| "Test verifies offsets and alignment of uniform buffer members") |
| { |
| } |
| |
| /** Get interface of program |
| * |
| * @param test_case_index Test case index |
| * @param program_interface Interface of program |
| * @param varying_passthrough Collection of connections between in and out variables |
| **/ |
| void UniformBlockMemberOffsetAndAlignTest::getProgramInterface(GLuint test_case_index, |
| Utils::ProgramInterface& program_interface, |
| Utils::VaryingPassthrough& varying_passthrough) |
| { |
| std::string globals = "const int basic_size = BASIC_SIZE;\n" |
| "const int type_align = TYPE_ALIGN;\n" |
| "const int type_size = TYPE_SIZE;\n"; |
| |
| Utils::Type type = getType(test_case_index); |
| GLuint basic_size = Utils::Type::GetTypeSize(type.m_basic_type); |
| const GLuint base_align = type.GetBaseAlignment(false); |
| const GLuint array_align = type.GetBaseAlignment(true); |
| const GLuint base_stride = Utils::Type::CalculateStd140Stride(base_align, type.m_n_columns, 0); |
| const GLuint type_align = Utils::roundUpToPowerOf2(base_stride); |
| |
| /* Calculate offsets */ |
| const GLuint first_offset = 0; |
| const GLuint second_offset = type.GetActualOffset(base_stride, basic_size / 2); |
| |
| #if WRKARD_UNIFORMBLOCKMEMBEROFFSETANDALIGNTEST |
| |
| const GLuint third_offset = type.GetActualOffset(second_offset + base_stride, base_align); |
| const GLuint fourth_offset = type.GetActualOffset(third_offset + base_stride, base_align); |
| const GLuint fifth_offset = type.GetActualOffset(fourth_offset + base_stride, base_align); |
| const GLuint sixth_offset = type.GetActualOffset(fifth_offset + base_stride, array_align); |
| const GLuint seventh_offset = type.GetActualOffset(sixth_offset + base_stride, array_align); |
| const GLuint eigth_offset = type.GetActualOffset(seventh_offset + base_stride, array_align); |
| |
| #else /* WRKARD_UNIFORMBLOCKMEMBEROFFSETANDALIGNTEST */ |
| |
| const GLuint third_offset = type.GetActualOffset(second_offset + base_stride, 2 * type_align); |
| const GLuint fourth_offset = type.GetActualOffset(3 * type_align + base_stride, base_align); |
| const GLuint fifth_offset = type.GetActualOffset(fourth_offset + base_stride, base_align); |
| const GLuint sixth_offset = type.GetActualOffset(fifth_offset + base_stride, array_align); |
| const GLuint seventh_offset = type.GetActualOffset(sixth_offset + base_stride, array_align); |
| const GLuint eigth_offset = type.GetActualOffset(seventh_offset + base_stride, 8 * basic_size); |
| |
| #endif /* WRKARD_UNIFORMBLOCKMEMBEROFFSETANDALIGNTEST */ |
| |
| /* Prepare data */ |
| const std::vector<GLubyte>& first = type.GenerateData(); |
| const std::vector<GLubyte>& second = type.GenerateData(); |
| const std::vector<GLubyte>& third = type.GenerateData(); |
| const std::vector<GLubyte>& fourth = type.GenerateData(); |
| |
| m_data.resize(eigth_offset + base_stride); |
| GLubyte* ptr = &m_data[0]; |
| memcpy(ptr + first_offset, &first[0], first.size()); |
| memcpy(ptr + second_offset, &second[0], second.size()); |
| memcpy(ptr + third_offset, &third[0], third.size()); |
| memcpy(ptr + fourth_offset, &fourth[0], fourth.size()); |
| memcpy(ptr + fifth_offset, &fourth[0], fourth.size()); |
| memcpy(ptr + sixth_offset, &third[0], third.size()); |
| memcpy(ptr + seventh_offset, &second[0], second.size()); |
| memcpy(ptr + eigth_offset, &first[0], first.size()); |
| |
| /* Prepare globals */ |
| size_t position = 0; |
| GLchar buffer[16]; |
| |
| sprintf(buffer, "%d", basic_size); |
| Utils::replaceToken("BASIC_SIZE", position, buffer, globals); |
| |
| sprintf(buffer, "%d", type_align); |
| Utils::replaceToken("TYPE_ALIGN", position, buffer, globals); |
| |
| sprintf(buffer, "%d", base_stride); |
| Utils::replaceToken("TYPE_SIZE", position, buffer, globals); |
| |
| /* Prepare Block */ |
| Utils::Interface* vs_uni_block = program_interface.Block("vs_uni_Block"); |
| |
| vs_uni_block->Member("at_first_offset", "layout(offset = 0, align = 8 * basic_size)", 0 /* expected_component */, |
| 0 /* expected_location */, type, false /* normalized */, 0 /* n_array_elements */, base_stride, |
| first_offset); |
| |
| vs_uni_block->Member("at_second_offset", "layout(offset = type_size, align = basic_size / 2)", |
| 0 /* expected_component */, 0 /* expected_location */, type, false /* normalized */, |
| 0 /* n_array_elements */, base_stride, second_offset); |
| |
| vs_uni_block->Member("at_third_offset", "layout(align = 2 * type_align)", 0 /* expected_component */, |
| 0 /* expected_location */, type, false /* normalized */, 0 /* n_array_elements */, base_stride, |
| third_offset); |
| |
| vs_uni_block->Member("at_fourth_offset", "layout(offset = 3 * type_align + type_size)", 0 /* expected_component */, |
| 0 /* expected_location */, type, false /* normalized */, 0 /* n_array_elements */, base_stride, |
| fourth_offset); |
| |
| vs_uni_block->Member("at_fifth_offset", "", 0 /* expected_component */, 0 /* expected_location */, type, |
| false /* normalized */, 0 /* n_array_elements */, base_stride, fifth_offset); |
| |
| vs_uni_block->Member("at_sixth_offset", "", 0 /* expected_component */, 0 /* expected_location */, type, |
| false /* normalized */, 2 /* n_array_elements */, array_align * 2, sixth_offset); |
| |
| vs_uni_block->Member("at_eigth_offset", "layout(align = 8 * basic_size)", 0 /* expected_component */, |
| 0 /* expected_location */, type, false /* normalized */, 0 /* n_array_elements */, base_stride, |
| eigth_offset); |
| |
| Utils::ShaderInterface& vs_si = program_interface.GetShaderInterface(Utils::Shader::VERTEX); |
| |
| /* Add globals */ |
| vs_si.m_globals = globals; |
| |
| /* Add uniform BLOCK */ |
| vs_si.Uniform("vs_uni_block", "layout (std140, binding = BINDING)", 0, 0, vs_uni_block, 0, |
| static_cast<glw::GLint>(m_data.size()), 0, &m_data[0], m_data.size()); |
| |
| /* */ |
| program_interface.CloneVertexInterface(varying_passthrough); |
| } |
| |
| /** Get type name |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return Name of type test in test_case_index |
| **/ |
| std::string UniformBlockMemberOffsetAndAlignTest::getTestCaseName(glw::GLuint test_case_index) |
| { |
| return getTypeName(test_case_index); |
| } |
| |
| /** Returns number of types to test |
| * |
| * @return Number of types, 34 |
| **/ |
| glw::GLuint UniformBlockMemberOffsetAndAlignTest::getTestCaseNumber() |
| { |
| return getTypesNumber(); |
| } |
| |
| /** Prepare code snippet that will verify in and uniform variables |
| * |
| * @param ignored |
| * @param ignored |
| * @param stage Shader stage |
| * |
| * @return Code that verify variables |
| **/ |
| std::string UniformBlockMemberOffsetAndAlignTest::getVerificationSnippet( |
| GLuint /* test_case_index */, Utils::ProgramInterface& /* program_interface */, Utils::Shader::STAGES stage) |
| { |
| std::string verification = "if ( (PREFIXblock.at_first_offset != PREFIXblock.at_eigth_offset ) ||\n" |
| " (PREFIXblock.at_second_offset != PREFIXblock.at_sixth_offset[1]) ||\n" |
| " (PREFIXblock.at_third_offset != PREFIXblock.at_sixth_offset[0]) ||\n" |
| " (PREFIXblock.at_fourth_offset != PREFIXblock.at_fifth_offset ) )\n" |
| " {\n" |
| " result = 0;\n" |
| " }"; |
| |
| const GLchar* prefix = Utils::ProgramInterface::GetStagePrefix(stage, Utils::Variable::UNIFORM); |
| |
| Utils::replaceAllTokens("PREFIX", prefix, verification); |
| |
| return verification; |
| } |
| |
| /** Constructor |
| * |
| * @param context Test framework context |
| **/ |
| UniformBlockLayoutQualifierConflictTest::UniformBlockLayoutQualifierConflictTest(deqp::Context& context) |
| : NegativeTestBase( |
| context, "uniform_block_layout_qualifier_conflict", |
| "Test verifies that std140 is required when offset and/or align qualifiers are used with uniform block") |
| { |
| /* Nothing to be done here */ |
| } |
| |
| /** Source for given test case and stage |
| * |
| * @param test_case_index Index of test case |
| * @param stage Shader stage |
| * |
| * @return Shader source |
| **/ |
| std::string UniformBlockLayoutQualifierConflictTest::getShaderSource(GLuint test_case_index, |
| Utils::Shader::STAGES stage) |
| { |
| static const GLchar* cs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n" |
| "\n" |
| "LAYOUTuniform Block {\n" |
| " layout(offset = 16) vec4 boy;\n" |
| " layout(align = 64) vec4 man;\n" |
| "} uni_block;\n" |
| "\n" |
| "writeonly uniform image2D uni_image;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = uni_block.boy + uni_block.man;\n" |
| "\n" |
| " imageStore(uni_image, ivec2(gl_GlobalInvocationID.xy), result);\n" |
| "}\n" |
| "\n"; |
| static const GLchar* fs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "LAYOUTuniform Block {\n" |
| " layout(offset = 16) vec4 boy;\n" |
| " layout(align = 64) vec4 man;\n" |
| "} uni_block;\n" |
| "\n" |
| "in vec4 gs_fs;\n" |
| "out vec4 fs_out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " fs_out = gs_fs + uni_block.boy + uni_block.man;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* gs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| "LAYOUTuniform Block {\n" |
| " layout(offset = 16) vec4 boy;\n" |
| " layout(align = 64) vec4 man;\n" |
| "} uni_block;\n" |
| "\n" |
| "in vec4 tes_gs[];\n" |
| "out vec4 gs_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " gs_fs = tes_gs[0] + uni_block.boy + uni_block.man;\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0] + uni_block.boy + uni_block.man;\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0] + uni_block.boy + uni_block.man;\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0] + uni_block.boy + uni_block.man;\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tcs = |
| "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "LAYOUTuniform Block {\n" |
| " layout(offset = 16) vec4 boy;\n" |
| " layout(align = 64) vec4 man;\n" |
| "} uni_block;\n" |
| "\n" |
| "in vec4 vs_tcs[];\n" |
| "out vec4 tcs_tes[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| "\n" |
| " tcs_tes[gl_InvocationID] = vs_tcs[gl_InvocationID] + uni_block.boy + uni_block.man;\n" |
| "\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tes = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(isolines, point_mode) in;\n" |
| "\n" |
| "LAYOUTuniform Block {\n" |
| " layout(offset = 16) vec4 boy;\n" |
| " layout(align = 64) vec4 man;\n" |
| "} uni_block;\n" |
| "\n" |
| "in vec4 tcs_tes[];\n" |
| "out vec4 tes_gs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " tes_gs = tcs_tes[0] + uni_block.boy + uni_block.man;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "LAYOUTuniform Block {\n" |
| " layout(offset = 16) vec4 boy;\n" |
| " layout(align = 64) vec4 man;\n" |
| "} uni_block;\n" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 vs_tcs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vs_tcs = in_vs + uni_block.boy + uni_block.man;\n" |
| "}\n" |
| "\n"; |
| |
| std::string layout = ""; |
| size_t position = 0; |
| testCase& test_case = m_test_cases[test_case_index]; |
| const GLchar* qualifier = getQualifierName(test_case.m_qualifier); |
| std::string source; |
| |
| if (0 != qualifier[0]) |
| { |
| size_t layout_position = 0; |
| |
| layout = "layout (QUALIFIER) "; |
| |
| Utils::replaceToken("QUALIFIER", layout_position, qualifier, layout); |
| } |
| |
| switch (stage) |
| { |
| case Utils::Shader::COMPUTE: |
| source = cs; |
| break; |
| case Utils::Shader::FRAGMENT: |
| source = fs; |
| break; |
| case Utils::Shader::GEOMETRY: |
| source = gs; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| source = tcs; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| source = tes; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| if (test_case.m_stage == stage) |
| { |
| Utils::replaceToken("LAYOUT", position, layout.c_str(), source); |
| } |
| else |
| { |
| Utils::replaceToken("LAYOUT", position, "layout (std140) ", source); |
| } |
| |
| return source; |
| } |
| |
| /** Get description of test case |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return Qualifier name |
| **/ |
| std::string UniformBlockLayoutQualifierConflictTest::getTestCaseName(GLuint test_case_index) |
| { |
| std::string result = getQualifierName(m_test_cases[test_case_index].m_qualifier); |
| |
| return result; |
| } |
| |
| /** Get number of test cases |
| * |
| * @return Number of test cases |
| **/ |
| GLuint UniformBlockLayoutQualifierConflictTest::getTestCaseNumber() |
| { |
| return static_cast<GLuint>(m_test_cases.size()); |
| } |
| |
| /** Selects if "compute" stage is relevant for test |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return true when tested stage is compute |
| **/ |
| bool UniformBlockLayoutQualifierConflictTest::isComputeRelevant(GLuint test_case_index) |
| { |
| return (Utils::Shader::COMPUTE == m_test_cases[test_case_index].m_stage); |
| } |
| |
| /** Selects if compilation failure is expected result |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return false for STD140 cases, true otherwise |
| **/ |
| bool UniformBlockLayoutQualifierConflictTest::isFailureExpected(GLuint test_case_index) |
| { |
| return (STD140 != m_test_cases[test_case_index].m_qualifier); |
| } |
| |
| /** Prepare all test cases |
| * |
| **/ |
| void UniformBlockLayoutQualifierConflictTest::testInit() |
| { |
| for (GLuint qualifier = 0; qualifier < QUALIFIERS_MAX; ++qualifier) |
| { |
| for (GLuint stage = 0; stage < Utils::Shader::STAGE_MAX; ++stage) |
| { |
| testCase test_case = { (QUALIFIERS)qualifier, (Utils::Shader::STAGES)stage }; |
| |
| m_test_cases.push_back(test_case); |
| } |
| } |
| } |
| |
| /** Get name of glsl constant |
| * |
| * @param Constant id |
| * |
| * @return Name of constant used in GLSL |
| **/ |
| const GLchar* UniformBlockLayoutQualifierConflictTest::getQualifierName(QUALIFIERS qualifier) |
| { |
| const GLchar* name = ""; |
| |
| switch (qualifier) |
| { |
| case DEFAULT: |
| name = ""; |
| break; |
| case STD140: |
| name = "std140"; |
| break; |
| case SHARED: |
| name = "shared"; |
| break; |
| case PACKED: |
| name = "packed"; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| return name; |
| } |
| |
| /** Constructor |
| * |
| * @param context Test framework context |
| **/ |
| UniformBlockMemberInvalidOffsetAlignmentTest::UniformBlockMemberInvalidOffsetAlignmentTest(deqp::Context& context) |
| : NegativeTestBase(context, "uniform_block_member_invalid_offset_alignment", |
| "Test verifies that invalid alignment of offset qualifiers cause compilation failure") |
| { |
| /* Nothing to be done here */ |
| } |
| |
| /** Constructor |
| * |
| * @param context Test framework context |
| * @param name Test name |
| * @param description Test description |
| **/ |
| UniformBlockMemberInvalidOffsetAlignmentTest::UniformBlockMemberInvalidOffsetAlignmentTest( |
| deqp::Context& context, const glw::GLchar* name, const glw::GLchar* description) |
| : NegativeTestBase(context, name, description) |
| { |
| /* Nothing to be done here */ |
| } |
| |
| /** Source for given test case and stage |
| * |
| * @param test_case_index Index of test case |
| * @param stage Shader stage |
| * |
| * @return Shader source |
| **/ |
| std::string UniformBlockMemberInvalidOffsetAlignmentTest::getShaderSource(GLuint test_case_index, |
| Utils::Shader::STAGES stage) |
| { |
| static const GLchar* cs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n" |
| "\n" |
| "layout (std140) uniform Block {\n" |
| " layout (offset = OFFSET) TYPE member;\n" |
| "} block;\n" |
| "\n" |
| "writeonly uniform image2D uni_image;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = vec4(1, 0, 0.5, 1);\n" |
| "\n" |
| " if (TYPE(1) == block.member)\n" |
| " {\n" |
| " result = vec4(1, 1, 1, 1);\n" |
| " }\n" |
| "\n" |
| " imageStore(uni_image, ivec2(gl_GlobalInvocationID.xy), result);\n" |
| "}\n" |
| "\n"; |
| static const GLchar* fs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 gs_fs;\n" |
| "out vec4 fs_out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " fs_out = gs_fs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* fs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout (std140) uniform Block {\n" |
| " layout (offset = OFFSET) TYPE member;\n" |
| "} block;\n" |
| "\n" |
| "in vec4 gs_fs;\n" |
| "out vec4 fs_out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " if (TYPE(1) == block.member)\n" |
| " {\n" |
| " fs_out = vec4(1, 1, 1, 1);\n" |
| " }\n" |
| "\n" |
| " fs_out += gs_fs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* gs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| "in vec4 tes_gs[];\n" |
| "out vec4 gs_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| static const GLchar* gs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| "layout (std140) uniform Block {\n" |
| " layout (offset = OFFSET) TYPE member;\n" |
| "} block;\n" |
| "\n" |
| "in vec4 tes_gs[];\n" |
| "out vec4 gs_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " if (TYPE(1) == block.member)\n" |
| " {\n" |
| " gs_fs = vec4(1, 1, 1, 1);\n" |
| " }\n" |
| "\n" |
| " gs_fs += tes_gs[0];\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs += tes_gs[0];\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs += tes_gs[0];\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs += tes_gs[0];\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tcs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "in vec4 vs_tcs[];\n" |
| "out vec4 tcs_tes[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| "\n" |
| " tcs_tes[gl_InvocationID] = vs_tcs[gl_InvocationID];\n" |
| "\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tcs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "layout (std140) uniform Block {\n" |
| " layout (offset = OFFSET) TYPE member;\n" |
| "} block;\n" |
| "\n" |
| "in vec4 vs_tcs[];\n" |
| "out vec4 tcs_tes[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " if (TYPE(1) == block.member)\n" |
| " {\n" |
| " tcs_tes[gl_InvocationID] = vec4(1, 1, 1, 1);\n" |
| " }\n" |
| "\n" |
| "\n" |
| " tcs_tes[gl_InvocationID] += vs_tcs[gl_InvocationID];\n" |
| "\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tes = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(isolines, point_mode) in;\n" |
| "\n" |
| "in vec4 tcs_tes[];\n" |
| "out vec4 tes_gs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " tes_gs = tcs_tes[0];\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tes_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(isolines, point_mode) in;\n" |
| "\n" |
| "layout (std140) uniform Block {\n" |
| " layout (offset = OFFSET) TYPE member;\n" |
| "} block;\n" |
| "\n" |
| "in vec4 tcs_tes[];\n" |
| "out vec4 tes_gs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " if (TYPE(1) == block.member)\n" |
| " {\n" |
| " tes_gs = vec4(1, 1, 1, 1);\n" |
| " }\n" |
| "\n" |
| " tes_gs += tcs_tes[0];\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 vs_tcs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vs_tcs = in_vs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout (std140) uniform Block {\n" |
| " layout (offset = OFFSET) TYPE member;\n" |
| "} block;\n" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 vs_tcs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " if (TYPE(1) == block.member)\n" |
| " {\n" |
| " vs_tcs = vec4(1, 1, 1, 1);\n" |
| " }\n" |
| "\n" |
| " vs_tcs += in_vs;\n" |
| "}\n" |
| "\n"; |
| |
| std::string source; |
| testCase& test_case = m_test_cases[test_case_index]; |
| |
| if (test_case.m_stage == stage) |
| { |
| GLchar buffer[16]; |
| const GLuint offset = test_case.m_offset; |
| size_t position = 0; |
| const Utils::Type& type = test_case.m_type; |
| const GLchar* type_name = type.GetGLSLTypeName(); |
| |
| sprintf(buffer, "%d", offset); |
| |
| switch (stage) |
| { |
| case Utils::Shader::COMPUTE: |
| source = cs; |
| break; |
| case Utils::Shader::FRAGMENT: |
| source = fs_tested; |
| break; |
| case Utils::Shader::GEOMETRY: |
| source = gs_tested; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| source = tcs_tested; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| source = tes_tested; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs_tested; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| Utils::replaceToken("OFFSET", position, buffer, source); |
| Utils::replaceToken("TYPE", position, type_name, source); |
| Utils::replaceToken("TYPE", position, type_name, source); |
| } |
| else |
| { |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs; |
| break; |
| case Utils::Shader::GEOMETRY: |
| source = gs; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| source = tcs; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| source = tes; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| } |
| |
| return source; |
| } |
| |
| /** Get description of test case |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return Type name and offset |
| **/ |
| std::string UniformBlockMemberInvalidOffsetAlignmentTest::getTestCaseName(GLuint test_case_index) |
| { |
| std::stringstream stream; |
| testCase& test_case = m_test_cases[test_case_index]; |
| |
| stream << "Type: " << test_case.m_type.GetGLSLTypeName() << ", offset: " << test_case.m_offset; |
| |
| return stream.str(); |
| } |
| |
| /** Get number of test cases |
| * |
| * @return Number of test cases |
| **/ |
| GLuint UniformBlockMemberInvalidOffsetAlignmentTest::getTestCaseNumber() |
| { |
| return static_cast<GLuint>(m_test_cases.size()); |
| } |
| |
| /** Get the maximum size for an uniform block |
| * |
| * @return The maximum size in basic machine units of a uniform block. |
| **/ |
| GLint UniformBlockMemberInvalidOffsetAlignmentTest::getMaxBlockSize() |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| GLint max_size = 0; |
| |
| gl.getIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &max_size); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv"); |
| |
| return max_size; |
| } |
| |
| /** Selects if "compute" stage is relevant for test |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return true when tested stage is compute |
| **/ |
| bool UniformBlockMemberInvalidOffsetAlignmentTest::isComputeRelevant(GLuint test_case_index) |
| { |
| return (Utils::Shader::COMPUTE == m_test_cases[test_case_index].m_stage); |
| } |
| |
| /** Selects if compilation failure is expected result |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return should_fail field from testCase |
| **/ |
| bool UniformBlockMemberInvalidOffsetAlignmentTest::isFailureExpected(GLuint test_case_index) |
| { |
| return m_test_cases[test_case_index].m_should_fail; |
| } |
| |
| /** Checks if stage is supported |
| * |
| * @param stage ignored |
| * |
| * @return true |
| **/ |
| bool UniformBlockMemberInvalidOffsetAlignmentTest::isStageSupported(Utils::Shader::STAGES /* stage */) |
| { |
| return true; |
| } |
| |
| /** Prepare all test cases |
| * |
| **/ |
| void UniformBlockMemberInvalidOffsetAlignmentTest::testInit() |
| { |
| const GLuint n_types = getTypesNumber(); |
| bool stage_support[Utils::Shader::STAGE_MAX]; |
| |
| for (GLuint stage = 0; stage < Utils::Shader::STAGE_MAX; ++stage) |
| { |
| stage_support[stage] = isStageSupported((Utils::Shader::STAGES)stage); |
| } |
| |
| for (GLuint i = 0; i < n_types; ++i) |
| { |
| const Utils::Type& type = getType(i); |
| const GLuint alignment = type.GetBaseAlignment(false); |
| const GLuint type_size = type.GetSize(true); |
| const GLuint sec_to_end = getMaxBlockSize() - 2 * type_size; |
| |
| for (GLuint stage = 0; stage < Utils::Shader::STAGE_MAX; ++stage) |
| { |
| if (false == stage_support[stage]) |
| { |
| continue; |
| } |
| |
| for (GLuint offset = 0; offset <= type_size; ++offset) |
| { |
| const GLuint modulo = offset % alignment; |
| const bool is_aligned = (0 == modulo) ? true : false; |
| const bool should_fail = !is_aligned; |
| |
| testCase test_case = { offset, should_fail, (Utils::Shader::STAGES)stage, type }; |
| |
| m_test_cases.push_back(test_case); |
| } |
| |
| for (GLuint offset = sec_to_end; offset <= sec_to_end + type_size; ++offset) |
| { |
| const GLuint modulo = offset % alignment; |
| const bool is_aligned = (0 == modulo) ? true : false; |
| const bool should_fail = !is_aligned; |
| |
| testCase test_case = { offset, should_fail, (Utils::Shader::STAGES)stage, type }; |
| |
| m_test_cases.push_back(test_case); |
| } |
| } |
| } |
| } |
| |
| /** Constructor |
| * |
| * @param context Test framework context |
| **/ |
| UniformBlockMemberOverlappingOffsetsTest::UniformBlockMemberOverlappingOffsetsTest(deqp::Context& context) |
| : NegativeTestBase(context, "uniform_block_member_overlapping_offsets", |
| "Test verifies that overlapping offsets qualifiers cause compilation failure") |
| { |
| /* Nothing to be done here */ |
| } |
| |
| /** Constructor |
| * |
| * @param context Test framework context |
| * @param name Test name |
| * @param description Test description |
| **/ |
| UniformBlockMemberOverlappingOffsetsTest::UniformBlockMemberOverlappingOffsetsTest(deqp::Context& context, |
| const glw::GLchar* name, |
| const glw::GLchar* description) |
| : NegativeTestBase(context, name, description) |
| { |
| /* Nothing to be done here */ |
| } |
| |
| /** Source for given test case and stage |
| * |
| * @param test_case_index Index of test case |
| * @param stage Shader stage |
| * |
| * @return Shader source |
| **/ |
| std::string UniformBlockMemberOverlappingOffsetsTest::getShaderSource(GLuint test_case_index, |
| Utils::Shader::STAGES stage) |
| { |
| static const GLchar* cs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n" |
| "\n" |
| "layout (std140) uniform Block {\n" |
| " layout (offset = BOY_OFFSET) BOY_TYPE boy;\n" |
| " layout (offset = MAN_OFFSET) MAN_TYPE man;\n" |
| "} block;\n" |
| "\n" |
| "writeonly uniform image2D uni_image;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = vec4(1, 0, 0.5, 1);\n" |
| "\n" |
| " if ((BOY_TYPE(1) == block.boy) ||\n" |
| " (MAN_TYPE(0) == block.man) )\n" |
| " {\n" |
| " result = vec4(1, 1, 1, 1);\n" |
| " }\n" |
| "\n" |
| " imageStore(uni_image, ivec2(gl_GlobalInvocationID.xy), result);\n" |
| "}\n" |
| "\n"; |
| static const GLchar* fs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 gs_fs;\n" |
| "out vec4 fs_out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " fs_out = gs_fs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* fs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout (std140) uniform Block {\n" |
| " layout (offset = BOY_OFFSET) BOY_TYPE boy;\n" |
| " layout (offset = MAN_OFFSET) MAN_TYPE man;\n" |
| "} block;\n" |
| "\n" |
| "in vec4 gs_fs;\n" |
| "out vec4 fs_out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " if ((BOY_TYPE(1) == block.boy) ||\n" |
| " (MAN_TYPE(0) == block.man) )\n" |
| " {\n" |
| " fs_out = vec4(1, 1, 1, 1);\n" |
| " }\n" |
| "\n" |
| " fs_out += gs_fs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* gs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| "in vec4 tes_gs[];\n" |
| "out vec4 gs_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| static const GLchar* gs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| "layout (std140) uniform Block {\n" |
| " layout (offset = BOY_OFFSET) BOY_TYPE boy;\n" |
| " layout (offset = MAN_OFFSET) MAN_TYPE man;\n" |
| "} block;\n" |
| "\n" |
| "in vec4 tes_gs[];\n" |
| "out vec4 gs_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " if ((BOY_TYPE(1) == block.boy) ||\n" |
| " (MAN_TYPE(0) == block.man) )\n" |
| " {\n" |
| " gs_fs = vec4(1, 1, 1, 1);\n" |
| " }\n" |
| "\n" |
| " gs_fs += tes_gs[0];\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs += tes_gs[0];\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs += tes_gs[0];\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs += tes_gs[0];\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tcs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "in vec4 vs_tcs[];\n" |
| "out vec4 tcs_tes[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| "\n" |
| " tcs_tes[gl_InvocationID] = vs_tcs[gl_InvocationID];\n" |
| "\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tcs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "layout (std140) uniform Block {\n" |
| " layout (offset = BOY_OFFSET) BOY_TYPE boy;\n" |
| " layout (offset = MAN_OFFSET) MAN_TYPE man;\n" |
| "} block;\n" |
| "\n" |
| "in vec4 vs_tcs[];\n" |
| "out vec4 tcs_tes[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " if ((BOY_TYPE(1) == block.boy) ||\n" |
| " (MAN_TYPE(0) == block.man) )\n" |
| " {\n" |
| " tcs_tes[gl_InvocationID] = vec4(1, 1, 1, 1);\n" |
| " }\n" |
| "\n" |
| "\n" |
| " tcs_tes[gl_InvocationID] += vs_tcs[gl_InvocationID];\n" |
| "\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tes = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(isolines, point_mode) in;\n" |
| "\n" |
| "in vec4 tcs_tes[];\n" |
| "out vec4 tes_gs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " tes_gs = tcs_tes[0];\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tes_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(isolines, point_mode) in;\n" |
| "\n" |
| "layout (std140) uniform Block {\n" |
| " layout (offset = BOY_OFFSET) BOY_TYPE boy;\n" |
| " layout (offset = MAN_OFFSET) MAN_TYPE man;\n" |
| "} block;\n" |
| "\n" |
| "in vec4 tcs_tes[];\n" |
| "out vec4 tes_gs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " if ((BOY_TYPE(1) == block.boy) ||\n" |
| " (MAN_TYPE(0) == block.man) )\n" |
| " {\n" |
| " tes_gs = vec4(1, 1, 1, 1);\n" |
| " }\n" |
| "\n" |
| " tes_gs += tcs_tes[0];\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 vs_tcs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vs_tcs = in_vs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout (std140) uniform Block {\n" |
| " layout (offset = BOY_OFFSET) BOY_TYPE boy;\n" |
| " layout (offset = MAN_OFFSET) MAN_TYPE man;\n" |
| "} block;\n" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 vs_tcs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " if ((BOY_TYPE(1) == block.boy) ||\n" |
| " (MAN_TYPE(0) == block.man) )\n" |
| " {\n" |
| " vs_tcs = vec4(1, 1, 1, 1);\n" |
| " }\n" |
| "\n" |
| " vs_tcs += in_vs;\n" |
| "}\n" |
| "\n"; |
| |
| std::string source; |
| testCase& test_case = m_test_cases[test_case_index]; |
| |
| if (test_case.m_stage == stage) |
| { |
| GLchar buffer[16]; |
| const GLuint boy_offset = test_case.m_boy_offset; |
| const Utils::Type& boy_type = test_case.m_boy_type; |
| const GLchar* boy_type_name = boy_type.GetGLSLTypeName(); |
| const GLuint man_offset = test_case.m_man_offset; |
| const Utils::Type& man_type = test_case.m_man_type; |
| const GLchar* man_type_name = man_type.GetGLSLTypeName(); |
| size_t position = 0; |
| |
| switch (stage) |
| { |
| case Utils::Shader::COMPUTE: |
| source = cs; |
| break; |
| case Utils::Shader::FRAGMENT: |
| source = fs_tested; |
| break; |
| case Utils::Shader::GEOMETRY: |
| source = gs_tested; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| source = tcs_tested; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| source = tes_tested; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs_tested; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| sprintf(buffer, "%d", boy_offset); |
| Utils::replaceToken("BOY_OFFSET", position, buffer, source); |
| Utils::replaceToken("BOY_TYPE", position, boy_type_name, source); |
| sprintf(buffer, "%d", man_offset); |
| Utils::replaceToken("MAN_OFFSET", position, buffer, source); |
| Utils::replaceToken("MAN_TYPE", position, man_type_name, source); |
| Utils::replaceToken("BOY_TYPE", position, boy_type_name, source); |
| Utils::replaceToken("MAN_TYPE", position, man_type_name, source); |
| } |
| else |
| { |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs; |
| break; |
| case Utils::Shader::GEOMETRY: |
| source = gs; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| source = tcs; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| source = tes; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| } |
| |
| return source; |
| } |
| |
| /** Get description of test case |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return Type name and offset |
| **/ |
| std::string UniformBlockMemberOverlappingOffsetsTest::getTestCaseName(GLuint test_case_index) |
| { |
| std::stringstream stream; |
| testCase& test_case = m_test_cases[test_case_index]; |
| |
| stream << "Type: " << test_case.m_boy_type.GetGLSLTypeName() << ", offset: " << test_case.m_boy_offset |
| << ". Type: " << test_case.m_man_type.GetGLSLTypeName() << ", offset: " << test_case.m_man_offset; |
| |
| return stream.str(); |
| } |
| |
| /** Get number of test cases |
| * |
| * @return Number of test cases |
| **/ |
| GLuint UniformBlockMemberOverlappingOffsetsTest::getTestCaseNumber() |
| { |
| return static_cast<GLuint>(m_test_cases.size()); |
| } |
| |
| /** Selects if "compute" stage is relevant for test |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return true when tested stage is compute |
| **/ |
| bool UniformBlockMemberOverlappingOffsetsTest::isComputeRelevant(GLuint test_case_index) |
| { |
| return (Utils::Shader::COMPUTE == m_test_cases[test_case_index].m_stage); |
| } |
| |
| /** Checks if stage is supported |
| * |
| * @param stage ignored |
| * |
| * @return true |
| **/ |
| bool UniformBlockMemberOverlappingOffsetsTest::isStageSupported(Utils::Shader::STAGES /* stage */) |
| { |
| return true; |
| } |
| |
| /** Prepare all test cases |
| * |
| **/ |
| void UniformBlockMemberOverlappingOffsetsTest::testInit() |
| { |
| const GLuint n_types = getTypesNumber(); |
| bool stage_support[Utils::Shader::STAGE_MAX]; |
| |
| for (GLuint stage = 0; stage < Utils::Shader::STAGE_MAX; ++stage) |
| { |
| stage_support[stage] = isStageSupported((Utils::Shader::STAGES)stage); |
| } |
| |
| for (GLuint i = 0; i < n_types; ++i) |
| { |
| const Utils::Type& boy_type = getType(i); |
| const GLuint boy_size = boy_type.GetActualAlignment(1 /* align */, false /* is_array*/); |
| |
| for (GLuint j = 0; j < n_types; ++j) |
| { |
| const Utils::Type& man_type = getType(j); |
| const GLuint man_align = man_type.GetBaseAlignment(false); |
| const GLuint man_size = man_type.GetActualAlignment(1 /* align */, false /* is_array*/); |
| |
| const GLuint boy_offset = lcm(boy_size, man_size); |
| const GLuint man_after_start = boy_offset + 1; |
| const GLuint man_after_off = man_type.GetActualOffset(man_after_start, man_size); |
| const GLuint man_before_start = boy_offset - man_align; |
| const GLuint man_before_off = man_type.GetActualOffset(man_before_start, man_size); |
| |
| for (GLuint stage = 0; stage < Utils::Shader::STAGE_MAX; ++stage) |
| { |
| if (false == stage_support[stage]) |
| { |
| continue; |
| } |
| |
| if ((boy_offset > man_before_off) && (boy_offset < man_before_off + man_size)) |
| { |
| testCase test_case = { boy_offset, boy_type, man_before_off, man_type, |
| (Utils::Shader::STAGES)stage }; |
| |
| m_test_cases.push_back(test_case); |
| } |
| |
| if ((boy_offset < man_after_off) && (boy_offset + boy_size > man_after_off)) |
| { |
| testCase test_case = { boy_offset, boy_type, man_after_off, man_type, |
| (Utils::Shader::STAGES)stage }; |
| |
| m_test_cases.push_back(test_case); |
| } |
| |
| /* Boy offset, should be fine for both types */ |
| testCase test_case = { boy_offset, boy_type, boy_offset, man_type, (Utils::Shader::STAGES)stage }; |
| |
| m_test_cases.push_back(test_case); |
| } |
| } |
| } |
| } |
| |
| /** Find greatest common divisor for a and b |
| * |
| * @param a A argument |
| * @param b B argument |
| * |
| * @return Found gcd value |
| **/ |
| GLuint UniformBlockMemberOverlappingOffsetsTest::gcd(GLuint a, GLuint b) |
| { |
| if ((0 != a) && (0 == b)) |
| { |
| return a; |
| } |
| else |
| { |
| GLuint greater = std::max(a, b); |
| GLuint lesser = std::min(a, b); |
| |
| return gcd(lesser, greater % lesser); |
| } |
| } |
| |
| /** Find lowest common multiple for a and b |
| * |
| * @param a A argument |
| * @param b B argument |
| * |
| * @return Found gcd value |
| **/ |
| GLuint UniformBlockMemberOverlappingOffsetsTest::lcm(GLuint a, GLuint b) |
| { |
| return (a * b) / gcd(a, b); |
| } |
| |
| /** Constructor |
| * |
| * @param context Test framework context |
| **/ |
| UniformBlockMemberAlignNonPowerOf2Test::UniformBlockMemberAlignNonPowerOf2Test(deqp::Context& context) |
| : NegativeTestBase(context, "uniform_block_member_align_non_power_of_2", |
| "Test verifies that align qualifier requires value that is a power of 2") |
| { |
| /* Nothing to be done here */ |
| } |
| |
| /** Constructor |
| * |
| * @param context Test framework context |
| * @param name Test name |
| * @param description Test description |
| **/ |
| UniformBlockMemberAlignNonPowerOf2Test::UniformBlockMemberAlignNonPowerOf2Test(deqp::Context& context, |
| const glw::GLchar* name, |
| const glw::GLchar* description) |
| : NegativeTestBase(context, name, description) |
| { |
| /* Nothing to be done here */ |
| } |
| |
| /** Source for given test case and stage |
| * |
| * @param test_case_index Index of test case |
| * @param stage Shader stage |
| * |
| * @return Shader source |
| **/ |
| std::string UniformBlockMemberAlignNonPowerOf2Test::getShaderSource(GLuint test_case_index, Utils::Shader::STAGES stage) |
| { |
| static const GLchar* cs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n" |
| "\n" |
| "layout (std140) uniform Block {\n" |
| " vec4 boy;\n" |
| " layout (align = ALIGN) TYPE man;\n" |
| "} block;\n" |
| "\n" |
| "writeonly uniform image2D uni_image;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = vec4(1, 0, 0.5, 1);\n" |
| "\n" |
| " if (TYPE(0) == block.man)\n" |
| " {\n" |
| " result = vec4(1, 1, 1, 1) - block.boy;\n" |
| " }\n" |
| "\n" |
| " imageStore(uni_image, ivec2(gl_GlobalInvocationID.xy), result);\n" |
| "}\n" |
| "\n"; |
| static const GLchar* fs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 gs_fs;\n" |
| "out vec4 fs_out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " fs_out = gs_fs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* fs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout (std140) uniform Block {\n" |
| " vec4 boy;\n" |
| " layout (align = ALIGN) TYPE man;\n" |
| "} block;\n" |
| "\n" |
| "in vec4 gs_fs;\n" |
| "out vec4 fs_out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " if (TYPE(0) == block.man)\n" |
| " {\n" |
| " fs_out = block.boy;\n" |
| " }\n" |
| "\n" |
| " fs_out += gs_fs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* gs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| "in vec4 tes_gs[];\n" |
| "out vec4 gs_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| static const GLchar* gs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| "layout (std140) uniform Block {\n" |
| " vec4 boy;\n" |
| " layout (align = ALIGN) TYPE man;\n" |
| "} block;\n" |
| "\n" |
| "in vec4 tes_gs[];\n" |
| "out vec4 gs_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " if (TYPE(0) == block.man)\n" |
| " {\n" |
| " gs_fs = block.boy;\n" |
| " }\n" |
| "\n" |
| " gs_fs += tes_gs[0];\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs += tes_gs[0];\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs += tes_gs[0];\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs += tes_gs[0];\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tcs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "in vec4 vs_tcs[];\n" |
| "out vec4 tcs_tes[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| "\n" |
| " tcs_tes[gl_InvocationID] = vs_tcs[gl_InvocationID];\n" |
| "\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tcs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "layout (std140) uniform Block {\n" |
| " vec4 boy;\n" |
| " layout (align = ALIGN) TYPE man;\n" |
| "} block;\n" |
| "\n" |
| "in vec4 vs_tcs[];\n" |
| "out vec4 tcs_tes[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " if (TYPE(0) == block.man)\n" |
| " {\n" |
| " tcs_tes[gl_InvocationID] = block.boy;\n" |
| " }\n" |
| "\n" |
| "\n" |
| " tcs_tes[gl_InvocationID] += vs_tcs[gl_InvocationID];\n" |
| "\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tes = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(isolines, point_mode) in;\n" |
| "\n" |
| "in vec4 tcs_tes[];\n" |
| "out vec4 tes_gs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " tes_gs = tcs_tes[0];\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tes_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(isolines, point_mode) in;\n" |
| "\n" |
| "layout (std140) uniform Block {\n" |
| " vec4 boy;\n" |
| " layout (align = ALIGN) TYPE man;\n" |
| "} block;\n" |
| "\n" |
| "in vec4 tcs_tes[];\n" |
| "out vec4 tes_gs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " if (TYPE(0) == block.man)\n" |
| " {\n" |
| " tes_gs = block.boy;\n" |
| " }\n" |
| "\n" |
| " tes_gs += tcs_tes[0];\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 vs_tcs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vs_tcs = in_vs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout (std140) uniform Block {\n" |
| " vec4 boy;\n" |
| " layout (align = ALIGN) TYPE man;\n" |
| "} block;\n" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 vs_tcs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " if (TYPE(0) == block.man)\n" |
| " {\n" |
| " vs_tcs = block.boy;\n" |
| " }\n" |
| "\n" |
| " vs_tcs += in_vs;\n" |
| "}\n" |
| "\n"; |
| |
| std::string source; |
| testCase& test_case = m_test_cases[test_case_index]; |
| |
| if (test_case.m_stage == stage) |
| { |
| GLchar buffer[16]; |
| const GLuint alignment = test_case.m_alignment; |
| const Utils::Type& type = test_case.m_type; |
| const GLchar* type_name = type.GetGLSLTypeName(); |
| size_t position = 0; |
| |
| switch (stage) |
| { |
| case Utils::Shader::COMPUTE: |
| source = cs; |
| break; |
| case Utils::Shader::FRAGMENT: |
| source = fs_tested; |
| break; |
| case Utils::Shader::GEOMETRY: |
| source = gs_tested; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| source = tcs_tested; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| source = tes_tested; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs_tested; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| sprintf(buffer, "%d", alignment); |
| Utils::replaceToken("ALIGN", position, buffer, source); |
| Utils::replaceToken("TYPE", position, type_name, source); |
| Utils::replaceToken("TYPE", position, type_name, source); |
| } |
| else |
| { |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs; |
| break; |
| case Utils::Shader::GEOMETRY: |
| source = gs; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| source = tcs; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| source = tes; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| } |
| |
| return source; |
| } |
| |
| /** Get description of test case |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return Type name and offset |
| **/ |
| std::string UniformBlockMemberAlignNonPowerOf2Test::getTestCaseName(GLuint test_case_index) |
| { |
| std::stringstream stream; |
| testCase& test_case = m_test_cases[test_case_index]; |
| |
| stream << "Type: " << test_case.m_type.GetGLSLTypeName() << ", align: " << test_case.m_alignment; |
| |
| return stream.str(); |
| } |
| |
| /** Get number of test cases |
| * |
| * @return Number of test cases |
| **/ |
| GLuint UniformBlockMemberAlignNonPowerOf2Test::getTestCaseNumber() |
| { |
| return static_cast<GLuint>(m_test_cases.size()); |
| } |
| |
| /** Selects if "compute" stage is relevant for test |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return true when tested stage is compute |
| **/ |
| bool UniformBlockMemberAlignNonPowerOf2Test::isComputeRelevant(GLuint test_case_index) |
| { |
| return (Utils::Shader::COMPUTE == m_test_cases[test_case_index].m_stage); |
| } |
| |
| /** Checks if stage is supported |
| * |
| * @param ignored |
| * |
| * @return true |
| **/ |
| bool UniformBlockMemberAlignNonPowerOf2Test::isStageSupported(Utils::Shader::STAGES /* stage */) |
| { |
| return true; |
| } |
| |
| /** Selects if compilation failure is expected result |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return should_fail field from testCase |
| **/ |
| bool UniformBlockMemberAlignNonPowerOf2Test::isFailureExpected(GLuint test_case_index) |
| { |
| return m_test_cases[test_case_index].m_should_fail; |
| } |
| |
| /** Prepare all test cases |
| * |
| **/ |
| void UniformBlockMemberAlignNonPowerOf2Test::testInit() |
| { |
| static const GLuint dmat4_size = 128; |
| const GLuint n_types = getTypesNumber(); |
| bool stage_support[Utils::Shader::STAGE_MAX]; |
| |
| for (GLuint stage = 0; stage < Utils::Shader::STAGE_MAX; ++stage) |
| { |
| stage_support[stage] = isStageSupported((Utils::Shader::STAGES)stage); |
| } |
| |
| for (GLuint j = 0; j < n_types; ++j) |
| { |
| const Utils::Type& type = getType(j); |
| |
| for (GLuint align = 0; align <= dmat4_size; ++align) |
| { |
| |
| #if WRKARD_UNIFORMBLOCKMEMBERALIGNNONPOWEROF2TEST |
| |
| const bool should_fail = (0 == align) ? false : !isPowerOf2(align); |
| |
| #else /* WRKARD_UNIFORMBLOCKMEMBERALIGNNONPOWEROF2TEST */ |
| |
| const bool should_fail = !isPowerOf2(align); |
| |
| #endif /* WRKARD_UNIFORMBLOCKMEMBERALIGNNONPOWEROF2TEST */ |
| |
| for (GLuint stage = 0; stage < Utils::Shader::STAGE_MAX; ++stage) |
| { |
| if (false == stage_support[stage]) |
| { |
| continue; |
| } |
| |
| testCase test_case = { align, type, should_fail, (Utils::Shader::STAGES)stage }; |
| |
| m_test_cases.push_back(test_case); |
| } |
| } |
| } |
| } |
| |
| /** Check if value is power of 2 |
| * |
| * @param val Tested value |
| * |
| * @return true if val is power of 2, false otherwise |
| **/ |
| bool UniformBlockMemberAlignNonPowerOf2Test::isPowerOf2(GLuint val) |
| { |
| if (0 == val) |
| { |
| return false; |
| } |
| |
| return (0 == (val & (val - 1))); |
| } |
| |
| /** Constructor |
| * |
| * @param context Test framework context |
| **/ |
| UniformBlockAlignmentTest::UniformBlockAlignmentTest(deqp::Context& context) |
| : TextureTestBase(context, "uniform_block_alignment", "Test verifies offset and alignment of uniform buffer") |
| { |
| } |
| |
| /** Get interface of program |
| * |
| * @param ignored |
| * @param program_interface Interface of program |
| * @param varying_passthrough Collection of connections between in and out variables |
| **/ |
| void UniformBlockAlignmentTest::getProgramInterface(GLuint /* test_case_index */, |
| Utils::ProgramInterface& program_interface, |
| Utils::VaryingPassthrough& varying_passthrough) |
| { |
| static const Utils::Type vec4 = Utils::Type::vec4; |
| |
| #if WRKARD_UNIFORMBLOCKALIGNMENT |
| |
| static const GLuint block_align = 16; |
| |
| #else /* WRKARD_UNIFORMBLOCKALIGNMENT */ |
| |
| static const GLuint block_align = 64; |
| |
| #endif /* WRKARD_UNIFORMBLOCKALIGNMENT */ |
| |
| static const GLuint vec4_stride = 16; |
| static const GLuint data_stride = vec4_stride * 2; /* one vec4 + one scalar aligned to 16 */ |
| |
| /*Fixed a test issue, the fifth_offset should be calculated by block_align, instead of fifth_align, according to spec, the actual |
| alignment of a member will be the greater of the specified alignment and the base aligment for the member type |
| */ |
| const GLuint first_offset = 0; /* vec4 at 0 */ |
| const GLuint second_offset = Utils::Type::GetActualOffset(first_offset + vec4_stride, block_align); /* Data at 32 */ |
| const GLuint third_offset = |
| Utils::Type::GetActualOffset(second_offset + data_stride, block_align); /* Data[2] at 64 */ |
| const GLuint fourth_offset = |
| Utils::Type::GetActualOffset(third_offset + data_stride * 2, block_align); /* vec4[3] at 96 */ |
| const GLuint fifth_offset = |
| Utils::Type::GetActualOffset(fourth_offset + vec4_stride * 3, block_align); /* vec4[2] at 160 */ |
| const GLuint sixth_offset = |
| Utils::Type::GetActualOffset(fifth_offset + vec4_stride * 2, block_align); /* Data at 192 */ |
| |
| Utils::Interface* structure = program_interface.Structure("Data"); |
| |
| structure->Member("vector", "", 0 /* expected_component */, 0 /* expected_location */, Utils::Type::vec4, |
| false /* normalized */, 0 /* n_array_elements */, Utils::Type::vec4.GetSize(), 0 /* offset */); |
| |
| structure->Member("scalar", "", 0 /* expected_component */, 0 /* expected_location */, Utils::Type::_float, |
| false /* normalized */, 0 /* n_array_elements */, Utils::Type::_float.GetSize(), |
| Utils::Type::vec4.GetSize() /* offset */); |
| |
| /* Prepare Block */ |
| Utils::Interface* vs_uni_block = program_interface.Block("vs_uni_Block"); |
| |
| vs_uni_block->Member("first", "", 0 /* expected_component */, 0 /* expected_location */, Utils::Type::vec4, |
| false /* normalized */, 0 /* n_array_elements */, vec4_stride, first_offset /* offset */); |
| |
| vs_uni_block->Member("second", "", 0 /* expected_component */, 0 /* expected_location */, structure, |
| 0 /* n_array_elements */, data_stride, second_offset); |
| |
| vs_uni_block->Member("third", "", 0 /* expected_component */, 0 /* expected_location */, structure, |
| 2 /* n_array_elements */, data_stride, third_offset); |
| |
| vs_uni_block->Member("fourth", "", 0 /* expected_component */, 0 /* expected_location */, vec4, |
| false /* normalized */, 3 /* n_array_elements */, vec4_stride, fourth_offset); |
| |
| vs_uni_block->Member("fifth", "layout(align = 64)", 0 /* expected_component */, 0 /* expected_location */, vec4, |
| false /* normalized */, 2 /* n_array_elements */, vec4_stride, fifth_offset); |
| |
| vs_uni_block->Member("sixth", "", 0 /* expected_component */, 0 /* expected_location */, structure, |
| 0 /* n_array_elements */, data_stride, sixth_offset); |
| |
| const GLuint stride = calculateStride(*vs_uni_block); |
| m_data.resize(stride); |
| generateData(*vs_uni_block, 0, m_data); |
| |
| Utils::ShaderInterface& vs_si = program_interface.GetShaderInterface(Utils::Shader::VERTEX); |
| |
| /* Add uniform BLOCK */ |
| #if WRKARD_UNIFORMBLOCKALIGNMENT |
| vs_si.Uniform("vs_uni_block", "layout (std140, binding = BINDING)", 0, 0, vs_uni_block, 0, |
| static_cast<GLuint>(m_data.size()), 0, &m_data[0], m_data.size()); |
| #else /* WRKARD_UNIFORMBLOCKALIGNMENT */ |
| vs_si.Uniform("vs_uni_block", "layout (std140, binding = BINDING, align = 64)", 0, 0, vs_uni_block, 0, |
| static_cast<GLuint>(m_data.size()), 0, &m_data[0], m_data.size()); |
| #endif /* WRKARD_UNIFORMBLOCKALIGNMENT */ |
| |
| program_interface.CloneVertexInterface(varying_passthrough); |
| } |
| |
| /** Constructor |
| * |
| * @param context Test framework context |
| **/ |
| SSBMemberOffsetAndAlignTest::SSBMemberOffsetAndAlignTest(deqp::Context& context) |
| : TextureTestBase(context, "ssb_member_offset_and_align", |
| "Test verifies offsets and alignment of storage buffer members") |
| { |
| } |
| |
| /** Get interface of program |
| * |
| * @param test_case_index Test case index |
| * @param program_interface Interface of program |
| * @param varying_passthrough Collection of connections between in and out variables |
| **/ |
| void SSBMemberOffsetAndAlignTest::getProgramInterface(GLuint test_case_index, |
| Utils::ProgramInterface& program_interface, |
| Utils::VaryingPassthrough& varying_passthrough) |
| { |
| std::string globals = "const int basic_size = BASIC_SIZE;\n" |
| "const int type_align = TYPE_ALIGN;\n" |
| "const int type_size = TYPE_SIZE;\n"; |
| |
| Utils::Type type = getType(test_case_index); |
| GLuint basic_size = Utils::Type::GetTypeSize(type.m_basic_type); |
| const GLuint base_align = type.GetBaseAlignment(false); |
| const GLuint array_align = type.GetBaseAlignment(true); |
| const GLuint base_stride = Utils::Type::CalculateStd140Stride(base_align, type.m_n_columns, 0); |
| const GLuint type_align = Utils::roundUpToPowerOf2(base_stride); |
| |
| /* Calculate offsets */ |
| const GLuint first_offset = 0; |
| const GLuint second_offset = type.GetActualOffset(base_stride, basic_size / 2); |
| |
| #if WRKARD_UNIFORMBLOCKMEMBEROFFSETANDALIGNTEST |
| |
| const GLuint third_offset = type.GetActualOffset(second_offset + base_stride, base_align); |
| const GLuint fourth_offset = type.GetActualOffset(third_offset + base_stride, base_align); |
| const GLuint fifth_offset = type.GetActualOffset(fourth_offset + base_stride, base_align); |
| const GLuint sixth_offset = type.GetActualOffset(fifth_offset + base_stride, array_align); |
| const GLuint seventh_offset = type.GetActualOffset(sixth_offset + base_stride, array_align); |
| const GLuint eigth_offset = type.GetActualOffset(seventh_offset + base_stride, array_align); |
| |
| #else /* WRKARD_UNIFORMBLOCKMEMBEROFFSETANDALIGNTEST */ |
| |
| const GLuint third_offset = type.GetActualOffset(second_offset + base_stride, 2 * type_align); |
| const GLuint fourth_offset = type.GetActualOffset(3 * type_align + base_stride, base_align); |
| const GLuint fifth_offset = type.GetActualOffset(fourth_offset + base_stride, base_align); |
| const GLuint sixth_offset = type.GetActualOffset(fifth_offset + base_stride, array_align); |
| const GLuint seventh_offset = type.GetActualOffset(sixth_offset + base_stride, array_align); |
| const GLuint eigth_offset = type.GetActualOffset(seventh_offset + base_stride, 8 * basic_size); |
| |
| #endif /* WRKARD_UNIFORMBLOCKMEMBEROFFSETANDALIGNTEST */ |
| |
| /* Prepare data */ |
| const std::vector<GLubyte>& first = type.GenerateData(); |
| const std::vector<GLubyte>& second = type.GenerateData(); |
| const std::vector<GLubyte>& third = type.GenerateData(); |
| const std::vector<GLubyte>& fourth = type.GenerateData(); |
| |
| m_data.resize(eigth_offset + base_stride); |
| GLubyte* ptr = &m_data[0]; |
| memcpy(ptr + first_offset, &first[0], first.size()); |
| memcpy(ptr + second_offset, &second[0], second.size()); |
| memcpy(ptr + third_offset, &third[0], third.size()); |
| memcpy(ptr + fourth_offset, &fourth[0], fourth.size()); |
| memcpy(ptr + fifth_offset, &fourth[0], fourth.size()); |
| memcpy(ptr + sixth_offset, &third[0], third.size()); |
| memcpy(ptr + seventh_offset, &second[0], second.size()); |
| memcpy(ptr + eigth_offset, &first[0], first.size()); |
| |
| /* Prepare globals */ |
| size_t position = 0; |
| GLchar buffer[16]; |
| |
| sprintf(buffer, "%d", basic_size); |
| Utils::replaceToken("BASIC_SIZE", position, buffer, globals); |
| |
| sprintf(buffer, "%d", type_align); |
| Utils::replaceToken("TYPE_ALIGN", position, buffer, globals); |
| |
| sprintf(buffer, "%d", base_stride); |
| Utils::replaceToken("TYPE_SIZE", position, buffer, globals); |
| |
| /* Prepare Block */ |
| Utils::Interface* vs_buf_block = program_interface.Block("vs_buf_Block"); |
| |
| vs_buf_block->Member("at_first_offset", "layout(offset = 0, align = 8 * basic_size)", 0 /* expected_component */, |
| 0 /* expected_location */, type, false /* normalized */, 0 /* n_array_elements */, base_stride, |
| first_offset); |
| |
| vs_buf_block->Member("at_second_offset", "layout(offset = type_size, align = basic_size / 2)", |
| 0 /* expected_component */, 0 /* expected_location */, type, false /* normalized */, |
| 0 /* n_array_elements */, base_stride, second_offset); |
| |
| vs_buf_block->Member("at_third_offset", "layout(align = 2 * type_align)", 0 /* expected_component */, |
| 0 /* expected_location */, type, false /* normalized */, 0 /* n_array_elements */, base_stride, |
| third_offset); |
| |
| vs_buf_block->Member("at_fourth_offset", "layout(offset = 3 * type_align + type_size)", 0 /* expected_component */, |
| 0 /* expected_location */, type, false /* normalized */, 0 /* n_array_elements */, base_stride, |
| fourth_offset); |
| |
| vs_buf_block->Member("at_fifth_offset", "", 0 /* expected_component */, 0 /* expected_location */, type, |
| false /* normalized */, 0 /* n_array_elements */, base_stride, fifth_offset); |
| |
| vs_buf_block->Member("at_sixth_offset", "", 0 /* expected_component */, 0 /* expected_location */, type, |
| false /* normalized */, 2 /* n_array_elements */, array_align * 2, sixth_offset); |
| |
| vs_buf_block->Member("at_eigth_offset", "layout(align = 8 * basic_size)", 0 /* expected_component */, |
| 0 /* expected_location */, type, false /* normalized */, 0 /* n_array_elements */, base_stride, |
| eigth_offset); |
| |
| Utils::ShaderInterface& vs_si = program_interface.GetShaderInterface(Utils::Shader::VERTEX); |
| |
| /* Add globals */ |
| vs_si.m_globals = globals; |
| |
| /* Add uniform BLOCK */ |
| vs_si.SSB("vs_buf_block", "layout (std140, binding = BINDING)", 0, 0, vs_buf_block, 0, |
| static_cast<GLuint>(m_data.size()), 0, &m_data[0], m_data.size()); |
| |
| /* */ |
| program_interface.CloneVertexInterface(varying_passthrough); |
| } |
| |
| /** Get type name |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return Name of type test in test_case_index |
| **/ |
| std::string SSBMemberOffsetAndAlignTest::getTestCaseName(glw::GLuint test_case_index) |
| { |
| return getTypeName(test_case_index); |
| } |
| |
| /** Returns number of types to test |
| * |
| * @return Number of types, 34 |
| **/ |
| glw::GLuint SSBMemberOffsetAndAlignTest::getTestCaseNumber() |
| { |
| return getTypesNumber(); |
| } |
| |
| /** Prepare code snippet that will verify in and uniform variables |
| * |
| * @param ignored |
| * @param ignored |
| * @param stage Shader stage |
| * |
| * @return Code that verify variables |
| **/ |
| std::string SSBMemberOffsetAndAlignTest::getVerificationSnippet(GLuint /* test_case_index */, |
| Utils::ProgramInterface& /* program_interface */, |
| Utils::Shader::STAGES stage) |
| { |
| std::string verification = "if ( (PREFIXblock.at_first_offset != PREFIXblock.at_eigth_offset ) ||\n" |
| " (PREFIXblock.at_second_offset != PREFIXblock.at_sixth_offset[1]) ||\n" |
| " (PREFIXblock.at_third_offset != PREFIXblock.at_sixth_offset[0]) ||\n" |
| " (PREFIXblock.at_fourth_offset != PREFIXblock.at_fifth_offset ) )\n" |
| " {\n" |
| " result = 0;\n" |
| " }"; |
| |
| const GLchar* prefix = Utils::ProgramInterface::GetStagePrefix(stage, Utils::Variable::SSB); |
| |
| Utils::replaceAllTokens("PREFIX", prefix, verification); |
| |
| return verification; |
| } |
| |
| /** Selects if "draw" stages are relevant for test |
| * |
| * @param ignored |
| * |
| * @return true if all stages support shader storage buffers, false otherwise |
| **/ |
| bool SSBMemberOffsetAndAlignTest::isDrawRelevant(GLuint /* test_case_index */) |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| GLint gs_supported_buffers = 0; |
| GLint tcs_supported_buffers = 0; |
| GLint tes_supported_buffers = 0; |
| GLint vs_supported_buffers = 0; |
| |
| gl.getIntegerv(GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS, &gs_supported_buffers); |
| gl.getIntegerv(GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS, &tcs_supported_buffers); |
| gl.getIntegerv(GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS, &tes_supported_buffers); |
| gl.getIntegerv(GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, &vs_supported_buffers); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv"); |
| |
| return ((1 <= gs_supported_buffers) && (1 <= tcs_supported_buffers) && (1 <= tes_supported_buffers) && |
| (1 <= vs_supported_buffers)); |
| } |
| |
| /** Constructor |
| * |
| * @param context Test framework context |
| **/ |
| SSBLayoutQualifierConflictTest::SSBLayoutQualifierConflictTest(deqp::Context& context) |
| : NegativeTestBase(context, "ssb_layout_qualifier_conflict", "Test verifies that std140 or std430 is required when " |
| "offset and/or align qualifiers are used with storage " |
| "block") |
| { |
| /* Nothing to be done here */ |
| } |
| |
| /** Source for given test case and stage |
| * |
| * @param test_case_index Index of test case |
| * @param stage Shader stage |
| * |
| * @return Shader source |
| **/ |
| std::string SSBLayoutQualifierConflictTest::getShaderSource(GLuint test_case_index, Utils::Shader::STAGES stage) |
| { |
| static const GLchar* cs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n" |
| "\n" |
| "layout (QUALIFIERbinding = BINDING) buffer cs_Block {\n" |
| " layout(offset = 16) vec4 boy;\n" |
| " layout(align = 64) vec4 man;\n" |
| "} uni_block;\n" |
| "\n" |
| "writeonly uniform image2D uni_image;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = uni_block.boy + uni_block.man;\n" |
| "\n" |
| " imageStore(uni_image, ivec2(gl_GlobalInvocationID.xy), result);\n" |
| "}\n" |
| "\n"; |
| static const GLchar* fs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout (QUALIFIERbinding = BINDING) buffer Block {\n" |
| " layout(offset = 16) vec4 boy;\n" |
| " layout(align = 64) vec4 man;\n" |
| "} uni_block;\n" |
| "\n" |
| "in vec4 gs_fs;\n" |
| "out vec4 fs_out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " fs_out = gs_fs + uni_block.boy + uni_block.man;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* gs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| "layout (QUALIFIERbinding = BINDING) buffer gs_Block {\n" |
| " layout(offset = 16) vec4 boy;\n" |
| " layout(align = 64) vec4 man;\n" |
| "} uni_block;\n" |
| "\n" |
| "in vec4 tes_gs[];\n" |
| "out vec4 gs_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " gs_fs = tes_gs[0] + uni_block.boy + uni_block.man;\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0] + uni_block.boy + uni_block.man;\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0] + uni_block.boy + uni_block.man;\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0] + uni_block.boy + uni_block.man;\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tcs = |
| "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "layout (QUALIFIERbinding = BINDING) buffer tcs_Block {\n" |
| " layout(offset = 16) vec4 boy;\n" |
| " layout(align = 64) vec4 man;\n" |
| "} uni_block;\n" |
| "\n" |
| "in vec4 vs_tcs[];\n" |
| "out vec4 tcs_tes[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| "\n" |
| " tcs_tes[gl_InvocationID] = vs_tcs[gl_InvocationID] + uni_block.boy + uni_block.man;\n" |
| "\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tes = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(isolines, point_mode) in;\n" |
| "\n" |
| "layout (QUALIFIERbinding = BINDING) buffer tes_Block {\n" |
| " layout(offset = 16) vec4 boy;\n" |
| " layout(align = 64) vec4 man;\n" |
| "} uni_block;\n" |
| "\n" |
| "in vec4 tcs_tes[];\n" |
| "out vec4 tes_gs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " tes_gs = tcs_tes[0] + uni_block.boy + uni_block.man;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout (QUALIFIERbinding = BINDING) buffer vs_Block {\n" |
| " layout(offset = 16) vec4 boy;\n" |
| " layout(align = 64) vec4 man;\n" |
| "} uni_block;\n" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 vs_tcs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vs_tcs = in_vs + uni_block.boy + uni_block.man;\n" |
| "}\n" |
| "\n"; |
| |
| GLchar buffer[16]; |
| size_t position = 0; |
| std::string source; |
| testCase& test_case = m_test_cases[test_case_index]; |
| std::string qualifier = getQualifierName(test_case.m_qualifier); |
| |
| if (false == qualifier.empty()) |
| { |
| qualifier.append(", "); |
| } |
| |
| sprintf(buffer, "%d", stage); |
| |
| switch (stage) |
| { |
| case Utils::Shader::COMPUTE: |
| source = cs; |
| break; |
| case Utils::Shader::FRAGMENT: |
| source = fs; |
| break; |
| case Utils::Shader::GEOMETRY: |
| source = gs; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| source = tcs; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| source = tes; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| if (test_case.m_stage == stage) |
| { |
| Utils::replaceToken("QUALIFIER", position, qualifier.c_str(), source); |
| } |
| else |
| { |
| Utils::replaceToken("QUALIFIER", position, "std140, ", source); |
| } |
| |
| Utils::replaceToken("BINDING", position, buffer, source); |
| |
| return source; |
| } |
| |
| /** Get description of test case |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return Qualifier name |
| **/ |
| std::string SSBLayoutQualifierConflictTest::getTestCaseName(GLuint test_case_index) |
| { |
| std::string result = getQualifierName(m_test_cases[test_case_index].m_qualifier); |
| |
| return result; |
| } |
| |
| /** Get number of test cases |
| * |
| * @return Number of test cases |
| **/ |
| GLuint SSBLayoutQualifierConflictTest::getTestCaseNumber() |
| { |
| return static_cast<GLuint>(m_test_cases.size()); |
| } |
| |
| /** Selects if "compute" stage is relevant for test |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return true when tested stage is compute |
| **/ |
| bool SSBLayoutQualifierConflictTest::isComputeRelevant(GLuint test_case_index) |
| { |
| return (Utils::Shader::COMPUTE == m_test_cases[test_case_index].m_stage); |
| } |
| |
| /** Selects if compilation failure is expected result |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return false for STD140 and STD430 cases, true otherwise |
| **/ |
| bool SSBLayoutQualifierConflictTest::isFailureExpected(GLuint test_case_index) |
| { |
| const QUALIFIERS qualifier = m_test_cases[test_case_index].m_qualifier; |
| |
| return !((STD140 == qualifier) || (STD430 == qualifier)); |
| } |
| |
| /** Checks if stage is supported |
| * |
| * @param stage Shader stage |
| * |
| * @return true if supported, false otherwise |
| **/ |
| bool SSBLayoutQualifierConflictTest::isStageSupported(Utils::Shader::STAGES stage) |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| GLint max_supported_buffers = 0; |
| GLenum pname = 0; |
| |
| switch (stage) |
| { |
| case Utils::Shader::COMPUTE: |
| pname = GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS; |
| break; |
| case Utils::Shader::FRAGMENT: |
| pname = GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS; |
| break; |
| case Utils::Shader::GEOMETRY: |
| pname = GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| pname = GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| pname = GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS; |
| break; |
| case Utils::Shader::VERTEX: |
| pname = GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| gl.getIntegerv(pname, &max_supported_buffers); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv"); |
| |
| return 1 <= max_supported_buffers; |
| } |
| |
| /** Prepare all test cases |
| * |
| **/ |
| void SSBLayoutQualifierConflictTest::testInit() |
| { |
| bool stage_support[Utils::Shader::STAGE_MAX]; |
| |
| for (GLuint stage = 0; stage < Utils::Shader::STAGE_MAX; ++stage) |
| { |
| stage_support[stage] = isStageSupported((Utils::Shader::STAGES)stage); |
| } |
| |
| for (GLuint qualifier = 0; qualifier < QUALIFIERS_MAX; ++qualifier) |
| { |
| for (GLuint stage = 0; stage < Utils::Shader::STAGE_MAX; ++stage) |
| { |
| if (false == stage_support[stage]) |
| { |
| continue; |
| } |
| |
| testCase test_case = { (QUALIFIERS)qualifier, (Utils::Shader::STAGES)stage }; |
| |
| m_test_cases.push_back(test_case); |
| } |
| } |
| } |
| |
| /** Get name of glsl constant |
| * |
| * @param Constant id |
| * |
| * @return Name of constant used in GLSL |
| **/ |
| const GLchar* SSBLayoutQualifierConflictTest::getQualifierName(QUALIFIERS qualifier) |
| { |
| const GLchar* name = ""; |
| |
| switch (qualifier) |
| { |
| case DEFAULT: |
| name = ""; |
| break; |
| case STD140: |
| name = "std140"; |
| break; |
| case STD430: |
| name = "std430"; |
| break; |
| case SHARED: |
| name = "shared"; |
| break; |
| case PACKED: |
| name = "packed"; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| return name; |
| } |
| |
| /** Constructor |
| * |
| * @param context Test framework context |
| **/ |
| SSBMemberInvalidOffsetAlignmentTest::SSBMemberInvalidOffsetAlignmentTest(deqp::Context& context) |
| : UniformBlockMemberInvalidOffsetAlignmentTest( |
| context, "ssb_member_invalid_offset_alignment", |
| "Test verifies that invalid alignment of offset qualifiers cause compilation failure") |
| { |
| /* Nothing to be done here */ |
| } |
| |
| /** Get the maximum size for a shader storage block |
| * |
| * @return The maximum size in basic machine units of a shader storage block. |
| **/ |
| GLint SSBMemberInvalidOffsetAlignmentTest::getMaxBlockSize() |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| GLint max_size = 0; |
| |
| gl.getIntegerv(GL_MAX_SHADER_STORAGE_BLOCK_SIZE, &max_size); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv"); |
| |
| return max_size; |
| } |
| |
| /** Source for given test case and stage |
| * |
| * @param test_case_index Index of test case |
| * @param stage Shader stage |
| * |
| * @return Shader source |
| **/ |
| std::string SSBMemberInvalidOffsetAlignmentTest::getShaderSource(GLuint test_case_index, Utils::Shader::STAGES stage) |
| { |
| static const GLchar* cs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n" |
| "\n" |
| "layout (std140) buffer Block {\n" |
| " layout (offset = OFFSET) TYPE member;\n" |
| "} block;\n" |
| "\n" |
| "writeonly uniform image2D uni_image;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = vec4(1, 0, 0.5, 1);\n" |
| "\n" |
| " if (TYPE(1) == block.member)\n" |
| " {\n" |
| " result = vec4(1, 1, 1, 1);\n" |
| " }\n" |
| "\n" |
| " imageStore(uni_image, ivec2(gl_GlobalInvocationID.xy), result);\n" |
| "}\n" |
| "\n"; |
| static const GLchar* fs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 gs_fs;\n" |
| "out vec4 fs_out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " fs_out = gs_fs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* fs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout (std140) buffer Block {\n" |
| " layout (offset = OFFSET) TYPE member;\n" |
| "} block;\n" |
| "\n" |
| "in vec4 gs_fs;\n" |
| "out vec4 fs_out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " if (TYPE(1) == block.member)\n" |
| " {\n" |
| " fs_out = vec4(1, 1, 1, 1);\n" |
| " }\n" |
| "\n" |
| " fs_out += gs_fs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* gs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| "in vec4 tes_gs[];\n" |
| "out vec4 gs_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| static const GLchar* gs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| "layout (std140) buffer Block {\n" |
| " layout (offset = OFFSET) TYPE member;\n" |
| "} block;\n" |
| "\n" |
| "in vec4 tes_gs[];\n" |
| "out vec4 gs_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " if (TYPE(1) == block.member)\n" |
| " {\n" |
| " gs_fs = vec4(1, 1, 1, 1);\n" |
| " }\n" |
| "\n" |
| " gs_fs += tes_gs[0];\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs += tes_gs[0];\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs += tes_gs[0];\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs += tes_gs[0];\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tcs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "in vec4 vs_tcs[];\n" |
| "out vec4 tcs_tes[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| "\n" |
| " tcs_tes[gl_InvocationID] = vs_tcs[gl_InvocationID];\n" |
| "\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tcs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "layout (std140) buffer Block {\n" |
| " layout (offset = OFFSET) TYPE member;\n" |
| "} block;\n" |
| "\n" |
| "in vec4 vs_tcs[];\n" |
| "out vec4 tcs_tes[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " if (TYPE(1) == block.member)\n" |
| " {\n" |
| " tcs_tes[gl_InvocationID] = vec4(1, 1, 1, 1);\n" |
| " }\n" |
| "\n" |
| "\n" |
| " tcs_tes[gl_InvocationID] += vs_tcs[gl_InvocationID];\n" |
| "\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tes = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(isolines, point_mode) in;\n" |
| "\n" |
| "in vec4 tcs_tes[];\n" |
| "out vec4 tes_gs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " tes_gs = tcs_tes[0];\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tes_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(isolines, point_mode) in;\n" |
| "\n" |
| "layout (std140) buffer Block {\n" |
| " layout (offset = OFFSET) TYPE member;\n" |
| "} block;\n" |
| "\n" |
| "in vec4 tcs_tes[];\n" |
| "out vec4 tes_gs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " if (TYPE(1) == block.member)\n" |
| " {\n" |
| " tes_gs = vec4(1, 1, 1, 1);\n" |
| " }\n" |
| "\n" |
| " tes_gs += tcs_tes[0];\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 vs_tcs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vs_tcs = in_vs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout (std140) buffer Block {\n" |
| " layout (offset = OFFSET) TYPE member;\n" |
| "} block;\n" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 vs_tcs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " if (TYPE(1) == block.member)\n" |
| " {\n" |
| " vs_tcs = vec4(1, 1, 1, 1);\n" |
| " }\n" |
| "\n" |
| " vs_tcs += in_vs;\n" |
| "}\n" |
| "\n"; |
| |
| std::string source; |
| testCase& test_case = m_test_cases[test_case_index]; |
| |
| if (test_case.m_stage == stage) |
| { |
| GLchar buffer[16]; |
| const GLuint offset = test_case.m_offset; |
| size_t position = 0; |
| const Utils::Type& type = test_case.m_type; |
| const GLchar* type_name = type.GetGLSLTypeName(); |
| |
| sprintf(buffer, "%d", offset); |
| |
| switch (stage) |
| { |
| case Utils::Shader::COMPUTE: |
| source = cs; |
| break; |
| case Utils::Shader::FRAGMENT: |
| source = fs_tested; |
| break; |
| case Utils::Shader::GEOMETRY: |
| source = gs_tested; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| source = tcs_tested; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| source = tes_tested; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs_tested; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| Utils::replaceToken("OFFSET", position, buffer, source); |
| Utils::replaceToken("TYPE", position, type_name, source); |
| Utils::replaceToken("TYPE", position, type_name, source); |
| } |
| else |
| { |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs; |
| break; |
| case Utils::Shader::GEOMETRY: |
| source = gs; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| source = tcs; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| source = tes; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| } |
| |
| return source; |
| } |
| |
| /** Checks if stage is supported |
| * |
| * @param stage Shader stage |
| * |
| * @return true if supported, false otherwise |
| **/ |
| bool SSBMemberInvalidOffsetAlignmentTest::isStageSupported(Utils::Shader::STAGES stage) |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| GLint max_supported_buffers = 0; |
| GLenum pname = 0; |
| |
| switch (stage) |
| { |
| case Utils::Shader::COMPUTE: |
| pname = GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS; |
| break; |
| case Utils::Shader::FRAGMENT: |
| pname = GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS; |
| break; |
| case Utils::Shader::GEOMETRY: |
| pname = GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| pname = GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| pname = GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS; |
| break; |
| case Utils::Shader::VERTEX: |
| pname = GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| gl.getIntegerv(pname, &max_supported_buffers); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv"); |
| |
| return 1 <= max_supported_buffers; |
| } |
| |
| /** Constructor |
| * |
| * @param context Test framework context |
| **/ |
| SSBMemberOverlappingOffsetsTest::SSBMemberOverlappingOffsetsTest(deqp::Context& context) |
| : UniformBlockMemberOverlappingOffsetsTest( |
| context, "ssb_member_overlapping_offsets", |
| "Test verifies that overlapping offsets qualifiers cause compilation failure") |
| { |
| /* Nothing to be done here */ |
| } |
| |
| /** Source for given test case and stage |
| * |
| * @param test_case_index Index of test case |
| * @param stage Shader stage |
| * |
| * @return Shader source |
| **/ |
| std::string SSBMemberOverlappingOffsetsTest::getShaderSource(GLuint test_case_index, Utils::Shader::STAGES stage) |
| { |
| static const GLchar* cs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n" |
| "\n" |
| "layout (std140) buffer Block {\n" |
| " layout (offset = BOY_OFFSET) BOY_TYPE boy;\n" |
| " layout (offset = MAN_OFFSET) MAN_TYPE man;\n" |
| "} block;\n" |
| "\n" |
| "writeonly uniform image2D uni_image;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = vec4(1, 0, 0.5, 1);\n" |
| "\n" |
| " if ((BOY_TYPE(1) == block.boy) ||\n" |
| " (MAN_TYPE(0) == block.man) )\n" |
| " {\n" |
| " result = vec4(1, 1, 1, 1);\n" |
| " }\n" |
| "\n" |
| " imageStore(uni_image, ivec2(gl_GlobalInvocationID.xy), result);\n" |
| "}\n" |
| "\n"; |
| static const GLchar* fs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 gs_fs;\n" |
| "out vec4 fs_out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " fs_out = gs_fs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* fs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout (std140) buffer Block {\n" |
| " layout (offset = BOY_OFFSET) BOY_TYPE boy;\n" |
| " layout (offset = MAN_OFFSET) MAN_TYPE man;\n" |
| "} block;\n" |
| "\n" |
| "in vec4 gs_fs;\n" |
| "out vec4 fs_out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " if ((BOY_TYPE(1) == block.boy) ||\n" |
| " (MAN_TYPE(0) == block.man) )\n" |
| " {\n" |
| " fs_out = vec4(1, 1, 1, 1);\n" |
| " }\n" |
| "\n" |
| " fs_out += gs_fs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* gs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| "in vec4 tes_gs[];\n" |
| "out vec4 gs_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| static const GLchar* gs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| "layout (std140) buffer Block {\n" |
| " layout (offset = BOY_OFFSET) BOY_TYPE boy;\n" |
| " layout (offset = MAN_OFFSET) MAN_TYPE man;\n" |
| "} block;\n" |
| "\n" |
| "in vec4 tes_gs[];\n" |
| "out vec4 gs_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " if ((BOY_TYPE(1) == block.boy) ||\n" |
| " (MAN_TYPE(0) == block.man) )\n" |
| " {\n" |
| " gs_fs = vec4(1, 1, 1, 1);\n" |
| " }\n" |
| "\n" |
| " gs_fs += tes_gs[0];\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs += tes_gs[0];\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs += tes_gs[0];\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs += tes_gs[0];\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tcs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "in vec4 vs_tcs[];\n" |
| "out vec4 tcs_tes[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| "\n" |
| " tcs_tes[gl_InvocationID] = vs_tcs[gl_InvocationID];\n" |
| "\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tcs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "layout (std140) buffer Block {\n" |
| " layout (offset = BOY_OFFSET) BOY_TYPE boy;\n" |
| " layout (offset = MAN_OFFSET) MAN_TYPE man;\n" |
| "} block;\n" |
| "\n" |
| "in vec4 vs_tcs[];\n" |
| "out vec4 tcs_tes[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " if ((BOY_TYPE(1) == block.boy) ||\n" |
| " (MAN_TYPE(0) == block.man) )\n" |
| " {\n" |
| " tcs_tes[gl_InvocationID] = vec4(1, 1, 1, 1);\n" |
| " }\n" |
| "\n" |
| "\n" |
| " tcs_tes[gl_InvocationID] += vs_tcs[gl_InvocationID];\n" |
| "\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tes = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(isolines, point_mode) in;\n" |
| "\n" |
| "in vec4 tcs_tes[];\n" |
| "out vec4 tes_gs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " tes_gs = tcs_tes[0];\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tes_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(isolines, point_mode) in;\n" |
| "\n" |
| "layout (std140) buffer Block {\n" |
| " layout (offset = BOY_OFFSET) BOY_TYPE boy;\n" |
| " layout (offset = MAN_OFFSET) MAN_TYPE man;\n" |
| "} block;\n" |
| "\n" |
| "in vec4 tcs_tes[];\n" |
| "out vec4 tes_gs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " if ((BOY_TYPE(1) == block.boy) ||\n" |
| " (MAN_TYPE(0) == block.man) )\n" |
| " {\n" |
| " tes_gs = vec4(1, 1, 1, 1);\n" |
| " }\n" |
| "\n" |
| " tes_gs += tcs_tes[0];\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 vs_tcs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vs_tcs = in_vs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout (std140) buffer Block {\n" |
| " layout (offset = BOY_OFFSET) BOY_TYPE boy;\n" |
| " layout (offset = MAN_OFFSET) MAN_TYPE man;\n" |
| "} block;\n" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 vs_tcs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " if ((BOY_TYPE(1) == block.boy) ||\n" |
| " (MAN_TYPE(0) == block.man) )\n" |
| " {\n" |
| " vs_tcs = vec4(1, 1, 1, 1);\n" |
| " }\n" |
| "\n" |
| " vs_tcs += in_vs;\n" |
| "}\n" |
| "\n"; |
| |
| std::string source; |
| testCase& test_case = m_test_cases[test_case_index]; |
| |
| if (test_case.m_stage == stage) |
| { |
| GLchar buffer[16]; |
| const GLuint boy_offset = test_case.m_boy_offset; |
| const Utils::Type& boy_type = test_case.m_boy_type; |
| const GLchar* boy_type_name = boy_type.GetGLSLTypeName(); |
| const GLuint man_offset = test_case.m_man_offset; |
| const Utils::Type& man_type = test_case.m_man_type; |
| const GLchar* man_type_name = man_type.GetGLSLTypeName(); |
| size_t position = 0; |
| |
| switch (stage) |
| { |
| case Utils::Shader::COMPUTE: |
| source = cs; |
| break; |
| case Utils::Shader::FRAGMENT: |
| source = fs_tested; |
| break; |
| case Utils::Shader::GEOMETRY: |
| source = gs_tested; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| source = tcs_tested; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| source = tes_tested; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs_tested; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| sprintf(buffer, "%d", boy_offset); |
| Utils::replaceToken("BOY_OFFSET", position, buffer, source); |
| Utils::replaceToken("BOY_TYPE", position, boy_type_name, source); |
| sprintf(buffer, "%d", man_offset); |
| Utils::replaceToken("MAN_OFFSET", position, buffer, source); |
| Utils::replaceToken("MAN_TYPE", position, man_type_name, source); |
| Utils::replaceToken("BOY_TYPE", position, boy_type_name, source); |
| Utils::replaceToken("MAN_TYPE", position, man_type_name, source); |
| } |
| else |
| { |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs; |
| break; |
| case Utils::Shader::GEOMETRY: |
| source = gs; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| source = tcs; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| source = tes; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| } |
| |
| return source; |
| } |
| |
| /** Checks if stage is supported |
| * |
| * @param stage Shader stage |
| * |
| * @return true if supported, false otherwise |
| **/ |
| bool SSBMemberOverlappingOffsetsTest::isStageSupported(Utils::Shader::STAGES stage) |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| GLint max_supported_buffers = 0; |
| GLenum pname = 0; |
| |
| switch (stage) |
| { |
| case Utils::Shader::COMPUTE: |
| pname = GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS; |
| break; |
| case Utils::Shader::FRAGMENT: |
| pname = GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS; |
| break; |
| case Utils::Shader::GEOMETRY: |
| pname = GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| pname = GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| pname = GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS; |
| break; |
| case Utils::Shader::VERTEX: |
| pname = GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| gl.getIntegerv(pname, &max_supported_buffers); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv"); |
| |
| return 1 <= max_supported_buffers; |
| } |
| |
| /** Constructor |
| * |
| * @param context Test framework context |
| **/ |
| SSBMemberAlignNonPowerOf2Test::SSBMemberAlignNonPowerOf2Test(deqp::Context& context) |
| : UniformBlockMemberAlignNonPowerOf2Test(context, "ssb_member_align_non_power_of_2", |
| "Test verifies that align qualifier requires value that is a power of 2") |
| { |
| /* Nothing to be done here */ |
| } |
| |
| /** Source for given test case and stage |
| * |
| * @param test_case_index Index of test case |
| * @param stage Shader stage |
| * |
| * @return Shader source |
| **/ |
| std::string SSBMemberAlignNonPowerOf2Test::getShaderSource(GLuint test_case_index, Utils::Shader::STAGES stage) |
| { |
| static const GLchar* cs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n" |
| "\n" |
| "layout (std140) buffer Block {\n" |
| " vec4 boy;\n" |
| " layout (align = ALIGN) TYPE man;\n" |
| "} block;\n" |
| "\n" |
| "writeonly uniform image2D uni_image;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = vec4(1, 0, 0.5, 1);\n" |
| "\n" |
| " if (TYPE(0) == block.man)\n" |
| " {\n" |
| " result = vec4(1, 1, 1, 1) - block.boy;\n" |
| " }\n" |
| "\n" |
| " imageStore(uni_image, ivec2(gl_GlobalInvocationID.xy), result);\n" |
| "}\n" |
| "\n"; |
| static const GLchar* fs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 gs_fs;\n" |
| "out vec4 fs_out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " fs_out = gs_fs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* fs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout (std140) buffer Block {\n" |
| " vec4 boy;\n" |
| " layout (align = ALIGN) TYPE man;\n" |
| "} block;\n" |
| "\n" |
| "in vec4 gs_fs;\n" |
| "out vec4 fs_out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " if (TYPE(0) == block.man)\n" |
| " {\n" |
| " fs_out = block.boy;\n" |
| " }\n" |
| "\n" |
| " fs_out += gs_fs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* gs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| "in vec4 tes_gs[];\n" |
| "out vec4 gs_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| static const GLchar* gs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| "layout (std140) buffer Block {\n" |
| " vec4 boy;\n" |
| " layout (align = ALIGN) TYPE man;\n" |
| "} block;\n" |
| "\n" |
| "in vec4 tes_gs[];\n" |
| "out vec4 gs_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " if (TYPE(0) == block.man)\n" |
| " {\n" |
| " gs_fs = block.boy;\n" |
| " }\n" |
| "\n" |
| " gs_fs += tes_gs[0];\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs += tes_gs[0];\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs += tes_gs[0];\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs += tes_gs[0];\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tcs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "in vec4 vs_tcs[];\n" |
| "out vec4 tcs_tes[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| "\n" |
| " tcs_tes[gl_InvocationID] = vs_tcs[gl_InvocationID];\n" |
| "\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tcs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "layout (std140) buffer Block {\n" |
| " vec4 boy;\n" |
| " layout (align = ALIGN) TYPE man;\n" |
| "} block;\n" |
| "\n" |
| "in vec4 vs_tcs[];\n" |
| "out vec4 tcs_tes[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " if (TYPE(0) == block.man)\n" |
| " {\n" |
| " tcs_tes[gl_InvocationID] = block.boy;\n" |
| " }\n" |
| "\n" |
| "\n" |
| " tcs_tes[gl_InvocationID] += vs_tcs[gl_InvocationID];\n" |
| "\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tes = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(isolines, point_mode) in;\n" |
| "\n" |
| "in vec4 tcs_tes[];\n" |
| "out vec4 tes_gs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " tes_gs = tcs_tes[0];\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tes_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(isolines, point_mode) in;\n" |
| "\n" |
| "layout (std140) buffer Block {\n" |
| " vec4 boy;\n" |
| " layout (align = ALIGN) TYPE man;\n" |
| "} block;\n" |
| "\n" |
| "in vec4 tcs_tes[];\n" |
| "out vec4 tes_gs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " if (TYPE(0) == block.man)\n" |
| " {\n" |
| " tes_gs = block.boy;\n" |
| " }\n" |
| "\n" |
| " tes_gs += tcs_tes[0];\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 vs_tcs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vs_tcs = in_vs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout (std140) buffer Block {\n" |
| " vec4 boy;\n" |
| " layout (align = ALIGN) TYPE man;\n" |
| "} block;\n" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 vs_tcs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " if (TYPE(0) == block.man)\n" |
| " {\n" |
| " vs_tcs = block.boy;\n" |
| " }\n" |
| "\n" |
| " vs_tcs += in_vs;\n" |
| "}\n" |
| "\n"; |
| |
| std::string source; |
| testCase& test_case = m_test_cases[test_case_index]; |
| |
| if (test_case.m_stage == stage) |
| { |
| GLchar buffer[16]; |
| const GLuint alignment = test_case.m_alignment; |
| const Utils::Type& type = test_case.m_type; |
| const GLchar* type_name = type.GetGLSLTypeName(); |
| size_t position = 0; |
| |
| switch (stage) |
| { |
| case Utils::Shader::COMPUTE: |
| source = cs; |
| break; |
| case Utils::Shader::FRAGMENT: |
| source = fs_tested; |
| break; |
| case Utils::Shader::GEOMETRY: |
| source = gs_tested; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| source = tcs_tested; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| source = tes_tested; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs_tested; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| sprintf(buffer, "%d", alignment); |
| Utils::replaceToken("ALIGN", position, buffer, source); |
| Utils::replaceToken("TYPE", position, type_name, source); |
| Utils::replaceToken("TYPE", position, type_name, source); |
| } |
| else |
| { |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs; |
| break; |
| case Utils::Shader::GEOMETRY: |
| source = gs; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| source = tcs; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| source = tes; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| } |
| |
| return source; |
| } |
| |
| /** Checks if stage is supported |
| * |
| * @param stage Shader stage |
| * |
| * @return true if supported, false otherwise |
| **/ |
| bool SSBMemberAlignNonPowerOf2Test::isStageSupported(Utils::Shader::STAGES stage) |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| GLint max_supported_buffers = 0; |
| GLenum pname = 0; |
| |
| switch (stage) |
| { |
| case Utils::Shader::COMPUTE: |
| pname = GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS; |
| break; |
| case Utils::Shader::FRAGMENT: |
| pname = GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS; |
| break; |
| case Utils::Shader::GEOMETRY: |
| pname = GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| pname = GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| pname = GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS; |
| break; |
| case Utils::Shader::VERTEX: |
| pname = GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| gl.getIntegerv(pname, &max_supported_buffers); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv"); |
| |
| return 1 <= max_supported_buffers; |
| } |
| |
| /** Constructor |
| * |
| * @param context Test framework context |
| **/ |
| SSBAlignmentTest::SSBAlignmentTest(deqp::Context& context) |
| : TextureTestBase(context, "ssb_alignment", "Test verifies offset and alignment of ssb buffer") |
| { |
| } |
| |
| /** Get interface of program |
| * |
| * @param ignored |
| * @param program_interface Interface of program |
| * @param varying_passthrough Collection of connections between in and out variables |
| **/ |
| void SSBAlignmentTest::getProgramInterface(GLuint /* test_case_index */, Utils::ProgramInterface& program_interface, |
| Utils::VaryingPassthrough& varying_passthrough) |
| { |
| static const Utils::Type vec4 = Utils::Type::vec4; |
| |
| #if WRKARD_UNIFORMBLOCKALIGNMENT |
| |
| static const GLuint block_align = 16; |
| |
| #else /* WRKARD_UNIFORMBLOCKALIGNMENT */ |
| |
| static const GLuint block_align = 64; |
| |
| #endif /* WRKARD_UNIFORMBLOCKALIGNMENT */ |
| |
| static const GLuint fifth_align = 16; |
| static const GLuint vec4_stride = 16; |
| static const GLuint data_stride = vec4_stride * 2; /* one vec4 + one scalar aligned to 16 */ |
| |
| const GLuint first_offset = 0; /* vec4 at 0 */ |
| const GLuint second_offset = Utils::Type::GetActualOffset(first_offset + vec4_stride, block_align); /* Data at 32 */ |
| const GLuint third_offset = |
| Utils::Type::GetActualOffset(second_offset + data_stride, block_align); /* Data[2] at 64 */ |
| const GLuint fourth_offset = |
| Utils::Type::GetActualOffset(third_offset + data_stride * 2, block_align); /* vec4[3] at 96 */ |
| const GLuint fifth_offset = |
| Utils::Type::GetActualOffset(fourth_offset + vec4_stride * 3, fifth_align); /* vec4[2] at 160 */ |
| const GLuint sixth_offset = |
| Utils::Type::GetActualOffset(fifth_offset + vec4_stride * 2, block_align); /* Data at 192 */ |
| |
| Utils::Interface* structure = program_interface.Structure("Data"); |
| |
| structure->Member("vector", "", 0 /* expected_component */, 0 /* expected_location */, Utils::Type::vec4, |
| false /* normalized */, 0 /* n_array_elements */, Utils::Type::vec4.GetSize(), 0 /* offset */); |
| |
| structure->Member("scalar", "", 0 /* expected_component */, 0 /* expected_location */, Utils::Type::_float, |
| false /* normalized */, 0 /* n_array_elements */, Utils::Type::_float.GetSize(), |
| Utils::Type::vec4.GetSize() /* offset */); |
| |
| /* Prepare Block */ |
| Utils::Interface* vs_buf_Block = program_interface.Block("vs_buf_Block"); |
| |
| vs_buf_Block->Member("first", "", 0 /* expected_component */, 0 /* expected_location */, Utils::Type::vec4, |
| false /* normalized */, 0 /* n_array_elements */, vec4_stride, first_offset /* offset */); |
| |
| vs_buf_Block->Member("second", "", 0 /* expected_component */, 0 /* expected_location */, structure, |
| 0 /* n_array_elements */, data_stride, second_offset); |
| |
| vs_buf_Block->Member("third", "", 0 /* expected_component */, 0 /* expected_location */, structure, |
| 2 /* n_array_elements */, data_stride, third_offset); |
| |
| vs_buf_Block->Member("fourth", "", 0 /* expected_component */, 0 /* expected_location */, vec4, |
| false /* normalized */, 3 /* n_array_elements */, vec4_stride, fourth_offset); |
| |
| vs_buf_Block->Member("fifth", "layout(align = 16)", 0 /* expected_component */, 0 /* expected_location */, vec4, |
| false /* normalized */, 2 /* n_array_elements */, vec4_stride, fifth_offset); |
| |
| vs_buf_Block->Member("sixth", "", 0 /* expected_component */, 0 /* expected_location */, structure, |
| 0 /* n_array_elements */, data_stride, sixth_offset); |
| |
| const GLuint stride = calculateStride(*vs_buf_Block); |
| m_data.resize(stride); |
| generateData(*vs_buf_Block, 0, m_data); |
| |
| Utils::ShaderInterface& vs_si = program_interface.GetShaderInterface(Utils::Shader::VERTEX); |
| |
| /* Add uniform BLOCK */ |
| #if WRKARD_UNIFORMBLOCKALIGNMENT |
| vs_si.SSB("vs_buf_block", "layout (std140, binding = BINDING)", 0, 0, vs_buf_Block, 0, |
| static_cast<GLuint>(m_data.size()), 0, &m_data[0], m_data.size()); |
| #else /* WRKARD_UNIFORMBLOCKALIGNMENT */ |
| vs_si.SSB("vs_buf_block", "layout (std140, binding = BINDING, align = 64)", 0, 0, vs_buf_Block, 0, |
| static_cast<GLuint>(m_data.size()), 0, &m_data[0], m_data.size()); |
| #endif /* WRKARD_UNIFORMBLOCKALIGNMENT */ |
| |
| program_interface.CloneVertexInterface(varying_passthrough); |
| } |
| |
| /** Selects if "draw" stages are relevant for test |
| * |
| * @param ignored |
| * |
| * @return true if all stages support shader storage buffers, false otherwise |
| **/ |
| bool SSBAlignmentTest::isDrawRelevant(GLuint /* test_case_index */) |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| GLint gs_supported_buffers = 0; |
| GLint tcs_supported_buffers = 0; |
| GLint tes_supported_buffers = 0; |
| GLint vs_supported_buffers = 0; |
| |
| gl.getIntegerv(GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS, &gs_supported_buffers); |
| gl.getIntegerv(GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS, &tcs_supported_buffers); |
| gl.getIntegerv(GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS, &tes_supported_buffers); |
| gl.getIntegerv(GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, &vs_supported_buffers); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv"); |
| |
| return ((1 <= gs_supported_buffers) && (1 <= tcs_supported_buffers) && (1 <= tes_supported_buffers) && |
| (1 <= vs_supported_buffers)); |
| } |
| |
| /** Constructor |
| * |
| * @param context Test framework context |
| **/ |
| VaryingLocationsTest::VaryingLocationsTest(deqp::Context& context) |
| : TextureTestBase(context, "varying_locations", "Test verifies that input and output locations are respected") |
| { |
| } |
| |
| /** Constructor |
| * |
| * @param context Test context |
| * @param test_name Name of test |
| * @param test_description Description of test |
| **/ |
| VaryingLocationsTest::VaryingLocationsTest(deqp::Context& context, const glw::GLchar* test_name, |
| const glw::GLchar* test_description) |
| : TextureTestBase(context, test_name, test_description) |
| { |
| } |
| |
| /** Get interface of program |
| * |
| * @param test_case_index Test case |
| * @param program_interface Interface of program |
| * @param varying_passthrough Collection of connections between in and out variables |
| **/ |
| void VaryingLocationsTest::getProgramInterface(GLuint test_case_index, Utils::ProgramInterface& program_interface, |
| Utils::VaryingPassthrough& varying_passthrough) |
| { |
| const Utils::Type type = getType(test_case_index); |
| |
| m_first_data = type.GenerateDataPacked(); |
| m_last_data = type.GenerateDataPacked(); |
| |
| prepareShaderStage(Utils::Shader::FRAGMENT, type, program_interface, varying_passthrough); |
| prepareShaderStage(Utils::Shader::GEOMETRY, type, program_interface, varying_passthrough); |
| prepareShaderStage(Utils::Shader::TESS_CTRL, type, program_interface, varying_passthrough); |
| prepareShaderStage(Utils::Shader::TESS_EVAL, type, program_interface, varying_passthrough); |
| prepareShaderStage(Utils::Shader::VERTEX, type, program_interface, varying_passthrough); |
| } |
| |
| /** Get type name |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return Name of type test in test_case_index |
| **/ |
| std::string VaryingLocationsTest::getTestCaseName(glw::GLuint test_case_index) |
| { |
| return getTypeName(test_case_index); |
| } |
| |
| /** Returns number of types to test |
| * |
| * @return Number of types, 34 |
| **/ |
| glw::GLuint VaryingLocationsTest::getTestCaseNumber() |
| { |
| return getTypesNumber(); |
| } |
| |
| /** Selects if "compute" stage is relevant for test |
| * |
| * @param ignored |
| * |
| * @return false |
| **/ |
| bool VaryingLocationsTest::isComputeRelevant(GLuint /* test_case_index */) |
| { |
| return false; |
| } |
| |
| /** |
| * |
| * |
| **/ |
| std::string VaryingLocationsTest::prepareGlobals(GLint last_in_loc, GLint last_out_loc) |
| { |
| GLchar buffer[16]; |
| std::string globals = "const uint first_input_location = 0u;\n" |
| "const uint first_output_location = 0u;\n" |
| "const uint last_input_location = LAST_INPUTu;\n" |
| "const uint last_output_location = LAST_OUTPUTu;\n"; |
| size_t position = 100; /* Skip first part */ |
| |
| sprintf(buffer, "%d", last_in_loc); |
| Utils::replaceToken("LAST_INPUT", position, buffer, globals); |
| |
| sprintf(buffer, "%d", last_out_loc); |
| Utils::replaceToken("LAST_OUTPUT", position, buffer, globals); |
| |
| return globals; |
| } |
| |
| /** |
| * |
| **/ |
| void VaryingLocationsTest::prepareShaderStage(Utils::Shader::STAGES stage, const Utils::Type& type, |
| Utils::ProgramInterface& program_interface, |
| Utils::VaryingPassthrough& varying_passthrough) |
| { |
| const GLuint array_length = 1; |
| const GLuint first_in_loc = 0; |
| const GLuint first_out_loc = 0; |
| const GLuint last_in_loc = getLastInputLocation(stage, type, array_length, false); |
| size_t position = 0; |
| |
| const GLchar* prefix_in = Utils::ProgramInterface::GetStagePrefix(stage, Utils::Variable::VARYING_INPUT); |
| |
| const GLchar* prefix_out = Utils::ProgramInterface::GetStagePrefix(stage, Utils::Variable::VARYING_OUTPUT); |
| |
| const GLchar* qual_first_in = "layout (location = first_input_location)"; |
| const GLchar* qual_first_out = "layout (location = first_output_location)"; |
| const GLchar* qual_last_in = "layout (location = last_input_location)"; |
| const GLchar* qual_last_out = "layout (location = last_output_location)"; |
| |
| Utils::ShaderInterface& si = program_interface.GetShaderInterface(stage); |
| const GLuint type_size = type.GetSize(); |
| |
| std::string first_in_name = "PREFIXfirst"; |
| std::string first_out_name = "PREFIXfirst"; |
| std::string last_in_name = "PREFIXlast"; |
| std::string last_out_name = "PREFIXlast"; |
| |
| Utils::replaceToken("PREFIX", position, prefix_in, first_in_name); |
| position = 0; |
| Utils::replaceToken("PREFIX", position, prefix_out, first_out_name); |
| position = 0; |
| Utils::replaceToken("PREFIX", position, prefix_in, last_in_name); |
| position = 0; |
| Utils::replaceToken("PREFIX", position, prefix_out, last_out_name); |
| |
| if (Utils::Shader::FRAGMENT == stage) |
| { |
| qual_first_in = "layout (location = first_input_location) flat"; |
| qual_last_in = "layout (location = last_input_location) flat"; |
| } |
| if (Utils::Shader::GEOMETRY == stage) |
| { |
| qual_first_out = "layout (location = first_output_location) flat"; |
| qual_last_out = "layout (location = last_output_location) flat"; |
| } |
| |
| Utils::Variable* first_in = si.Input( |
| first_in_name.c_str(), qual_first_in /* qualifiers */, 0 /* expected_componenet */, |
| first_in_loc /* expected_location */, type /* type */, GL_FALSE /* normalized */, 0u /* n_array_elements */, |
| 0u /* stride */, 0u /* offset */, (GLvoid*)&m_first_data[0] /* data */, m_first_data.size() /* data_size */); |
| |
| Utils::Variable* last_in = |
| si.Input(last_in_name.c_str(), qual_last_in /* qualifiers */, 0 /* expected_componenet */, |
| last_in_loc /* expected_location */, type /* type */, GL_FALSE /* normalized */, |
| 0u /* n_array_elements */, 0u /* stride */, type_size /* offset */, |
| (GLvoid*)&m_last_data[0] /* data */, m_last_data.size() /* data_size */); |
| |
| if (Utils::Shader::FRAGMENT != stage) |
| { |
| const GLuint last_out_loc = getLastOutputLocation(stage, type, array_length, false); |
| |
| Utils::Variable* first_out = |
| si.Output(first_out_name.c_str(), qual_first_out /* qualifiers */, 0 /* expected_componenet */, |
| first_out_loc /* expected_location */, type /* type */, GL_FALSE /* normalized */, |
| 0u /* n_array_elements */, 0u /* stride */, 0u /* offset */, (GLvoid*)&m_first_data[0] /* data */, |
| m_first_data.size() /* data_size */); |
| |
| Utils::Variable* last_out = si.Output( |
| last_out_name.c_str(), qual_last_out /* qualifiers */, 0 /* expected_componenet */, |
| last_out_loc /* expected_location */, type /* type */, GL_FALSE /* normalized */, 0u /* n_array_elements */, |
| 0u /* stride */, 0u /* offset */, (GLvoid*)&m_last_data[0] /* data */, m_last_data.size() /* data_size */); |
| |
| si.m_globals = prepareGlobals(last_in_loc, last_out_loc); |
| |
| varying_passthrough.Add(stage, first_in, first_out); |
| varying_passthrough.Add(stage, last_in, last_out); |
| } |
| else |
| { |
| /* No outputs for fragment shader, so last_output_location can be 0 */ |
| si.m_globals = prepareGlobals(last_in_loc, 0); |
| } |
| } |
| |
| /** This test should be run with separable programs |
| * |
| * @param ignored |
| * |
| * @return true |
| **/ |
| bool VaryingLocationsTest::useMonolithicProgram(GLuint /* test_case_index */) |
| { |
| return false; |
| } |
| |
| /* Constants used by VertexAttribLocationsTest */ |
| const GLuint VertexAttribLocationsTest::m_base_vertex = 4; |
| const GLuint VertexAttribLocationsTest::m_base_instance = 2; |
| const GLuint VertexAttribLocationsTest::m_loc_vertex = 2; |
| const GLuint VertexAttribLocationsTest::m_loc_instance = 5; |
| const GLuint VertexAttribLocationsTest::m_n_instances = 4; |
| |
| /** Constructor |
| * |
| * @param context Test framework context |
| **/ |
| VertexAttribLocationsTest::VertexAttribLocationsTest(deqp::Context& context) |
| : TextureTestBase(context, "vertex_attrib_locations", |
| "Test verifies that attribute locations are respected by drawing operations") |
| { |
| } |
| |
| /** Execute proper draw command for test case |
| * |
| * @param test_case_index Index of test case |
| **/ |
| void VertexAttribLocationsTest::executeDrawCall(GLuint test_case_index) |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| switch (test_case_index) |
| { |
| case DRAWARRAYS: |
| gl.drawArrays(GL_PATCHES, 0 /* first */, 1 /* count */); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays"); |
| break; |
| case DRAWARRAYSINSTANCED: |
| gl.drawArraysInstanced(GL_PATCHES, 0 /* first */, 1 /* count */, m_n_instances); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArraysInstanced"); |
| break; |
| case DRAWELEMENTS: |
| gl.drawElements(GL_PATCHES, 1 /* count */, GL_UNSIGNED_BYTE, DE_NULL); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "DrawElements"); |
| break; |
| case DRAWELEMENTSBASEVERTEX: |
| gl.drawElementsBaseVertex(GL_PATCHES, 1 /* count */, GL_UNSIGNED_BYTE, DE_NULL, m_base_vertex); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "DrawElementsBaseVertex"); |
| break; |
| case DRAWELEMENTSINSTANCED: |
| gl.drawElementsInstanced(GL_PATCHES, 1 /* count */, GL_UNSIGNED_BYTE, DE_NULL, m_n_instances); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "DrawElementsInstanced"); |
| break; |
| case DRAWELEMENTSINSTANCEDBASEINSTANCE: |
| gl.drawElementsInstancedBaseInstance(GL_PATCHES, 1 /* count */, GL_UNSIGNED_BYTE, DE_NULL, m_n_instances, |
| m_base_instance); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "DrawElementsInstancedBaseInstance"); |
| break; |
| case DRAWELEMENTSINSTANCEDBASEVERTEX: |
| gl.drawElementsInstancedBaseVertex(GL_PATCHES, 1 /* count */, GL_UNSIGNED_BYTE, DE_NULL, m_n_instances, |
| m_base_vertex); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "DrawElementsInstancedBaseVertex"); |
| break; |
| case DRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCE: |
| gl.drawElementsInstancedBaseVertexBaseInstance(GL_PATCHES, 1 /* count */, GL_UNSIGNED_BYTE, DE_NULL, |
| m_n_instances, m_base_vertex, m_base_instance); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "DrawElementsInstancedBaseVertexBaseInstance"); |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| } |
| |
| /** Get interface of program |
| * |
| * @param ignored |
| * @param program_interface Interface of program |
| * @param ignored |
| **/ |
| void VertexAttribLocationsTest::getProgramInterface(GLuint /* test_case_index */, |
| Utils::ProgramInterface& program_interface, |
| Utils::VaryingPassthrough& /* varying_passthrough */) |
| { |
| Utils::ShaderInterface& si = program_interface.GetShaderInterface(Utils::Shader::VERTEX); |
| |
| /* Globals */ |
| si.m_globals = "const uint vertex_index_location = 2;\n" |
| "const uint instance_index_location = 5;\n"; |
| |
| /* Attributes */ |
| si.Input("vertex_index" /* name */, "layout (location = vertex_index_location)" /* qualifiers */, |
| 0 /* expected_componenet */, m_loc_vertex /* expected_location */, Utils::Type::uint /* type */, |
| GL_FALSE /* normalized */, 0u /* n_array_elements */, 16 /* stride */, 0u /* offset */, |
| (GLvoid*)0 /* data */, 0 /* data_size */); |
| si.Input("instance_index" /* name */, "layout (location = instance_index_location)" /* qualifiers */, |
| 0 /* expected_componenet */, m_loc_instance /* expected_location */, Utils::Type::uint /* type */, |
| GL_FALSE /* normalized */, 0u /* n_array_elements */, 16 /* stride */, 16u /* offset */, |
| (GLvoid*)0 /* data */, 0 /* data_size */); |
| } |
| |
| /** Get name of test case |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return Name of test case |
| **/ |
| std::string VertexAttribLocationsTest::getTestCaseName(glw::GLuint test_case_index) |
| { |
| std::string result; |
| |
| switch (test_case_index) |
| { |
| case DRAWARRAYS: |
| result = "DrawArrays"; |
| break; |
| case DRAWARRAYSINSTANCED: |
| result = "DrawArraysInstanced"; |
| break; |
| case DRAWELEMENTS: |
| result = "DrawElements"; |
| break; |
| case DRAWELEMENTSBASEVERTEX: |
| result = "DrawElementsBaseVertex"; |
| break; |
| case DRAWELEMENTSINSTANCED: |
| result = "DrawElementsInstanced"; |
| break; |
| case DRAWELEMENTSINSTANCEDBASEINSTANCE: |
| result = "DrawElementsInstancedBaseInstance"; |
| break; |
| case DRAWELEMENTSINSTANCEDBASEVERTEX: |
| result = "DrawElementsInstancedBaseVertex"; |
| break; |
| case DRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCE: |
| result = "DrawElementsInstancedBaseVertexBaseInstance"; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| return result; |
| } |
| |
| /** Get number of test cases |
| * |
| * @return Number of test cases |
| **/ |
| GLuint VertexAttribLocationsTest::getTestCaseNumber() |
| { |
| return TESTCASES_MAX; |
| } |
| |
| /** Prepare code snippet that will verify in and uniform variables |
| * |
| * @param ignored |
| * @param ignored |
| * @param stage Shader stage |
| * |
| * @return Code that verify variables |
| **/ |
| std::string VertexAttribLocationsTest::getVerificationSnippet(GLuint /* test_case_index */, |
| Utils::ProgramInterface& /* program_interface */, |
| Utils::Shader::STAGES stage) |
| { |
| std::string verification; |
| |
| if (Utils::Shader::VERTEX == stage) |
| { |
| |
| #if DEBUG_VERTEX_ATTRIB_LOCATIONS_TEST_VARIABLE |
| |
| verification = "if (gl_InstanceID != instance_index)\n" |
| " {\n" |
| " result = 12u;\n" |
| " }\n" |
| " else if (gl_VertexID != vertex_index)\n" |
| " {\n" |
| " result = 11u;\n" |
| " }\n"; |
| |
| #else |
| |
| verification = "if ((gl_VertexID != vertex_index) ||\n" |
| " (gl_InstanceID != instance_index) )\n" |
| " {\n" |
| " result = 0u;\n" |
| " }\n"; |
| |
| #endif |
| } |
| else |
| { |
| verification = ""; |
| } |
| |
| return verification; |
| } |
| |
| /** Selects if "compute" stage is relevant for test |
| * |
| * @param ignored |
| * |
| * @return false |
| **/ |
| bool VertexAttribLocationsTest::isComputeRelevant(GLuint /* test_case_index */) |
| { |
| return false; |
| } |
| |
| /** Prepare attributes, vertex array object and array buffer |
| * |
| * @param ignored |
| * @param ignored Interface of program |
| * @param buffer Array buffer |
| * @param vao Vertex array object |
| **/ |
| void VertexAttribLocationsTest::prepareAttributes(GLuint test_case_index /* test_case_index */, |
| Utils::ProgramInterface& /* program_interface */, |
| Utils::Buffer& buffer, Utils::VertexArray& vao) |
| { |
| static const GLuint vertex_index_data[8] = { 0, 1, 2, 3, 4, 5, 6, 7 }; |
| static const GLuint instance_index_data[8] = { 0, 1, 2, 3, 4, 5, 6, 7 }; |
| |
| std::vector<GLuint> buffer_data; |
| buffer_data.resize(8 + 8); /* vertex_index_data + instance_index_data */ |
| |
| GLubyte* ptr = (GLubyte*)&buffer_data[0]; |
| |
| /* |
| When case index >=2, the test calls glDrawElement*(), such as glDrawElementsBaseVertex(), glDrawElementsInstanced(), glDrawElementsInstancedBaseInstance() and so on, |
| So we need to change the buffer type as GL_ELEMENT_ARRAY_BUFFER |
| */ |
| if (test_case_index >= 2) |
| { |
| buffer.m_buffer = Utils::Buffer::Element; |
| } |
| vao.Bind(); |
| buffer.Bind(); |
| |
| vao.Attribute(m_loc_vertex /* vertex_index */, Utils::Type::uint, 0 /* array_elements */, false /* normalized */, |
| 0 /* stride */, 0 /* offset */); |
| |
| vao.Attribute(m_loc_instance /* instance_index */, Utils::Type::uint, 0 /* array_elements */, |
| false /* normalized */, 0 /* stride */, (GLvoid*)sizeof(vertex_index_data) /* offset */); |
| // when test_case_index is 5 or 7, the draw call is glDrawElementsInstancedBaseInstance, glDrawElementsInstancedBaseVertexBaseInstance |
| // the instancecount is 4, the baseinstance is 2, the divisor should be set 2 |
| bool isBaseInstanced = (test_case_index == DRAWELEMENTSINSTANCEDBASEINSTANCE || |
| test_case_index == DRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCE); |
| vao.Divisor(m_context.getRenderContext().getFunctions() /* gl */, m_loc_instance /* instance_index */, |
| isBaseInstanced ? 2 : 1 /* divisor. 1 - advance once per instance */); |
| |
| memcpy(ptr + 0, vertex_index_data, sizeof(vertex_index_data)); |
| memcpy(ptr + sizeof(vertex_index_data), instance_index_data, sizeof(instance_index_data)); |
| |
| buffer.Data(Utils::Buffer::StaticDraw, buffer_data.size() * sizeof(GLuint), ptr); |
| } |
| |
| /** This test should be run with separable programs |
| * |
| * @param ignored |
| * |
| * @return true |
| **/ |
| bool VertexAttribLocationsTest::useMonolithicProgram(GLuint /* test_case_index */) |
| { |
| return false; |
| } |
| |
| /** Constructor |
| * |
| * @param context Test framework context |
| **/ |
| VaryingArrayLocationsTest::VaryingArrayLocationsTest(deqp::Context& context) |
| : VaryingLocationsTest(context, "varying_array_locations", |
| "Test verifies that input and output locations are respected for arrays") |
| { |
| } |
| |
| /** |
| * |
| **/ |
| void VaryingArrayLocationsTest::prepareShaderStage(Utils::Shader::STAGES stage, const Utils::Type& type, |
| Utils::ProgramInterface& program_interface, |
| Utils::VaryingPassthrough& varying_passthrough) |
| { |
| const GLuint array_length = 1u; |
| const GLuint first_in_loc = 0; |
| const GLuint first_out_loc = 0; |
| const GLuint last_in_loc = getLastInputLocation(stage, type, array_length, false); |
| size_t position = 0; |
| |
| const GLchar* prefix_in = Utils::ProgramInterface::GetStagePrefix(stage, Utils::Variable::VARYING_INPUT); |
| |
| const GLchar* prefix_out = Utils::ProgramInterface::GetStagePrefix(stage, Utils::Variable::VARYING_OUTPUT); |
| |
| const GLchar* qual_first_in = "layout (location = first_input_location)"; |
| const GLchar* qual_first_out = "layout (location = first_output_location)"; |
| const GLchar* qual_last_in = "layout (location = last_input_location)"; |
| const GLchar* qual_last_out = "layout (location = last_output_location)"; |
| |
| Utils::ShaderInterface& si = program_interface.GetShaderInterface(stage); |
| const GLuint type_size = type.GetSize(); |
| |
| std::string first_in_name = "PREFIXfirst"; |
| std::string first_out_name = "PREFIXfirst"; |
| std::string last_in_name = "PREFIXlast"; |
| std::string last_out_name = "PREFIXlast"; |
| |
| Utils::replaceToken("PREFIX", position, prefix_in, first_in_name); |
| position = 0; |
| Utils::replaceToken("PREFIX", position, prefix_out, first_out_name); |
| position = 0; |
| Utils::replaceToken("PREFIX", position, prefix_in, last_in_name); |
| position = 0; |
| Utils::replaceToken("PREFIX", position, prefix_out, last_out_name); |
| |
| if (Utils::Shader::FRAGMENT == stage) |
| { |
| qual_first_in = "layout (location = first_input_location) flat"; |
| qual_last_in = "layout (location = last_input_location) flat"; |
| } |
| if (Utils::Shader::GEOMETRY == stage) |
| { |
| qual_first_out = "layout (location = first_output_location) flat"; |
| qual_last_out = "layout (location = last_output_location) flat"; |
| } |
| |
| Utils::Variable* first_in = |
| si.Input(first_in_name.c_str(), qual_first_in /* qualifiers */, 0 /* expected_componenet */, |
| first_in_loc /* expected_location */, type /* type */, GL_FALSE /* normalized */, |
| array_length /* n_array_elements */, 0u /* stride */, 0u /* offset */, |
| (GLvoid*)&m_first_data[0] /* data */, m_first_data.size() /* data_size */); |
| |
| Utils::Variable* last_in = |
| si.Input(last_in_name.c_str(), qual_last_in /* qualifiers */, 0 /* expected_componenet */, |
| last_in_loc /* expected_location */, type /* type */, GL_FALSE /* normalized */, |
| array_length /* n_array_elements */, 0u /* stride */, type_size /* offset */, |
| (GLvoid*)&m_last_data[0] /* data */, m_last_data.size() /* data_size */); |
| |
| if (Utils::Shader::FRAGMENT != stage) |
| { |
| const GLuint last_out_loc = getLastOutputLocation(stage, type, array_length, false); |
| |
| Utils::Variable* first_out = |
| si.Output(first_out_name.c_str(), qual_first_out /* qualifiers */, 0 /* expected_componenet */, |
| first_out_loc /* expected_location */, type /* type */, GL_FALSE /* normalized */, |
| array_length /* n_array_elements */, 0u /* stride */, 0u /* offset */, |
| (GLvoid*)&m_first_data[0] /* data */, m_first_data.size() /* data_size */); |
| |
| Utils::Variable* last_out = |
| si.Output(last_out_name.c_str(), qual_last_out /* qualifiers */, 0 /* expected_componenet */, |
| last_out_loc /* expected_location */, type /* type */, GL_FALSE /* normalized */, |
| array_length /* n_array_elements */, 0u /* stride */, 0u /* offset */, |
| (GLvoid*)&m_last_data[0] /* data */, m_last_data.size() /* data_size */); |
| |
| si.m_globals = prepareGlobals(last_in_loc, last_out_loc); |
| |
| varying_passthrough.Add(stage, first_in, first_out); |
| varying_passthrough.Add(stage, last_in, last_out); |
| } |
| else |
| { |
| /* No outputs for fragment shader, so last_output_location can be 0 */ |
| si.m_globals = prepareGlobals(last_in_loc, 0); |
| } |
| } |
| |
| /** Constructor |
| * |
| * @param context Test framework context |
| **/ |
| VaryingStructureLocationsTest::VaryingStructureLocationsTest(deqp::Context& context) |
| : TextureTestBase(context, "varying_structure_locations", |
| "Test verifies that locations are respected when structures are used as in and out ") |
| { |
| } |
| |
| /** Prepare code snippet that will pass in variables to out variables |
| * |
| * @param ignored |
| * @param varying_passthrough Collection of connections between in and out variables |
| * @param stage Shader stage |
| * |
| * @return Code that pass in variables to next stage |
| **/ |
| std::string VaryingStructureLocationsTest::getPassSnippet(GLuint /* test_case_index */, |
| Utils::VaryingPassthrough& varying_passthrough, |
| Utils::Shader::STAGES stage) |
| { |
| std::string result; |
| |
| if (Utils::Shader::VERTEX != stage) |
| { |
| result = TextureTestBase::getPassSnippet(0, varying_passthrough, stage); |
| } |
| else |
| { |
| result = " vs_tcs_output[0].single = vs_in_single[0];\n" |
| " vs_tcs_output[0].array[0] = vs_in_array[0];\n"; |
| } |
| |
| return result; |
| } |
| |
| /** Get interface of program |
| * |
| * @param test_case_index Test case |
| * @param program_interface Interface of program |
| * @param varying_passthrough Collection of connections between in and out variables |
| **/ |
| void VaryingStructureLocationsTest::getProgramInterface(GLuint test_case_index, |
| Utils::ProgramInterface& program_interface, |
| Utils::VaryingPassthrough& varying_passthrough) |
| { |
| Utils::ShaderInterface& si = program_interface.GetShaderInterface(Utils::Shader::VERTEX); |
| const Utils::Type type = getType(test_case_index); |
| |
| /* Prepare data */ |
| // We should call GenerateDataPacked() to generate data, which can make sure the data in shader is correct |
| m_single_data = type.GenerateDataPacked(); |
| m_array_data = type.GenerateDataPacked(); |
| |
| m_data.resize(m_single_data.size() + m_array_data.size()); |
| GLubyte* ptr = (GLubyte*)&m_data[0]; |
| memcpy(ptr, &m_single_data[0], m_single_data.size()); |
| memcpy(ptr + m_single_data.size(), &m_array_data[0], m_array_data.size()); |
| |
| Utils::Interface* structure = program_interface.Structure("Data"); |
| |
| structure->Member("single", "" /* qualifiers */, 0 /* component */, 0 /* location */, type, false /* normalized */, |
| 0u /* n_array_elements */, 0u /* stride */, 0u /* offset */); |
| |
| // the second struct member 's location should not be 0, it is based on by how many the locations the first struct member consumed. |
| structure->Member("array", "" /* qualifiers */, 0 /* component */, type.GetLocations() /* location */, type, |
| false /* normalized */, 1u /* n_array_elements */, 0u /* stride */, type.GetSize() /* offset */); |
| |
| si.Input("vs_in_single", "layout (location = 0)", 0 /* component */, 0 /* location */, type, false /* normalized */, |
| 1u /* n_array_elements */, 0u /* stride */, 0u /* offset */, (GLvoid*)&m_single_data[0] /* data */, |
| m_single_data.size() /* data_size */); |
| |
| si.Input("vs_in_array", "layout (location = 8)", 0 /* component */, 8 /* location */, type, false /* normalized */, |
| 1u /* n_array_elements */, 0u /* stride */, type.GetSize() /* offset */, |
| (GLvoid*)&m_array_data[0] /* data */, m_array_data.size() /* data_size */); |
| |
| si.Output("vs_tcs_output", "layout (location = 0)", 0 /* component */, 0 /* location */, structure, |
| 1u /* n_array_elements */, 0u /* stride */, 0u /* offset */, (GLvoid*)&m_data[0] /* data */, |
| m_data.size() /* data_size */); |
| |
| program_interface.CloneVertexInterface(varying_passthrough); |
| } |
| |
| /** Get type name |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return Name of type test in test_case_index |
| **/ |
| std::string VaryingStructureLocationsTest::getTestCaseName(glw::GLuint test_case_index) |
| { |
| return getTypeName(test_case_index); |
| } |
| |
| /** Returns number of types to test |
| * |
| * @return Number of types, 34 |
| **/ |
| glw::GLuint VaryingStructureLocationsTest::getTestCaseNumber() |
| { |
| return getTypesNumber(); |
| } |
| |
| /** Selects if "compute" stage is relevant for test |
| * |
| * @param ignored |
| * |
| * @return false |
| **/ |
| bool VaryingStructureLocationsTest::isComputeRelevant(GLuint /* test_case_index */) |
| { |
| return false; |
| } |
| |
| /** This test should be run with separable programs |
| * |
| * @param ignored |
| * |
| * @return true |
| **/ |
| bool VaryingStructureLocationsTest::useMonolithicProgram(GLuint /* test_case_index */) |
| { |
| return false; |
| } |
| |
| /** Constructor |
| * |
| * @param context Test context |
| * @param test_name Name of test |
| * @param test_description Description of test |
| **/ |
| VaryingStructureMemberLocationTest::VaryingStructureMemberLocationTest(deqp::Context& context) |
| : NegativeTestBase(context, "varying_structure_member_location", |
| "Test verifies that compiler does not allow location qualifier on member of structure") |
| { |
| } |
| |
| /** Source for given test case and stage |
| * |
| * @param test_case_index Index of test case |
| * @param stage Shader stage |
| * |
| * @return Shader source |
| **/ |
| std::string VaryingStructureMemberLocationTest::getShaderSource(GLuint test_case_index, Utils::Shader::STAGES stage) |
| { |
| static const GLchar* struct_definition = "struct Data {\n" |
| " vec4 gohan;\n" |
| #if DEBUG_NEG_REMOVE_ERROR |
| " /* layout (location = 4) */ vec4 goten;\n" |
| #else |
| " layout (location = 4) vec4 goten;\n" |
| #endif /* DEBUG_NEG_REMOVE_ERROR */ |
| "};\n"; |
| static const GLchar* input_use = " result += data.gohan + data.goten;\n"; |
| static const GLchar* input_var = "in Data dataARRAY;\n"; |
| static const GLchar* output_var = "out Data dataARRAY;\n"; |
| static const GLchar* output_use = " dataINDEX.gohan = result / 2;\n" |
| " dataINDEX.goten = result / 4 - dataINDEX.gohan;\n"; |
| static const GLchar* fs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 gs_fs;\n" |
| "out vec4 fs_out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " fs_out = gs_fs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* fs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "STRUCT_DEFINITION" |
| "\n" |
| "VARIABLE_DEFINITION" |
| "\n" |
| "in vec4 gs_fs;\n" |
| "out vec4 fs_out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = gs_fs;\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " fs_out += result;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* gs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| "in vec4 tes_gs[];\n" |
| "out vec4 gs_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| static const GLchar* gs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| "STRUCT_DEFINITION" |
| "\n" |
| "VARIABLE_DEFINITION" |
| "\n" |
| "in vec4 tes_gs[];\n" |
| "out vec4 gs_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = tes_gs[0];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tcs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "in vec4 vs_tcs[];\n" |
| "out vec4 tcs_tes[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| "\n" |
| " tcs_tes[gl_InvocationID] = vs_tcs[gl_InvocationID];\n" |
| "\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tcs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "STRUCT_DEFINITION" |
| "\n" |
| "VARIABLE_DEFINITION" |
| "\n" |
| "in vec4 vs_tcs[];\n" |
| "out vec4 tcs_tes[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = vs_tcs[gl_InvocationID];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " tcs_tes[gl_InvocationID] = result;\n" |
| "\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tes = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(isolines, point_mode) in;\n" |
| "\n" |
| "in vec4 tcs_tes[];\n" |
| "out vec4 tes_gs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " tes_gs = tcs_tes[0];\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tes_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(isolines, point_mode) in;\n" |
| "\n" |
| "STRUCT_DEFINITION" |
| "\n" |
| "VARIABLE_DEFINITION" |
| "\n" |
| "in vec4 tcs_tes[];\n" |
| "out vec4 tes_gs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = tcs_tes[0];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " tes_gs += result;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 vs_tcs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vs_tcs = in_vs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "STRUCT_DEFINITION" |
| "\n" |
| "VARIABLE_DEFINITION" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 vs_tcs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = in_vs;\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " vs_tcs += result;\n" |
| "}\n" |
| "\n"; |
| |
| std::string source; |
| testCase& test_case = m_test_cases[test_case_index]; |
| const GLchar* var_definition = input_var; |
| const GLchar* var_use = Utils::Shader::VERTEX == test_case.m_stage ? input_use : "\n"; |
| const GLchar* array = ""; |
| const GLchar* index = ""; |
| |
| if (!test_case.m_is_input) |
| { |
| var_definition = output_var; |
| var_use = output_use; |
| } |
| |
| if (test_case.m_stage == stage) |
| { |
| size_t position = 0; |
| size_t temp = 0; |
| |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs_tested; |
| break; |
| case Utils::Shader::GEOMETRY: |
| source = gs_tested; |
| array = test_case.m_is_input ? "[]" : ""; |
| index = test_case.m_is_input ? "[0]" : ""; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| source = tcs_tested; |
| array = "[]"; |
| index = "[gl_InvocationID]"; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| source = tes_tested; |
| array = test_case.m_is_input ? "[]" : ""; |
| index = test_case.m_is_input ? "[0]" : ""; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs_tested; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| Utils::replaceToken("STRUCT_DEFINITION", position, struct_definition, source); |
| temp = position; |
| Utils::replaceToken("VARIABLE_DEFINITION", position, var_definition, source); |
| position = temp; |
| Utils::replaceToken("ARRAY", position, array, source); |
| Utils::replaceToken("VARIABLE_USE", position, var_use, source); |
| |
| Utils::replaceAllTokens("INDEX", index, source); |
| } |
| else |
| { |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs; |
| break; |
| case Utils::Shader::GEOMETRY: |
| source = gs; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| source = tcs; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| source = tes; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| } |
| |
| return source; |
| } |
| |
| /** Get description of test case |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return Test case description |
| **/ |
| std::string VaryingStructureMemberLocationTest::getTestCaseName(GLuint test_case_index) |
| { |
| std::stringstream stream; |
| testCase& test_case = m_test_cases[test_case_index]; |
| |
| stream << "Stage: " << Utils::Shader::GetStageName(test_case.m_stage) << ", direction: "; |
| |
| if (true == test_case.m_is_input) |
| { |
| stream << "input"; |
| } |
| else |
| { |
| stream << "output"; |
| } |
| |
| return stream.str(); |
| } |
| |
| /** Get number of test cases |
| * |
| * @return Number of test cases |
| **/ |
| GLuint VaryingStructureMemberLocationTest::getTestCaseNumber() |
| { |
| return static_cast<GLuint>(m_test_cases.size()); |
| } |
| |
| /** Selects if "compute" stage is relevant for test |
| * |
| * @param ignored |
| * |
| * @return false |
| **/ |
| bool VaryingStructureMemberLocationTest::isComputeRelevant(GLuint /* test_case_index */) |
| { |
| return false; |
| } |
| |
| /** Prepare all test cases |
| * |
| **/ |
| void VaryingStructureMemberLocationTest::testInit() |
| { |
| for (GLuint stage = 0; stage < Utils::Shader::STAGE_MAX; ++stage) |
| { |
| if (Utils::Shader::COMPUTE == stage) |
| { |
| continue; |
| } |
| |
| testCase test_case_in = { true, (Utils::Shader::STAGES)stage }; |
| testCase test_case_out = { false, (Utils::Shader::STAGES)stage }; |
| |
| /* It is a compile-time error to declare a struct as a VS input */ |
| if (Utils::Shader::VERTEX != stage) |
| { |
| m_test_cases.push_back(test_case_in); |
| } |
| |
| if (Utils::Shader::FRAGMENT != stage) |
| { |
| m_test_cases.push_back(test_case_out); |
| } |
| } |
| } |
| |
| /** Constructor |
| * |
| * @param context Test framework context |
| **/ |
| VaryingBlockLocationsTest::VaryingBlockLocationsTest(deqp::Context& context) |
| : TextureTestBase(context, "varying_block_locations", |
| "Test verifies that locations are respected when blocks are used as in and out ") |
| { |
| } |
| |
| /** Prepare code snippet that will pass in variables to out variables |
| * |
| * @param ignored |
| * @param varying_passthrough Collection of connections between in and out variables |
| * @param stage Shader stage |
| * |
| * @return Code that pass in variables to next stage |
| **/ |
| std::string VaryingBlockLocationsTest::getPassSnippet(GLuint /* test_case_index */, |
| Utils::VaryingPassthrough& varying_passthrough, |
| Utils::Shader::STAGES stage) |
| { |
| std::string result; |
| |
| if (Utils::Shader::VERTEX != stage) |
| { |
| result = TextureTestBase::getPassSnippet(0, varying_passthrough, stage); |
| } |
| else |
| { |
| result = "vs_tcs_block.third = vs_in_third;\n" |
| " vs_tcs_block.fourth = vs_in_fourth;\n" |
| " vs_tcs_block.fifth = vs_in_fifth;\n"; |
| } |
| |
| return result; |
| } |
| |
| /** Get interface of program |
| * |
| * @param ignored |
| * @param program_interface Interface of program |
| * @param varying_passthrough Collection of connections between in and out variables |
| **/ |
| void VaryingBlockLocationsTest::getProgramInterface(GLuint /* test_case_index */, |
| Utils::ProgramInterface& program_interface, |
| Utils::VaryingPassthrough& varying_passthrough) |
| { |
| Utils::ShaderInterface& si = program_interface.GetShaderInterface(Utils::Shader::VERTEX); |
| const Utils::Type vec4 = Utils::Type::vec4; |
| |
| /* Prepare data */ |
| m_third_data = vec4.GenerateData(); |
| m_fourth_data = vec4.GenerateData(); |
| m_fifth_data = vec4.GenerateData(); |
| |
| /* Memory layout is different from location layout */ |
| const GLuint fifth_offset = 0u; |
| const GLuint third_offset = static_cast<GLuint>(fifth_offset + m_fifth_data.size()); |
| const GLuint fourth_offset = static_cast<GLuint>(third_offset + m_fourth_data.size()); |
| |
| m_data.resize(fourth_offset + m_fourth_data.size()); |
| GLubyte* ptr = (GLubyte*)&m_data[0]; |
| memcpy(ptr + third_offset, &m_third_data[0], m_third_data.size()); |
| memcpy(ptr + fourth_offset, &m_fourth_data[0], m_fourth_data.size()); |
| memcpy(ptr + fifth_offset, &m_fifth_data[0], m_fifth_data.size()); |
| |
| Utils::Interface* block = program_interface.Block("vs_tcs_Block"); |
| |
| block->Member("fifth", "" /* qualifiers */, 0 /* component */, 4 /* location */, vec4, false /* normalized */, |
| 0u /* n_array_elements */, 0u /* stride */, fifth_offset /* offset */); |
| |
| block->Member("third", "layout (location = 2)" /* qualifiers */, 0 /* component */, 2 /* location */, vec4, |
| false /* normalized */, 0u /* n_array_elements */, 0u /* stride */, third_offset /* offset */); |
| |
| block->Member("fourth", "" /* qualifiers */, 0 /* component */, 3 /* location */, vec4, false /* normalized */, |
| 0u /* n_array_elements */, 0u /* stride */, fourth_offset /* offset */); |
| |
| si.Output("vs_tcs_block", "layout (location = 4)", 0 /* component */, 4 /* location */, block, |
| 0u /* n_array_elements */, 0u /* stride */, 0u /* offset */, (GLvoid*)&m_data[0] /* data */, |
| m_data.size() /* data_size */); |
| |
| si.Input("vs_in_third", "layout (location = 0)", 0 /* component */, 0 /* location */, vec4, false /* normalized */, |
| 0u /* n_array_elements */, 0u /* stride */, third_offset /* offset */, |
| (GLvoid*)&m_third_data[0] /* data */, m_third_data.size() /* data_size */); |
| |
| si.Input("vs_in_fourth", "layout (location = 1)", 0 /* component */, 1 /* location */, vec4, false /* normalized */, |
| 0u /* n_array_elements */, 0u /* stride */, fourth_offset /* offset */, |
| (GLvoid*)&m_fourth_data[0] /* data */, m_fourth_data.size() /* data_size */); |
| |
| si.Input("vs_in_fifth", "layout (location = 2)", 0 /* component */, 2 /* location */, vec4, false /* normalized */, |
| 0u /* n_array_elements */, 0u /* stride */, fifth_offset /* offset */, |
| (GLvoid*)&m_fifth_data[0] /* data */, m_fifth_data.size() /* data_size */); |
| |
| program_interface.CloneVertexInterface(varying_passthrough); |
| } |
| |
| /** Selects if "compute" stage is relevant for test |
| * |
| * @param ignored |
| * |
| * @return false |
| **/ |
| bool VaryingBlockLocationsTest::isComputeRelevant(GLuint /* test_case_index */) |
| { |
| return false; |
| } |
| |
| /** This test should be run with separable programs |
| * |
| * @param ignored |
| * |
| * @return true |
| **/ |
| bool VaryingBlockLocationsTest::useMonolithicProgram(GLuint /* test_case_index */) |
| { |
| return false; |
| } |
| |
| /** Constructor |
| * |
| * @param context Test framework context |
| **/ |
| VaryingBlockMemberLocationsTest::VaryingBlockMemberLocationsTest(deqp::Context& context) |
| : NegativeTestBase( |
| context, "varying_block_member_locations", |
| "Test verifies that compilation error is reported when not all members of block are qualified with location") |
| { |
| } |
| |
| /** Source for given test case and stage |
| * |
| * @param test_case_index Index of test case |
| * @param stage Shader stage |
| * |
| * @return Shader source |
| **/ |
| std::string VaryingBlockMemberLocationsTest::getShaderSource(GLuint test_case_index, Utils::Shader::STAGES stage) |
| { |
| static const GLchar* block_definition_all = "Goku {\n" |
| " layout (location = 2) vec4 gohan;\n" |
| " layout (location = 4) vec4 goten;\n" |
| " layout (location = 6) vec4 chichi;\n" |
| "} gokuARRAY;\n"; |
| static const GLchar* block_definition_one = "Goku {\n" |
| " vec4 gohan;\n" |
| #if DEBUG_NEG_REMOVE_ERROR |
| " /* layout (location = 4) */ vec4 goten;\n" |
| #else |
| " layout (location = 4) vec4 goten;\n" |
| #endif /* DEBUG_NEG_REMOVE_ERROR */ |
| " vec4 chichi;\n" |
| "} gokuARRAY;\n"; |
| static const GLchar* input_use = " result += gokuINDEX.gohan + gokuINDEX.goten + gokuINDEX.chichi;\n"; |
| static const GLchar* output_use = " gokuINDEX.gohan = result / 2;\n" |
| " gokuINDEX.goten = result / 4 - gokuINDEX.gohan;\n" |
| " gokuINDEX.chichi = result / 8 - gokuINDEX.goten;\n"; |
| static const GLchar* fs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 gs_fs;\n" |
| "out vec4 fs_out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " fs_out = gs_fs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* fs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "DIRECTION BLOCK_DEFINITION" |
| "\n" |
| "in vec4 gs_fs;\n" |
| "out vec4 fs_out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = gs_fs;\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " fs_out = result;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* gs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| "in vec4 tes_gs[];\n" |
| "out vec4 gs_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| static const GLchar* gs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| "DIRECTION BLOCK_DEFINITION" |
| "\n" |
| "in vec4 tes_gs[];\n" |
| "out vec4 gs_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = tes_gs[0];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tcs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "in vec4 vs_tcs[];\n" |
| "out vec4 tcs_tes[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| "\n" |
| " tcs_tes[gl_InvocationID] = vs_tcs[gl_InvocationID];\n" |
| "\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tcs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "DIRECTION BLOCK_DEFINITION" |
| "\n" |
| "in vec4 vs_tcs[];\n" |
| "out vec4 tcs_tes[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = vs_tcs[gl_InvocationID];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " tcs_tes[gl_InvocationID] = result;\n" |
| "\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tes = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(isolines, point_mode) in;\n" |
| "\n" |
| "in vec4 tcs_tes[];\n" |
| "out vec4 tes_gs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " tes_gs = tcs_tes[0];\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tes_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(isolines, point_mode) in;\n" |
| "\n" |
| "DIRECTION BLOCK_DEFINITION" |
| "\n" |
| "in vec4 tcs_tes[];\n" |
| "out vec4 tes_gs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = tcs_tes[0];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " tes_gs = result;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 vs_tcs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vs_tcs = in_vs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "DIRECTION BLOCK_DEFINITION" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 vs_tcs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = in_vs;\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " vs_tcs = result;\n" |
| "}\n" |
| "\n"; |
| |
| const GLchar* array = ""; |
| const GLchar* direction = "in"; |
| const GLchar* index = ""; |
| std::string source; |
| testCase& test_case = m_test_cases[test_case_index]; |
| const GLchar* var_use = Utils::Shader::VERTEX == test_case.m_stage ? input_use : "\n"; |
| const GLchar* definition = test_case.m_qualify_all ? block_definition_all : block_definition_one; |
| |
| if (!test_case.m_is_input) |
| { |
| direction = "out"; |
| var_use = output_use; |
| } |
| |
| if (test_case.m_stage == stage) |
| { |
| size_t position = 0; |
| size_t temp = 0; |
| |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs_tested; |
| break; |
| case Utils::Shader::GEOMETRY: |
| source = gs_tested; |
| array = test_case.m_is_input ? "[]" : ""; |
| index = test_case.m_is_input ? "[0]" : ""; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| source = tcs_tested; |
| array = "[]"; |
| index = "[gl_InvocationID]"; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| source = tes_tested; |
| array = test_case.m_is_input ? "[]" : ""; |
| index = test_case.m_is_input ? "[0]" : ""; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs_tested; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| Utils::replaceToken("DIRECTION", position, direction, source); |
| temp = position; |
| Utils::replaceToken("BLOCK_DEFINITION", position, definition, source); |
| position = temp; |
| Utils::replaceToken("ARRAY", position, array, source); |
| Utils::replaceToken("VARIABLE_USE", position, var_use, source); |
| |
| Utils::replaceAllTokens("INDEX", index, source); |
| } |
| else |
| { |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs; |
| break; |
| case Utils::Shader::GEOMETRY: |
| source = gs; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| source = tcs; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| source = tes; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| } |
| |
| return source; |
| } |
| |
| /** Get description of test case |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return Test case description |
| **/ |
| std::string VaryingBlockMemberLocationsTest::getTestCaseName(GLuint test_case_index) |
| { |
| std::stringstream stream; |
| testCase& test_case = m_test_cases[test_case_index]; |
| |
| stream << "Stage: " << Utils::Shader::GetStageName(test_case.m_stage) << ", direction: "; |
| |
| if (true == test_case.m_is_input) |
| { |
| stream << "input"; |
| } |
| else |
| { |
| stream << "output"; |
| } |
| |
| if (true == test_case.m_qualify_all) |
| { |
| stream << ", all members qualified"; |
| } |
| else |
| { |
| stream << ", not all members qualified"; |
| } |
| |
| return stream.str(); |
| } |
| |
| /** Get number of test cases |
| * |
| * @return Number of test cases |
| **/ |
| GLuint VaryingBlockMemberLocationsTest::getTestCaseNumber() |
| { |
| return static_cast<GLuint>(m_test_cases.size()); |
| } |
| |
| /** Selects if "compute" stage is relevant for test |
| * |
| * @param ignored |
| * |
| * @return false |
| **/ |
| bool VaryingBlockMemberLocationsTest::isComputeRelevant(GLuint /* test_case_index */) |
| { |
| return false; |
| } |
| |
| /** Selects if compilation failure is expected result |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return false when all members are qualified, true otherwise |
| **/ |
| bool VaryingBlockMemberLocationsTest::isFailureExpected(GLuint test_case_index) |
| { |
| return (true != m_test_cases[test_case_index].m_qualify_all); |
| } |
| |
| /** Prepare all test cases |
| * |
| **/ |
| void VaryingBlockMemberLocationsTest::testInit() |
| { |
| for (GLuint stage = 0; stage < Utils::Shader::STAGE_MAX; ++stage) |
| { |
| if (Utils::Shader::COMPUTE == stage) |
| { |
| continue; |
| } |
| |
| testCase test_case_in_all = { true, true, (Utils::Shader::STAGES)stage }; |
| testCase test_case_in_one = { true, false, (Utils::Shader::STAGES)stage }; |
| testCase test_case_out_all = { false, true, (Utils::Shader::STAGES)stage }; |
| testCase test_case_out_one = { false, false, (Utils::Shader::STAGES)stage }; |
| |
| if (Utils::Shader::VERTEX != stage) |
| { |
| m_test_cases.push_back(test_case_in_all); |
| m_test_cases.push_back(test_case_in_one); |
| } |
| |
| if (Utils::Shader::FRAGMENT != stage) |
| { |
| m_test_cases.push_back(test_case_out_all); |
| m_test_cases.push_back(test_case_out_one); |
| } |
| } |
| } |
| |
| /** Constructor |
| * |
| * @param context Test framework context |
| **/ |
| VaryingBlockAutomaticMemberLocationsTest::VaryingBlockAutomaticMemberLocationsTest(deqp::Context& context) |
| : NegativeTestBase( |
| context, "varying_block_automatic_member_locations", |
| "Test verifies that compiler assigns subsequent locations to block members, even if this causes errors") |
| { |
| } |
| |
| /** Source for given test case and stage |
| * |
| * @param test_case_index Index of test case |
| * @param stage Shader stage |
| * |
| * @return Shader source |
| **/ |
| std::string VaryingBlockAutomaticMemberLocationsTest::getShaderSource(GLuint test_case_index, |
| Utils::Shader::STAGES stage) |
| { |
| static const GLchar* block_definition = "layout (location = 2) DIRECTION DBZ {\n" |
| " vec4 goku;\n" |
| " vec4 gohan[4];\n" |
| " vec4 goten;\n" |
| #if DEBUG_NEG_REMOVE_ERROR |
| " /* layout (location = 1) */ vec4 chichi;\n" |
| #else |
| " layout (location = 1) vec4 chichi;\n" |
| #endif /* DEBUG_NEG_REMOVE_ERROR */ |
| " vec4 pan;\n" |
| "} dbzARRAY;\n"; |
| static const GLchar* input_use = " result += dbzINDEX.goku + dbzINDEX.gohan[0] + dbzINDEX.gohan[1] + " |
| "dbzINDEX.gohan[3] + dbzINDEX.gohan[2] + dbzINDEX.goten + dbzINDEX.chichi + " |
| "dbzINDEX.pan;\n"; |
| static const GLchar* output_use = " dbzINDEX.goku = result;\n" |
| " dbzINDEX.gohan[0] = result / 2;\n" |
| " dbzINDEX.gohan[1] = result / 2.25;\n" |
| " dbzINDEX.gohan[2] = result / 2.5;\n" |
| " dbzINDEX.gohan[3] = result / 2.75;\n" |
| " dbzINDEX.goten = result / 4 - dbzINDEX.gohan[0] - dbzINDEX.gohan[1] - " |
| "dbzINDEX.gohan[2] - dbzINDEX.gohan[3];\n" |
| " dbzINDEX.chichi = result / 8 - dbzINDEX.goten;\n" |
| " dbzINDEX.pan = result / 16 - dbzINDEX.chichi;\n"; |
| static const GLchar* fs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 gs_fs;\n" |
| "out vec4 fs_out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " fs_out = gs_fs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* fs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "BLOCK_DEFINITION" |
| "\n" |
| "in vec4 gs_fs;\n" |
| "out vec4 fs_out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = gs_fs;\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " fs_out += result;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* gs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| "in vec4 tes_gs[];\n" |
| "out vec4 gs_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| static const GLchar* gs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| "BLOCK_DEFINITION" |
| "\n" |
| "in vec4 tes_gs[];\n" |
| "out vec4 gs_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = tes_gs[0];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tcs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "in vec4 vs_tcs[];\n" |
| "out vec4 tcs_tes[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| "\n" |
| " tcs_tes[gl_InvocationID] = vs_tcs[gl_InvocationID];\n" |
| "\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tcs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "BLOCK_DEFINITION" |
| "\n" |
| "in vec4 vs_tcs[];\n" |
| "out vec4 tcs_tes[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = vs_tcs[gl_InvocationID];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " tcs_tes[gl_InvocationID] = result;\n" |
| "\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tes = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(isolines, point_mode) in;\n" |
| "\n" |
| "in vec4 tcs_tes[];\n" |
| "out vec4 tes_gs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " tes_gs = tcs_tes[0];\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tes_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(isolines, point_mode) in;\n" |
| "\n" |
| "BLOCK_DEFINITION" |
| "\n" |
| "in vec4 tcs_tes[];\n" |
| "out vec4 tes_gs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = tcs_tes[0];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " tes_gs += result;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 vs_tcs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vs_tcs = in_vs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "BLOCK_DEFINITION" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 vs_tcs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = in_vs;\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " vs_tcs += result;\n" |
| "}\n" |
| "\n"; |
| |
| const GLchar* array = ""; |
| const GLchar* direction = "in"; |
| const GLchar* index = ""; |
| std::string source; |
| testCase& test_case = m_test_cases[test_case_index]; |
| const GLchar* var_use = Utils::Shader::VERTEX == test_case.m_stage ? input_use : "\n"; |
| |
| if (!test_case.m_is_input) |
| { |
| direction = "out"; |
| var_use = output_use; |
| } |
| |
| if (test_case.m_stage == stage) |
| { |
| size_t position = 0; |
| |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs_tested; |
| break; |
| case Utils::Shader::GEOMETRY: |
| source = gs_tested; |
| array = test_case.m_is_input ? "[]" : ""; |
| index = test_case.m_is_input ? "[0]" : ""; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| source = tcs_tested; |
| array = "[]"; |
| index = "[gl_InvocationID]"; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| source = tes_tested; |
| array = test_case.m_is_input ? "[]" : ""; |
| index = test_case.m_is_input ? "[0]" : ""; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs_tested; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| Utils::replaceToken("BLOCK_DEFINITION", position, block_definition, source); |
| position = 0; |
| Utils::replaceToken("DIRECTION", position, direction, source); |
| Utils::replaceToken("ARRAY", position, array, source); |
| Utils::replaceToken("VARIABLE_USE", position, var_use, source); |
| |
| Utils::replaceAllTokens("INDEX", index, source); |
| } |
| else |
| { |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs; |
| break; |
| case Utils::Shader::GEOMETRY: |
| source = gs; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| source = tcs; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| source = tes; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| } |
| |
| return source; |
| } |
| |
| /** Get description of test case |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return Test case description |
| **/ |
| std::string VaryingBlockAutomaticMemberLocationsTest::getTestCaseName(GLuint test_case_index) |
| { |
| std::stringstream stream; |
| testCase& test_case = m_test_cases[test_case_index]; |
| |
| stream << "Stage: " << Utils::Shader::GetStageName(test_case.m_stage) << ", direction: "; |
| |
| if (true == test_case.m_is_input) |
| { |
| stream << "input"; |
| } |
| else |
| { |
| stream << "output"; |
| } |
| |
| return stream.str(); |
| } |
| |
| /** Get number of test cases |
| * |
| * @return Number of test cases |
| **/ |
| GLuint VaryingBlockAutomaticMemberLocationsTest::getTestCaseNumber() |
| { |
| return static_cast<GLuint>(m_test_cases.size()); |
| } |
| |
| /** Selects if "compute" stage is relevant for test |
| * |
| * @param ignored |
| * |
| * @return false |
| **/ |
| bool VaryingBlockAutomaticMemberLocationsTest::isComputeRelevant(GLuint /* test_case_index */) |
| { |
| return false; |
| } |
| |
| /** Prepare all test cases |
| * |
| **/ |
| void VaryingBlockAutomaticMemberLocationsTest::testInit() |
| { |
| for (GLuint stage = 0; stage < Utils::Shader::STAGE_MAX; ++stage) |
| { |
| if (Utils::Shader::COMPUTE == stage) |
| { |
| continue; |
| } |
| |
| testCase test_case_in = { true, (Utils::Shader::STAGES)stage }; |
| testCase test_case_out = { false, (Utils::Shader::STAGES)stage }; |
| |
| if (Utils::Shader::VERTEX != stage) |
| { |
| m_test_cases.push_back(test_case_in); |
| } |
| |
| if (Utils::Shader::FRAGMENT != stage) |
| { |
| m_test_cases.push_back(test_case_out); |
| } |
| } |
| } |
| |
| /** Constructor |
| * |
| * @param context Test framework context |
| **/ |
| VaryingLocationLimitTest::VaryingLocationLimitTest(deqp::Context& context) |
| : NegativeTestBase(context, "varying_location_limit", |
| "Test verifies that compiler reports error when location qualifier exceeds limits") |
| { |
| } |
| |
| /** Source for given test case and stage |
| * |
| * @param test_case_index Index of test case |
| * @param stage Shader stage |
| * |
| * @return Shader source |
| **/ |
| std::string VaryingLocationLimitTest::getShaderSource(GLuint test_case_index, Utils::Shader::STAGES stage) |
| { |
| #if DEBUG_NEG_REMOVE_ERROR |
| static const GLchar* var_definition = "layout (location = LAST /* + 1 */) FLAT DIRECTION TYPE gokuARRAY;\n"; |
| #else |
| static const GLchar* var_definition = "layout (location = LAST + 1) FLAT DIRECTION TYPE gokuARRAY;\n"; |
| #endif /* DEBUG_NEG_REMOVE_ERROR */ |
| static const GLchar* input_use = " if (TYPE(0) == gokuINDEX)\n" |
| " {\n" |
| " result += vec4(1, 0.5, 0.25, 0.125);\n" |
| " }\n"; |
| static const GLchar* output_use = " gokuINDEX = TYPE(0);\n" |
| " if (vec4(0) == result)\n" |
| " {\n" |
| " gokuINDEX = TYPE(1);\n" |
| " }\n"; |
| static const GLchar* fs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 gs_fs;\n" |
| "out vec4 fs_out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " fs_out = gs_fs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* fs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 gs_fs;\n" |
| "out vec4 fs_out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = gs_fs;\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " fs_out += result;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* gs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| "PERVERTEX" /* Separable programs require explicit declaration of gl_PerVertex */ |
| "in vec4 tes_gs[];\n" |
| "out vec4 gs_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| static const GLchar* gs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| "PERVERTEX" /* Separable programs require explicit declaration of gl_PerVertex */ |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 tes_gs[];\n" |
| "out vec4 gs_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = tes_gs[0];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tcs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "in vec4 vs_tcs[];\n" |
| "out vec4 tcs_tes[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| "\n" |
| " tcs_tes[gl_InvocationID] = vs_tcs[gl_InvocationID];\n" |
| "\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tcs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 vs_tcs[];\n" |
| "out vec4 tcs_tes[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = vs_tcs[gl_InvocationID];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " tcs_tes[gl_InvocationID] = result;\n" |
| "\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tes = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(isolines, point_mode) in;\n" |
| "\n" |
| "in vec4 tcs_tes[];\n" |
| "out vec4 tes_gs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " tes_gs = tcs_tes[0];\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tes_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(isolines, point_mode) in;\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 tcs_tes[];\n" |
| "out vec4 tes_gs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = tcs_tes[0];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " tes_gs += result;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 vs_tcs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vs_tcs = in_vs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 vs_tcs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = in_vs;\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " vs_tcs += result;\n" |
| "}\n" |
| "\n"; |
| |
| std::string source; |
| testCase& test_case = m_test_cases[test_case_index]; |
| size_t position = 0; |
| const GLchar* per_vertex = !isSeparable(test_case_index) ? "" : "out gl_PerVertex {\n" |
| "vec4 gl_Position;\n" |
| "};\n" |
| "\n"; |
| |
| if (test_case.m_stage == stage) |
| { |
| const GLchar* array = ""; |
| GLchar buffer[16]; |
| const GLchar* direction = "in "; |
| const GLchar* flat = ""; |
| const GLchar* index = ""; |
| GLuint last = getLastInputLocation(stage, test_case.m_type, 0, true); |
| const GLchar* type_name = test_case.m_type.GetGLSLTypeName(); |
| Utils::Variable::STORAGE storage = Utils::Variable::VARYING_INPUT; |
| const GLchar* var_use = input_use; |
| |
| if (false == test_case.m_is_input) |
| { |
| direction = "out"; |
| last = getLastOutputLocation(stage, test_case.m_type, 0, true); |
| storage = Utils::Variable::VARYING_OUTPUT; |
| var_use = output_use; |
| } |
| |
| if (isFlatRequired(stage, test_case.m_type, storage)) |
| { |
| flat = "flat"; |
| } |
| |
| sprintf(buffer, "%d", last); |
| |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs_tested; |
| break; |
| case Utils::Shader::GEOMETRY: |
| source = gs_tested; |
| array = test_case.m_is_input ? "[]" : ""; |
| index = test_case.m_is_input ? "[0]" : ""; |
| Utils::replaceToken("PERVERTEX", position, per_vertex, source); |
| break; |
| case Utils::Shader::TESS_CTRL: |
| source = tcs_tested; |
| array = "[]"; |
| index = "[gl_InvocationID]"; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| source = tes_tested; |
| array = test_case.m_is_input ? "[]" : ""; |
| index = test_case.m_is_input ? "[0]" : ""; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs_tested; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| Utils::replaceToken("VAR_DEFINITION", position, var_definition, source); |
| position = 0; |
| Utils::replaceToken("LAST", position, buffer, source); |
| Utils::replaceToken("FLAT", position, flat, source); |
| Utils::replaceToken("DIRECTION", position, direction, source); |
| Utils::replaceToken("ARRAY", position, array, source); |
| Utils::replaceToken("VARIABLE_USE", position, var_use, source); |
| |
| Utils::replaceAllTokens("TYPE", type_name, source); |
| Utils::replaceAllTokens("INDEX", index, source); |
| } |
| else |
| { |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs; |
| break; |
| case Utils::Shader::GEOMETRY: |
| source = gs; |
| Utils::replaceToken("PERVERTEX", position, per_vertex, source); |
| break; |
| case Utils::Shader::TESS_CTRL: |
| source = tcs; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| source = tes; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| } |
| |
| return source; |
| } |
| |
| /** Get description of test case |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return Test case description |
| **/ |
| std::string VaryingLocationLimitTest::getTestCaseName(GLuint test_case_index) |
| { |
| std::stringstream stream; |
| testCase& test_case = m_test_cases[test_case_index]; |
| |
| stream << "Stage: " << Utils::Shader::GetStageName(test_case.m_stage) |
| << " type: " << test_case.m_type.GetGLSLTypeName() << ", direction: "; |
| |
| if (true == test_case.m_is_input) |
| { |
| stream << "input"; |
| } |
| else |
| { |
| stream << "output"; |
| } |
| |
| return stream.str(); |
| } |
| |
| /** Get number of test cases |
| * |
| * @return Number of test cases |
| **/ |
| GLuint VaryingLocationLimitTest::getTestCaseNumber() |
| { |
| return static_cast<GLuint>(m_test_cases.size()); |
| } |
| |
| /** Selects if "compute" stage is relevant for test |
| * |
| * @param ignored |
| * |
| * @return false |
| **/ |
| bool VaryingLocationLimitTest::isComputeRelevant(GLuint /* test_case_index */) |
| { |
| return false; |
| } |
| |
| /** Selects if the test case should use a separable program |
| * |
| * @param test_case_index Id of test case |
| * |
| * @return whether the test should use separable programs or not |
| **/ |
| bool VaryingLocationLimitTest::isSeparable(const GLuint test_case_index) |
| { |
| const testCase& test_case = m_test_cases[test_case_index]; |
| |
| return test_case.m_is_input && test_case.m_stage != Utils::Shader::VERTEX; |
| } |
| |
| /** Prepare all test cases |
| * |
| **/ |
| void VaryingLocationLimitTest::testInit() |
| { |
| const GLuint n_types = getTypesNumber(); |
| |
| for (GLuint i = 0; i < n_types; ++i) |
| { |
| const Utils::Type& type = getType(i); |
| |
| for (GLuint stage = 0; stage < Utils::Shader::STAGE_MAX; ++stage) |
| { |
| if (Utils::Shader::COMPUTE == stage) |
| { |
| continue; |
| } |
| |
| testCase test_case_in = { true, type, (Utils::Shader::STAGES)stage }; |
| testCase test_case_out = { false, type, (Utils::Shader::STAGES)stage }; |
| |
| m_test_cases.push_back(test_case_in); |
| |
| if (Utils::Shader::FRAGMENT != stage) |
| { |
| m_test_cases.push_back(test_case_out); |
| } |
| } |
| } |
| } |
| |
| /** Constructor |
| * |
| * @param context Test framework context |
| **/ |
| VaryingComponentsTest::VaryingComponentsTest(deqp::Context& context) |
| : VaryingLocationsTest(context, "varying_components", |
| "Test verifies that input and output components are respected") |
| { |
| } |
| |
| /** Constructor |
| * |
| * @param context Test framework context |
| * @param test_name Name of test |
| * @param test_description Description of test |
| **/ |
| VaryingComponentsTest::VaryingComponentsTest(deqp::Context& context, const glw::GLchar* test_name, |
| const glw::GLchar* test_description) |
| : VaryingLocationsTest(context, test_name, test_description) |
| { |
| } |
| |
| /** Get interface of program |
| * |
| * @param test_case_index Test case |
| * @param program_interface Interface of program |
| * @param varying_passthrough Collection of connections between in and out variables |
| **/ |
| void VaryingComponentsTest::getProgramInterface(GLuint test_case_index, Utils::ProgramInterface& program_interface, |
| Utils::VaryingPassthrough& varying_passthrough) |
| { |
| GLuint array_length = getArrayLength(); |
| const testCase& test_case = m_test_cases[test_case_index]; |
| const Utils::Type vector_type = Utils::Type::GetType(test_case.m_type, 1, 4); |
| Utils::ShaderInterface si = program_interface.GetShaderInterface(Utils::Shader::VERTEX); |
| |
| /* Zero means no array, however we still need at least 1 slot of data */ |
| if (0 == array_length) |
| { |
| array_length += 1; |
| } |
| |
| /* Generate data */ |
| const std::vector<GLubyte>& data = vector_type.GenerateDataPacked(); |
| const size_t data_size = data.size(); |
| |
| /* Prepare data for variables */ |
| m_data.resize(array_length * data_size); |
| |
| GLubyte* dst = &m_data[0]; |
| const GLubyte* src = &data[0]; |
| |
| for (GLuint i = 0; i < array_length; ++i) |
| { |
| memcpy(dst + data_size * i, src, data_size); |
| } |
| |
| /* Prepare interface for each stage */ |
| prepareShaderStage(Utils::Shader::FRAGMENT, vector_type, program_interface, test_case, varying_passthrough); |
| prepareShaderStage(Utils::Shader::GEOMETRY, vector_type, program_interface, test_case, varying_passthrough); |
| prepareShaderStage(Utils::Shader::TESS_CTRL, vector_type, program_interface, test_case, varying_passthrough); |
| prepareShaderStage(Utils::Shader::TESS_EVAL, vector_type, program_interface, test_case, varying_passthrough); |
| prepareShaderStage(Utils::Shader::VERTEX, vector_type, program_interface, test_case, varying_passthrough); |
| } |
| |
| /** Get type name |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return Name of type test in test_case_index |
| **/ |
| std::string VaryingComponentsTest::getTestCaseName(glw::GLuint test_case_index) |
| { |
| std::string name; |
| |
| const testCase& test_case = m_test_cases[test_case_index]; |
| |
| name = "Type: "; |
| |
| switch (test_case.m_type) |
| { |
| case Utils::Type::Double: |
| name.append(Utils::Type::_double.GetGLSLTypeName()); |
| break; |
| case Utils::Type::Float: |
| name.append(Utils::Type::_float.GetGLSLTypeName()); |
| break; |
| case Utils::Type::Int: |
| name.append(Utils::Type::_int.GetGLSLTypeName()); |
| break; |
| case Utils::Type::Uint: |
| name.append(Utils::Type::uint.GetGLSLTypeName()); |
| break; |
| } |
| |
| name.append(", layout: "); |
| |
| switch (test_case.m_layout) |
| { |
| case G64VEC2: |
| name.append("G64VEC2"); |
| break; |
| case G64SCALAR_G64SCALAR: |
| name.append("G64SCALAR_G64SCALAR"); |
| break; |
| case GVEC4: |
| name.append("GVEC4"); |
| break; |
| case SCALAR_GVEC3: |
| name.append("SCALAR_GVEC3"); |
| break; |
| case GVEC3_SCALAR: |
| name.append("GVEC3_SCALAR"); |
| break; |
| case GVEC2_GVEC2: |
| name.append("GVEC2_GVEC2"); |
| break; |
| case GVEC2_SCALAR_SCALAR: |
| name.append("GVEC2_SCALAR_SCALAR"); |
| break; |
| case SCALAR_GVEC2_SCALAR: |
| name.append("SCALAR_GVEC2_SCALAR"); |
| break; |
| case SCALAR_SCALAR_GVEC2: |
| name.append("SCALAR_SCALAR_GVEC2"); |
| break; |
| case SCALAR_SCALAR_SCALAR_SCALAR: |
| name.append("SCALAR_SCALAR_SCALAR_SCALAR"); |
| break; |
| } |
| |
| return name; |
| } |
| |
| /** Returns number of types to test |
| * |
| * @return Number of types |
| **/ |
| glw::GLuint VaryingComponentsTest::getTestCaseNumber() |
| { |
| return static_cast<GLuint>(m_test_cases.size()); |
| } |
| |
| /* Prepare test cases */ |
| void VaryingComponentsTest::testInit() |
| { |
| m_test_cases.push_back(testCase(G64VEC2, Utils::Type::Double)); |
| m_test_cases.push_back(testCase(G64SCALAR_G64SCALAR, Utils::Type::Double)); |
| |
| m_test_cases.push_back(testCase(GVEC4, Utils::Type::Float)); |
| m_test_cases.push_back(testCase(SCALAR_GVEC3, Utils::Type::Float)); |
| m_test_cases.push_back(testCase(GVEC3_SCALAR, Utils::Type::Float)); |
| m_test_cases.push_back(testCase(GVEC2_GVEC2, Utils::Type::Float)); |
| m_test_cases.push_back(testCase(GVEC2_SCALAR_SCALAR, Utils::Type::Float)); |
| m_test_cases.push_back(testCase(SCALAR_GVEC2_SCALAR, Utils::Type::Float)); |
| m_test_cases.push_back(testCase(SCALAR_SCALAR_GVEC2, Utils::Type::Float)); |
| m_test_cases.push_back(testCase(SCALAR_SCALAR_SCALAR_SCALAR, Utils::Type::Float)); |
| |
| m_test_cases.push_back(testCase(GVEC4, Utils::Type::Int)); |
| m_test_cases.push_back(testCase(SCALAR_GVEC3, Utils::Type::Int)); |
| m_test_cases.push_back(testCase(GVEC3_SCALAR, Utils::Type::Int)); |
| m_test_cases.push_back(testCase(GVEC2_GVEC2, Utils::Type::Int)); |
| m_test_cases.push_back(testCase(GVEC2_SCALAR_SCALAR, Utils::Type::Int)); |
| m_test_cases.push_back(testCase(SCALAR_GVEC2_SCALAR, Utils::Type::Int)); |
| m_test_cases.push_back(testCase(SCALAR_SCALAR_GVEC2, Utils::Type::Int)); |
| m_test_cases.push_back(testCase(SCALAR_SCALAR_SCALAR_SCALAR, Utils::Type::Int)); |
| |
| m_test_cases.push_back(testCase(GVEC4, Utils::Type::Uint)); |
| m_test_cases.push_back(testCase(SCALAR_GVEC3, Utils::Type::Uint)); |
| m_test_cases.push_back(testCase(GVEC3_SCALAR, Utils::Type::Uint)); |
| m_test_cases.push_back(testCase(GVEC2_GVEC2, Utils::Type::Uint)); |
| m_test_cases.push_back(testCase(GVEC2_SCALAR_SCALAR, Utils::Type::Uint)); |
| m_test_cases.push_back(testCase(SCALAR_GVEC2_SCALAR, Utils::Type::Uint)); |
| m_test_cases.push_back(testCase(SCALAR_SCALAR_GVEC2, Utils::Type::Uint)); |
| m_test_cases.push_back(testCase(SCALAR_SCALAR_SCALAR_SCALAR, Utils::Type::Uint)); |
| } |
| |
| /** Inform that test use components |
| * |
| * @param ignored |
| * |
| * @return true |
| **/ |
| bool VaryingComponentsTest::useComponentQualifier(glw::GLuint /* test_case_index */) |
| { |
| return true; |
| } |
| |
| /** Get length of arrays that should be used during test |
| * |
| * @return 0u - no array at all |
| **/ |
| GLuint VaryingComponentsTest::getArrayLength() |
| { |
| return 0; |
| } |
| |
| std::string VaryingComponentsTest::prepareGlobals(GLuint last_in_location, GLuint last_out_location) |
| { |
| std::string globals = VaryingLocationsTest::prepareGlobals(last_in_location, last_out_location); |
| |
| globals.append("const uint comp_x = 0u;\n" |
| "const uint comp_y = 1u;\n" |
| "const uint comp_z = 2u;\n" |
| "const uint comp_w = 3u;\n"); |
| |
| return globals; |
| } |
| |
| /** |
| * |
| **/ |
| std::string VaryingComponentsTest::prepareName(const glw::GLchar* name, glw::GLint location, glw::GLint component, |
| Utils::Shader::STAGES stage, Utils::Variable::STORAGE storage) |
| { |
| GLchar buffer[16]; |
| std::string result = "PREFIXNAME_lLOCATION_cCOMPONENT"; |
| size_t position = 0; |
| const GLchar* prefix = Utils::ProgramInterface::GetStagePrefix(stage, storage); |
| |
| Utils::replaceToken("PREFIX", position, prefix, result); |
| Utils::replaceToken("NAME", position, name, result); |
| |
| sprintf(buffer, "%d", location); |
| Utils::replaceToken("LOCATION", position, buffer, result); |
| |
| sprintf(buffer, "%d", component); |
| Utils::replaceToken("COMPONENT", position, buffer, result); |
| |
| return result; |
| } |
| |
| std::string VaryingComponentsTest::prepareQualifiers(const glw::GLchar* location, const glw::GLchar* component, |
| const glw::GLchar* interpolation) |
| { |
| size_t position = 0; |
| std::string qualifiers = "layout (location = LOCATION, component = COMPONENT) INTERPOLATION"; |
| |
| Utils::replaceToken("LOCATION", position, location, qualifiers); |
| Utils::replaceToken("COMPONENT", position, component, qualifiers); |
| Utils::replaceToken("INTERPOLATION", position, interpolation, qualifiers); |
| |
| return qualifiers; |
| } |
| |
| /** |
| * |
| **/ |
| void VaryingComponentsTest::prepareShaderStage(Utils::Shader::STAGES stage, const Utils::Type& vector_type, |
| Utils::ProgramInterface& program_interface, const testCase& test_case, |
| Utils::VaryingPassthrough& varying_passthrough) |
| { |
| const GLuint array_length = getArrayLength(); |
| const Utils::Type& basic_type = Utils::Type::GetType(vector_type.m_basic_type, 1 /* n_cols */, 1 /* n_rows */); |
| descriptor desc_in[8]; |
| descriptor desc_out[8]; |
| const GLuint first_in_loc = 0; |
| const GLuint first_out_loc = 0; |
| const GLchar* interpolation = ""; |
| const GLuint last_in_loc = getLastInputLocation(stage, vector_type, array_length, false); |
| GLuint last_out_loc = 0; |
| GLuint n_desc = 0; |
| Utils::ShaderInterface& si = program_interface.GetShaderInterface(stage); |
| |
| /* Select interpolation */ |
| if ((Utils::Shader::FRAGMENT == stage) || (Utils::Shader::GEOMETRY == stage)) |
| { |
| interpolation = " flat"; |
| } |
| |
| if (Utils::Shader::FRAGMENT != stage) |
| { |
| last_out_loc = getLastOutputLocation(stage, vector_type, array_length, false); |
| } |
| |
| switch (test_case.m_layout) |
| { |
| case G64VEC2: |
| n_desc = 2; |
| desc_in[0].assign(0, "comp_x", first_in_loc, "first_input_location", 2, "g64vec2"); |
| desc_in[1].assign(0, "comp_x", last_in_loc, "last_input_location", 2, "g64vec2"); |
| |
| desc_out[0].assign(0, "comp_x", first_out_loc, "first_output_location", 2, "g64vec2"); |
| desc_out[1].assign(0, "comp_x", last_out_loc, "last_output_location", 2, "g64vec2"); |
| break; |
| |
| case G64SCALAR_G64SCALAR: |
| n_desc = 4; |
| desc_in[0].assign(0, "comp_x", first_in_loc, "first_input_location", 1, "g64scalar"); |
| desc_in[1].assign(0, "comp_x", last_in_loc, "last_input_location", 1, "g64scalar"); |
| desc_in[2].assign(2, "comp_z", first_in_loc, "first_input_location", 1, "g64scalar"); |
| desc_in[3].assign(2, "comp_z", last_in_loc, "last_input_location", 1, "g64scalar"); |
| |
| desc_out[0].assign(0, "comp_x", first_out_loc, "first_output_location", 1, "g64scalar"); |
| desc_out[1].assign(0, "comp_x", last_out_loc, "last_output_location", 1, "g64scalar"); |
| desc_out[2].assign(2, "comp_z", first_out_loc, "first_output_location", 1, "g64scalar"); |
| desc_out[3].assign(2, "comp_z", last_out_loc, "last_output_location", 1, "g64scalar"); |
| break; |
| case GVEC4: |
| n_desc = 2; |
| desc_in[0].assign(0, "comp_x", first_in_loc, "first_input_location", 4, "gvec4"); |
| desc_in[1].assign(0, "comp_x", last_in_loc, "last_input_location", 4, "gvec4"); |
| |
| desc_out[0].assign(0, "comp_x", first_out_loc, "first_output_location", 4, "gvec4"); |
| desc_out[1].assign(0, "comp_x", last_out_loc, "last_output_location", 4, "gvec4"); |
| break; |
| case SCALAR_GVEC3: |
| n_desc = 4; |
| desc_in[0].assign(0, "comp_x", first_in_loc, "first_input_location", 1, "scalar"); |
| desc_in[1].assign(0, "comp_x", last_in_loc, "last_input_location", 1, "scalar"); |
| desc_in[2].assign(1, "comp_y", first_in_loc, "first_input_location", 3, "gvec3"); |
| desc_in[3].assign(1, "comp_y", last_in_loc, "last_input_location", 3, "gvec3"); |
| |
| desc_out[0].assign(0, "comp_x", first_out_loc, "first_output_location", 1, "scalar"); |
| desc_out[1].assign(0, "comp_x", last_out_loc, "last_output_location", 1, "scalar"); |
| desc_out[2].assign(1, "comp_y", first_out_loc, "first_output_location", 3, "gvec3"); |
| desc_out[3].assign(1, "comp_y", last_out_loc, "last_output_location", 3, "gvec3"); |
| break; |
| case GVEC3_SCALAR: |
| n_desc = 4; |
| desc_in[0].assign(0, "comp_x", first_in_loc, "first_input_location", 3, "gvec3"); |
| desc_in[1].assign(0, "comp_x", last_in_loc, "last_input_location", 3, "gvec3"); |
| desc_in[2].assign(3, "comp_w", first_in_loc, "first_input_location", 1, "scalar"); |
| desc_in[3].assign(3, "comp_w", last_in_loc, "last_input_location", 1, "scalar"); |
| |
| desc_out[0].assign(0, "comp_x", first_out_loc, "first_output_location", 3, "gvec3"); |
| desc_out[1].assign(0, "comp_x", last_out_loc, "last_output_location", 3, "gvec3"); |
| desc_out[2].assign(3, "comp_w", first_out_loc, "first_output_location", 1, "scalar"); |
| desc_out[3].assign(3, "comp_w", last_out_loc, "last_output_location", 1, "scalar"); |
| break; |
| case GVEC2_GVEC2: |
| n_desc = 4; |
| desc_in[0].assign(0, "comp_x", first_in_loc, "first_input_location", 2, "gvec2"); |
| desc_in[1].assign(0, "comp_x", last_in_loc, "last_input_location", 2, "gvec2"); |
| desc_in[2].assign(2, "comp_z", first_in_loc, "first_input_location", 2, "gvec2"); |
| desc_in[3].assign(2, "comp_z", last_in_loc, "last_input_location", 2, "gvec2"); |
| |
| desc_out[0].assign(0, "comp_x", first_out_loc, "first_output_location", 2, "gvec2"); |
| desc_out[1].assign(0, "comp_x", last_out_loc, "last_output_location", 2, "gvec2"); |
| desc_out[2].assign(2, "comp_z", first_out_loc, "first_output_location", 2, "gvec2"); |
| desc_out[3].assign(2, "comp_z", last_out_loc, "last_output_location", 2, "gvec2"); |
| break; |
| case GVEC2_SCALAR_SCALAR: |
| n_desc = 6; |
| desc_in[0].assign(0, "comp_x", first_in_loc, "first_input_location", 2, "gvec2"); |
| desc_in[1].assign(0, "comp_x", last_in_loc, "last_input_location", 2, "gvec2"); |
| desc_in[2].assign(2, "comp_z", first_in_loc, "first_input_location", 1, "scalar"); |
| desc_in[3].assign(2, "comp_z", last_in_loc, "last_input_location", 1, "scalar"); |
| desc_in[4].assign(3, "comp_w", first_in_loc, "first_input_location", 1, "scalar"); |
| desc_in[5].assign(3, "comp_w", last_in_loc, "last_input_location", 1, "scalar"); |
| |
| desc_out[0].assign(0, "comp_x", first_out_loc, "first_output_location", 2, "gvec2"); |
| desc_out[1].assign(0, "comp_x", last_out_loc, "last_output_location", 2, "gvec2"); |
| desc_out[2].assign(2, "comp_z", first_out_loc, "first_output_location", 1, "scalar"); |
| desc_out[3].assign(2, "comp_z", last_out_loc, "last_output_location", 1, "scalar"); |
| desc_out[4].assign(3, "comp_w", first_out_loc, "first_output_location", 1, "scalar"); |
| desc_out[5].assign(3, "comp_w", last_out_loc, "last_output_location", 1, "scalar"); |
| break; |
| case SCALAR_GVEC2_SCALAR: |
| n_desc = 6; |
| desc_in[0].assign(0, "comp_x", first_in_loc, "first_input_location", 1, "scalar"); |
| desc_in[1].assign(0, "comp_x", last_in_loc, "last_input_location", 1, "scalar"); |
| desc_in[2].assign(1, "comp_y", first_in_loc, "first_input_location", 2, "gvec2"); |
| desc_in[3].assign(1, "comp_y", last_in_loc, "last_input_location", 2, "gvec2"); |
| desc_in[4].assign(3, "comp_w", first_in_loc, "first_input_location", 1, "scalar"); |
| desc_in[5].assign(3, "comp_w", last_in_loc, "last_input_location", 1, "scalar"); |
| |
| desc_out[0].assign(0, "comp_x", first_out_loc, "first_output_location", 1, "scalar"); |
| desc_out[1].assign(0, "comp_x", last_out_loc, "last_output_location", 1, "scalar"); |
| desc_out[2].assign(1, "comp_y", first_out_loc, "first_output_location", 2, "gvec2"); |
| desc_out[3].assign(1, "comp_y", last_out_loc, "last_output_location", 2, "gvec2"); |
| desc_out[4].assign(3, "comp_w", first_out_loc, "first_output_location", 1, "scalar"); |
| desc_out[5].assign(3, "comp_w", last_out_loc, "last_output_location", 1, "scalar"); |
| break; |
| case SCALAR_SCALAR_GVEC2: |
| n_desc = 6; |
| desc_in[0].assign(0, "comp_x", first_in_loc, "first_input_location", 1, "scalar"); |
| desc_in[1].assign(0, "comp_x", last_in_loc, "last_input_location", 1, "scalar"); |
| desc_in[2].assign(1, "comp_y", first_in_loc, "first_input_location", 1, "scalar"); |
| desc_in[3].assign(1, "comp_y", last_in_loc, "last_input_location", 1, "scalar"); |
| desc_in[4].assign(2, "comp_z", first_in_loc, "first_input_location", 2, "gvec2"); |
| desc_in[5].assign(2, "comp_z", last_in_loc, "last_input_location", 2, "gvec2"); |
| |
| desc_out[0].assign(0, "comp_x", first_out_loc, "first_output_location", 1, "scalar"); |
| desc_out[1].assign(0, "comp_x", last_out_loc, "last_output_location", 1, "scalar"); |
| desc_out[2].assign(1, "comp_y", first_out_loc, "first_output_location", 1, "scalar"); |
| desc_out[3].assign(1, "comp_y", last_out_loc, "last_output_location", 1, "scalar"); |
| desc_out[4].assign(2, "comp_z", first_out_loc, "first_output_location", 2, "gvec2"); |
| desc_out[5].assign(2, "comp_z", last_out_loc, "last_output_location", 2, "gvec2"); |
| break; |
| case SCALAR_SCALAR_SCALAR_SCALAR: |
| n_desc = 8; |
| desc_in[0].assign(0, "comp_x", first_in_loc, "first_input_location", 1, "scalar"); |
| desc_in[1].assign(0, "comp_x", last_in_loc, "last_input_location", 1, "scalar"); |
| desc_in[2].assign(1, "comp_y", first_in_loc, "first_input_location", 1, "scalar"); |
| desc_in[3].assign(1, "comp_y", last_in_loc, "last_input_location", 1, "scalar"); |
| desc_in[4].assign(2, "comp_z", first_in_loc, "first_input_location", 1, "scalar"); |
| desc_in[5].assign(2, "comp_z", last_in_loc, "last_input_location", 1, "scalar"); |
| desc_in[6].assign(3, "comp_w", first_in_loc, "first_input_location", 1, "scalar"); |
| desc_in[7].assign(3, "comp_w", last_in_loc, "last_input_location", 1, "scalar"); |
| |
| desc_out[0].assign(0, "comp_x", first_out_loc, "first_output_location", 1, "scalar"); |
| desc_out[1].assign(0, "comp_x", last_out_loc, "last_output_location", 1, "scalar"); |
| desc_out[2].assign(1, "comp_y", first_out_loc, "first_output_location", 1, "scalar"); |
| desc_out[3].assign(1, "comp_y", last_out_loc, "last_output_location", 1, "scalar"); |
| desc_out[4].assign(2, "comp_z", first_out_loc, "first_output_location", 1, "scalar"); |
| desc_out[5].assign(2, "comp_z", last_out_loc, "last_output_location", 1, "scalar"); |
| desc_out[6].assign(3, "comp_w", first_out_loc, "first_output_location", 1, "scalar"); |
| desc_out[7].assign(3, "comp_w", last_out_loc, "last_output_location", 1, "scalar"); |
| break; |
| } |
| |
| for (GLuint i = 0; i < n_desc; ++i) |
| { |
| const descriptor& in_desc = desc_in[i]; |
| |
| Utils::Variable* in = |
| prepareVarying(basic_type, in_desc, interpolation, si, stage, Utils::Variable::VARYING_INPUT); |
| |
| if (Utils::Shader::FRAGMENT != stage) |
| { |
| const descriptor& out_desc = desc_out[i]; |
| |
| Utils::Variable* out = |
| prepareVarying(basic_type, out_desc, interpolation, si, stage, Utils::Variable::VARYING_OUTPUT); |
| |
| varying_passthrough.Add(stage, in, out); |
| } |
| } |
| |
| si.m_globals = prepareGlobals(last_in_loc, last_out_loc); |
| } |
| |
| /** |
| * |
| **/ |
| Utils::Variable* VaryingComponentsTest::prepareVarying(const Utils::Type& basic_type, const descriptor& desc, |
| const GLchar* interpolation, Utils::ShaderInterface& si, |
| Utils::Shader::STAGES stage, Utils::Variable::STORAGE storage) |
| { |
| const GLuint array_length = getArrayLength(); |
| const GLuint component_size = Utils::Type::_float.GetSize(); |
| const std::string& name = prepareName(desc.m_name, desc.m_location, desc.m_component, stage, storage); |
| const GLuint offset = desc.m_component * component_size; |
| const std::string& qual = prepareQualifiers(desc.m_location_str, desc.m_component_str, interpolation); |
| const GLuint size = desc.m_n_rows * basic_type.GetSize(); |
| const Utils::Type& type = Utils::Type::GetType(basic_type.m_basic_type, 1 /* n_columns */, desc.m_n_rows); |
| Utils::Variable* var = 0; |
| |
| if (Utils::Variable::VARYING_INPUT == storage) |
| { |
| var = si.Input(name.c_str(), qual.c_str() /* qualifiers */, desc.m_component /* expected_componenet */, |
| desc.m_location /* expected_location */, type, /* built_in_type */ |
| GL_FALSE /* normalized */, array_length /* n_array_elements */, 0u /* stride */, |
| offset /* offset */, (GLvoid*)&m_data[offset] /* data */, size /* data_size */); |
| } |
| else |
| { |
| var = si.Output(name.c_str(), qual.c_str() /* qualifiers */, desc.m_component /* expected_componenet */, |
| desc.m_location /* expected_location */, type, /* built_in_type */ |
| GL_FALSE /* normalized */, array_length /* n_array_elements */, 0u /* stride */, |
| offset /* offset */, (GLvoid*)&m_data[offset] /* data */, size /* data_size */); |
| } |
| |
| return var; |
| } |
| |
| void VaryingComponentsTest::descriptor::assign(glw::GLint component, const glw::GLchar* component_str, |
| glw::GLint location, const glw::GLchar* location_str, glw::GLuint n_rows, |
| const glw::GLchar* name) |
| { |
| m_component = component; |
| m_component_str = component_str; |
| m_location = location; |
| m_location_str = location_str; |
| m_n_rows = n_rows; |
| m_name = name; |
| } |
| |
| VaryingComponentsTest::testCase::testCase(COMPONENTS_LAYOUT layout, Utils::Type::TYPES type) |
| : m_layout(layout), m_type(type) |
| { |
| } |
| |
| /** Constructor |
| * |
| * @param context Test framework context |
| **/ |
| VaryingArrayComponentsTest::VaryingArrayComponentsTest(deqp::Context& context) |
| : VaryingComponentsTest(context, "varying_array_components", |
| "Test verifies that input and output components are respected for arrays") |
| { |
| } |
| |
| /** Get length of arrays that should be used during test |
| * |
| * @return 4u |
| **/ |
| GLuint VaryingArrayComponentsTest::getArrayLength() |
| { |
| return 4u; |
| } |
| |
| /** Constructor |
| * |
| * @param context Test framework context |
| **/ |
| VaryingInvalidValueComponentTest::VaryingInvalidValueComponentTest(deqp::Context& context) |
| : NegativeTestBase(context, "varying_invalid_value_component", "Test verifies that compiler reports error when " |
| "using an invalid value in the component " |
| "qualification for a specific type") |
| { |
| } |
| |
| /** Source for given test case and stage |
| * |
| * @param test_case_index Index of test case |
| * @param stage Shader stage |
| * |
| * @return Shader source |
| **/ |
| std::string VaryingInvalidValueComponentTest::getShaderSource(GLuint test_case_index, Utils::Shader::STAGES stage) |
| { |
| #if DEBUG_NEG_REMOVE_ERROR |
| static const GLchar* var_definition_arr = |
| "layout (location = 1 /*, component = COMPONENT */) FLAT DIRECTION TYPE gokuARRAY[1];\n"; |
| static const GLchar* var_definition_one = |
| "layout (location = 1 /*, component = COMPONENT */) FLAT DIRECTION TYPE gokuARRAY;\n"; |
| #else |
| static const GLchar* var_definition_arr = |
| "layout (location = 1, component = COMPONENT) FLAT DIRECTION TYPE gokuARRAY[1];\n"; |
| static const GLchar* var_definition_one = |
| "layout (location = 1, component = COMPONENT) FLAT DIRECTION TYPE gokuARRAY;\n"; |
| #endif /* DEBUG_NEG_REMOVE_ERROR */ |
| static const GLchar* input_use_arr = " if (TYPE(0) == gokuINDEX[0])\n" |
| " {\n" |
| " result += vec4(1, 0.5, 0.25, 0.125);\n" |
| " }\n"; |
| static const GLchar* input_use_one = " if (TYPE(0) == gokuINDEX)\n" |
| " {\n" |
| " result += vec4(1, 0.5, 0.25, 0.125);\n" |
| " }\n"; |
| static const GLchar* output_use_arr = " gokuINDEX[0] = TYPE(0);\n" |
| " if (vec4(0) == result)\n" |
| " {\n" |
| " gokuINDEX[0] = TYPE(1);\n" |
| " }\n"; |
| static const GLchar* output_use_one = " gokuINDEX = TYPE(0);\n" |
| " if (vec4(0) == result)\n" |
| " {\n" |
| " gokuINDEX = TYPE(1);\n" |
| " }\n"; |
| static const GLchar* fs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 gs_fs;\n" |
| "out vec4 fs_out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " fs_out = gs_fs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* fs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 gs_fs;\n" |
| "out vec4 fs_out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = gs_fs;\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " fs_out += result;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* gs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| "in vec4 tes_gs[];\n" |
| "out vec4 gs_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| static const GLchar* gs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 tes_gs[];\n" |
| "out vec4 gs_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = tes_gs[0];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tcs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "in vec4 vs_tcs[];\n" |
| "out vec4 tcs_tes[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| "\n" |
| " tcs_tes[gl_InvocationID] = vs_tcs[gl_InvocationID];\n" |
| "\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tcs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 vs_tcs[];\n" |
| "out vec4 tcs_tes[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = vs_tcs[gl_InvocationID];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " tcs_tes[gl_InvocationID] = result;\n" |
| "\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tes = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(isolines, point_mode) in;\n" |
| "\n" |
| "in vec4 tcs_tes[];\n" |
| "out vec4 tes_gs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " tes_gs = tcs_tes[0];\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tes_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(isolines, point_mode) in;\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 tcs_tes[];\n" |
| "out vec4 tes_gs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = tcs_tes[0];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " tes_gs += result;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 vs_tcs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vs_tcs = in_vs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 vs_tcs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = in_vs;\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " vs_tcs += result;\n" |
| "}\n" |
| "\n"; |
| |
| std::string source; |
| testCase& test_case = m_test_cases[test_case_index]; |
| |
| if (test_case.m_stage == stage) |
| { |
| const GLchar* array = ""; |
| GLchar buffer[16]; |
| const GLchar* var_definition = 0; |
| const GLchar* direction = "in"; |
| const GLchar* index = ""; |
| size_t position = 0; |
| const GLchar* type_name = test_case.m_type.GetGLSLTypeName(); |
| const GLchar* var_use = 0; |
| Utils::Variable::STORAGE storage = Utils::Variable::VARYING_INPUT; |
| const GLchar* flat = ""; |
| |
| if (false == test_case.m_is_input) |
| { |
| direction = "out"; |
| storage = Utils::Variable::VARYING_OUTPUT; |
| |
| if (false == test_case.m_is_array) |
| { |
| var_definition = var_definition_one; |
| var_use = output_use_one; |
| } |
| else |
| { |
| var_definition = var_definition_arr; |
| var_use = output_use_arr; |
| } |
| } |
| else |
| { |
| if (false == test_case.m_is_array) |
| { |
| var_definition = var_definition_one; |
| var_use = Utils::Shader::VERTEX == stage ? input_use_one : "\n"; |
| } |
| else |
| { |
| var_definition = var_definition_arr; |
| var_use = Utils::Shader::VERTEX == stage ? input_use_arr : "\n"; |
| } |
| } |
| |
| if (isFlatRequired(stage, test_case.m_type, storage, true)) |
| { |
| flat = "flat"; |
| } |
| |
| sprintf(buffer, "%d", test_case.m_component); |
| |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs_tested; |
| break; |
| case Utils::Shader::GEOMETRY: |
| source = gs_tested; |
| array = test_case.m_is_input ? "[]" : ""; |
| index = test_case.m_is_input ? "[0]" : ""; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| source = tcs_tested; |
| array = "[]"; |
| index = "[gl_InvocationID]"; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| source = tes_tested; |
| array = test_case.m_is_input ? "[]" : ""; |
| index = test_case.m_is_input ? "[0]" : ""; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs_tested; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| Utils::replaceToken("VAR_DEFINITION", position, var_definition, source); |
| position = 0; |
| Utils::replaceToken("COMPONENT", position, buffer, source); |
| Utils::replaceToken("FLAT", position, flat, source); |
| Utils::replaceToken("DIRECTION", position, direction, source); |
| Utils::replaceToken("ARRAY", position, array, source); |
| Utils::replaceToken("VARIABLE_USE", position, var_use, source); |
| |
| Utils::replaceAllTokens("TYPE", type_name, source); |
| Utils::replaceAllTokens("INDEX", index, source); |
| } |
| else |
| { |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs; |
| break; |
| case Utils::Shader::GEOMETRY: |
| source = gs; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| source = tcs; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| source = tes; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| } |
| |
| return source; |
| } |
| |
| /** Get description of test case |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return Test case description |
| **/ |
| std::string VaryingInvalidValueComponentTest::getTestCaseName(GLuint test_case_index) |
| { |
| std::stringstream stream; |
| testCase& test_case = m_test_cases[test_case_index]; |
| |
| stream << "Stage: " << Utils::Shader::GetStageName(test_case.m_stage) |
| << " type: " << test_case.m_type.GetGLSLTypeName(); |
| |
| if (true == test_case.m_is_array) |
| { |
| stream << "[1]"; |
| } |
| |
| stream << ", direction: "; |
| |
| if (true == test_case.m_is_input) |
| { |
| stream << "input"; |
| } |
| else |
| { |
| stream << "output"; |
| } |
| |
| stream << ", component: " << test_case.m_component; |
| |
| return stream.str(); |
| } |
| |
| /** Get number of test cases |
| * |
| * @return Number of test cases |
| **/ |
| GLuint VaryingInvalidValueComponentTest::getTestCaseNumber() |
| { |
| return static_cast<GLuint>(m_test_cases.size()); |
| } |
| |
| /** Selects if "compute" stage is relevant for test |
| * |
| * @param ignored |
| * |
| * @return false |
| **/ |
| bool VaryingInvalidValueComponentTest::isComputeRelevant(GLuint /* test_case_index */) |
| { |
| return false; |
| } |
| |
| /** Prepare all test cases |
| * |
| **/ |
| void VaryingInvalidValueComponentTest::testInit() |
| { |
| const GLuint n_types = getTypesNumber(); |
| |
| for (GLuint i = 0; i < n_types; ++i) |
| { |
| const Utils::Type& type = getType(i); |
| const std::vector<GLuint>& valid_components = type.GetValidComponents(); |
| |
| if (valid_components.empty()) |
| { |
| continue; |
| } |
| |
| std::vector<GLuint> every_component(4, 0); |
| every_component[1] = 1; |
| every_component[2] = 2; |
| every_component[3] = 3; |
| std::vector<GLuint> invalid_components; |
| |
| std::set_symmetric_difference(every_component.begin(), every_component.end(), valid_components.begin(), |
| valid_components.end(), back_inserter(invalid_components)); |
| |
| for (std::vector<GLuint>::const_iterator it_invalid_components = invalid_components.begin(); |
| it_invalid_components != invalid_components.end(); ++it_invalid_components) |
| { |
| for (GLuint stage = 0; stage < Utils::Shader::STAGE_MAX; ++stage) |
| { |
| if (Utils::Shader::COMPUTE == stage) |
| { |
| continue; |
| } |
| |
| testCase test_case_in_arr = { *it_invalid_components, true, true, (Utils::Shader::STAGES)stage, type }; |
| testCase test_case_in_one = { *it_invalid_components, true, false, (Utils::Shader::STAGES)stage, type }; |
| testCase test_case_out_arr = { *it_invalid_components, false, true, (Utils::Shader::STAGES)stage, |
| type }; |
| testCase test_case_out_one = { *it_invalid_components, false, false, (Utils::Shader::STAGES)stage, |
| type }; |
| |
| m_test_cases.push_back(test_case_in_arr); |
| m_test_cases.push_back(test_case_in_one); |
| |
| if (Utils::Shader::FRAGMENT != stage) |
| { |
| m_test_cases.push_back(test_case_out_arr); |
| m_test_cases.push_back(test_case_out_one); |
| } |
| } |
| } |
| } |
| } |
| |
| /** Constructor |
| * |
| * @param context Test framework context |
| **/ |
| VaryingExceedingComponentsTest::VaryingExceedingComponentsTest(deqp::Context& context) |
| : NegativeTestBase(context, "varying_exceeding_components", |
| "Test verifies that compiler reports error when component qualifier exceeds limits") |
| { |
| } |
| |
| /** Source for given test case and stage |
| * |
| * @param test_case_index Index of test case |
| * @param stage Shader stage |
| * |
| * @return Shader source |
| **/ |
| std::string VaryingExceedingComponentsTest::getShaderSource(GLuint test_case_index, Utils::Shader::STAGES stage) |
| { |
| #if DEBUG_NEG_REMOVE_ERROR |
| static const GLchar* var_definition_arr = |
| "layout (location = 1 /*, component = 4 */) FLAT DIRECTION TYPE gokuARRAY[1];\n"; |
| static const GLchar* var_definition_one = |
| "layout (location = 1 /*, component = 4 */) FLAT DIRECTION TYPE gokuARRAY;\n"; |
| #else |
| static const GLchar* var_definition_arr = |
| "layout (location = 1, component = 4) FLAT DIRECTION TYPE gokuARRAY[1];\n"; |
| static const GLchar* var_definition_one = "layout (location = 1, component = 4) FLAT DIRECTION TYPE gokuARRAY;\n"; |
| #endif /* DEBUG_NEG_REMOVE_ERROR */ |
| static const GLchar* input_use_arr = " if (TYPE(0) == gokuINDEX[0])\n" |
| " {\n" |
| " result += vec4(1, 0.5, 0.25, 0.125);\n" |
| " }\n"; |
| static const GLchar* input_use_one = " if (TYPE(0) == gokuINDEX)\n" |
| " {\n" |
| " result += vec4(1, 0.5, 0.25, 0.125);\n" |
| " }\n"; |
| static const GLchar* output_use_arr = " gokuINDEX[0] = TYPE(0);\n" |
| " if (vec4(0) == result)\n" |
| " {\n" |
| " gokuINDEX[0] = TYPE(1);\n" |
| " }\n"; |
| static const GLchar* output_use_one = " gokuINDEX = TYPE(0);\n" |
| " if (vec4(0) == result)\n" |
| " {\n" |
| " gokuINDEX = TYPE(1);\n" |
| " }\n"; |
| static const GLchar* fs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 gs_fs;\n" |
| "out vec4 fs_out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " fs_out = gs_fs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* fs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 gs_fs;\n" |
| "out vec4 fs_out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = gs_fs;\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " fs_out += result;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* gs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| "in vec4 tes_gs[];\n" |
| "out vec4 gs_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| static const GLchar* gs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 tes_gs[];\n" |
| "out vec4 gs_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = tes_gs[0];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tcs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "in vec4 vs_tcs[];\n" |
| "out vec4 tcs_tes[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| "\n" |
| " tcs_tes[gl_InvocationID] = vs_tcs[gl_InvocationID];\n" |
| "\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tcs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 vs_tcs[];\n" |
| "out vec4 tcs_tes[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = vs_tcs[gl_InvocationID];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " tcs_tes[gl_InvocationID] = result;\n" |
| "\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tes = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(isolines, point_mode) in;\n" |
| "\n" |
| "in vec4 tcs_tes[];\n" |
| "out vec4 tes_gs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " tes_gs = tcs_tes[0];\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tes_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(isolines, point_mode) in;\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 tcs_tes[];\n" |
| "out vec4 tes_gs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = tcs_tes[0];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " tes_gs += result;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 vs_tcs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vs_tcs = in_vs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 vs_tcs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = in_vs;\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " vs_tcs += result;\n" |
| "}\n" |
| "\n"; |
| |
| std::string source; |
| testCase& test_case = m_test_cases[test_case_index]; |
| |
| if (test_case.m_stage == stage) |
| { |
| const GLchar* array = ""; |
| const GLchar* var_definition = 0; |
| const GLchar* direction = "in"; |
| const GLchar* index = ""; |
| size_t position = 0; |
| const GLchar* type_name = test_case.m_type.GetGLSLTypeName(); |
| const GLchar* var_use = 0; |
| Utils::Variable::STORAGE storage = Utils::Variable::VARYING_INPUT; |
| const GLchar* flat = ""; |
| |
| if (false == test_case.m_is_input) |
| { |
| direction = "out"; |
| storage = Utils::Variable::VARYING_OUTPUT; |
| |
| if (false == test_case.m_is_array) |
| { |
| var_definition = var_definition_one; |
| var_use = output_use_one; |
| } |
| else |
| { |
| var_definition = var_definition_arr; |
| var_use = output_use_arr; |
| } |
| } |
| else |
| { |
| if (false == test_case.m_is_array) |
| { |
| var_definition = var_definition_one; |
| var_use = Utils::Shader::VERTEX == stage ? input_use_one : "\n"; |
| } |
| else |
| { |
| var_definition = var_definition_arr; |
| var_use = Utils::Shader::VERTEX == stage ? input_use_arr : "\n"; |
| } |
| } |
| |
| if (isFlatRequired(stage, test_case.m_type, storage, true)) |
| { |
| flat = "flat"; |
| } |
| |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs_tested; |
| break; |
| case Utils::Shader::GEOMETRY: |
| source = gs_tested; |
| array = test_case.m_is_input ? "[]" : ""; |
| index = test_case.m_is_input ? "[0]" : ""; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| source = tcs_tested; |
| array = "[]"; |
| index = "[gl_InvocationID]"; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| source = tes_tested; |
| array = test_case.m_is_input ? "[]" : ""; |
| index = test_case.m_is_input ? "[0]" : ""; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs_tested; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| Utils::replaceToken("VAR_DEFINITION", position, var_definition, source); |
| position = 0; |
| Utils::replaceToken("FLAT", position, flat, source); |
| Utils::replaceToken("DIRECTION", position, direction, source); |
| Utils::replaceToken("ARRAY", position, array, source); |
| Utils::replaceToken("VARIABLE_USE", position, var_use, source); |
| |
| Utils::replaceAllTokens("TYPE", type_name, source); |
| Utils::replaceAllTokens("INDEX", index, source); |
| } |
| else |
| { |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs; |
| break; |
| case Utils::Shader::GEOMETRY: |
| source = gs; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| source = tcs; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| source = tes; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| } |
| |
| return source; |
| } |
| |
| /** Get description of test case |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return Test case description |
| **/ |
| std::string VaryingExceedingComponentsTest::getTestCaseName(GLuint test_case_index) |
| { |
| std::stringstream stream; |
| testCase& test_case = m_test_cases[test_case_index]; |
| |
| stream << "Stage: " << Utils::Shader::GetStageName(test_case.m_stage) |
| << " type: " << test_case.m_type.GetGLSLTypeName(); |
| |
| if (true == test_case.m_is_array) |
| { |
| stream << "[1]"; |
| } |
| |
| stream << ", direction: "; |
| |
| if (true == test_case.m_is_input) |
| { |
| stream << "input"; |
| } |
| else |
| { |
| stream << "output"; |
| } |
| |
| return stream.str(); |
| } |
| |
| /** Get number of test cases |
| * |
| * @return Number of test cases |
| **/ |
| GLuint VaryingExceedingComponentsTest::getTestCaseNumber() |
| { |
| return static_cast<GLuint>(m_test_cases.size()); |
| } |
| |
| /** Selects if "compute" stage is relevant for test |
| * |
| * @param ignored |
| * |
| * @return false |
| **/ |
| bool VaryingExceedingComponentsTest::isComputeRelevant(GLuint /* test_case_index */) |
| { |
| return false; |
| } |
| |
| /** Prepare all test cases |
| * |
| **/ |
| void VaryingExceedingComponentsTest::testInit() |
| { |
| const GLuint n_types = getTypesNumber(); |
| |
| for (GLuint i = 0; i < n_types; ++i) |
| { |
| const Utils::Type& type = getType(i); |
| const std::vector<GLuint>& valid_components = type.GetValidComponents(); |
| |
| if (valid_components.empty()) |
| { |
| continue; |
| } |
| |
| for (GLuint stage = 0; stage < Utils::Shader::STAGE_MAX; ++stage) |
| { |
| if (Utils::Shader::COMPUTE == stage) |
| { |
| continue; |
| } |
| |
| testCase test_case_in_arr = { true, true, (Utils::Shader::STAGES)stage, type }; |
| testCase test_case_in_one = { true, false, (Utils::Shader::STAGES)stage, type }; |
| testCase test_case_out_arr = { false, true, (Utils::Shader::STAGES)stage, type }; |
| testCase test_case_out_one = { false, false, (Utils::Shader::STAGES)stage, type }; |
| |
| m_test_cases.push_back(test_case_in_arr); |
| m_test_cases.push_back(test_case_in_one); |
| |
| if (Utils::Shader::FRAGMENT != stage) |
| { |
| m_test_cases.push_back(test_case_out_arr); |
| m_test_cases.push_back(test_case_out_one); |
| } |
| } |
| } |
| } |
| |
| /** Constructor |
| * |
| * @param context Test framework context |
| **/ |
| VaryingComponentWithoutLocationTest::VaryingComponentWithoutLocationTest(deqp::Context& context) |
| : NegativeTestBase(context, "varying_component_without_location", |
| "Test verifies that compiler reports error when component qualifier is used without location") |
| { |
| } |
| |
| /** Source for given test case and stage |
| * |
| * @param test_case_index Index of test case |
| * @param stage Shader stage |
| * |
| * @return Shader source |
| **/ |
| std::string VaryingComponentWithoutLocationTest::getShaderSource(GLuint test_case_index, Utils::Shader::STAGES stage) |
| { |
| #if DEBUG_NEG_REMOVE_ERROR |
| static const GLchar* var_definition = "/* layout (component = COMPONENT) */ FLAT DIRECTION TYPE gokuARRAY;\n"; |
| #else |
| static const GLchar* var_definition = "layout (component = COMPONENT) FLAT DIRECTION TYPE gokuARRAY;\n"; |
| #endif /* DEBUG_NEG_REMOVE_ERROR */ |
| static const GLchar* input_use = " if (TYPE(0) == gokuINDEX)\n" |
| " {\n" |
| " result += vec4(1, 0.5, 0.25, 0.125);\n" |
| " }\n"; |
| static const GLchar* output_use = " gokuINDEX = TYPE(0);\n" |
| " if (vec4(0) == result)\n" |
| " {\n" |
| " gokuINDEX = TYPE(1);\n" |
| " }\n"; |
| static const GLchar* fs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 gs_fs;\n" |
| "out vec4 fs_out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " fs_out = gs_fs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* fs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 gs_fs;\n" |
| "out vec4 fs_out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = gs_fs;\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " fs_out = result;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* gs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| "in vec4 tes_gs[];\n" |
| "out vec4 gs_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| static const GLchar* gs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 tes_gs[];\n" |
| "out vec4 gs_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = tes_gs[0];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tcs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "in vec4 vs_tcs[];\n" |
| "out vec4 tcs_tes[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| "\n" |
| " tcs_tes[gl_InvocationID] = vs_tcs[gl_InvocationID];\n" |
| "\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tcs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 vs_tcs[];\n" |
| "out vec4 tcs_tes[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = vs_tcs[gl_InvocationID];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " tcs_tes[gl_InvocationID] = result;\n" |
| "\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tes = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(isolines, point_mode) in;\n" |
| "\n" |
| "in vec4 tcs_tes[];\n" |
| "out vec4 tes_gs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " tes_gs = tcs_tes[0];\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tes_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(isolines, point_mode) in;\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 tcs_tes[];\n" |
| "out vec4 tes_gs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = tcs_tes[0];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " tes_gs = result;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 vs_tcs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vs_tcs = in_vs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 vs_tcs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = in_vs;\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " vs_tcs = result;\n" |
| "}\n" |
| "\n"; |
| |
| std::string source; |
| testCase& test_case = m_test_cases[test_case_index]; |
| |
| if (test_case.m_stage == stage) |
| { |
| const GLchar* array = ""; |
| GLchar buffer[16]; |
| const GLchar* direction = "in"; |
| const GLchar* index = ""; |
| size_t position = 0; |
| const GLchar* type_name = test_case.m_type.GetGLSLTypeName(); |
| const GLchar* var_use = Utils::Shader::VERTEX == stage ? input_use : "\n"; |
| Utils::Variable::STORAGE storage = Utils::Variable::VARYING_INPUT; |
| const GLchar* flat = ""; |
| |
| if (false == test_case.m_is_input) |
| { |
| direction = "out"; |
| storage = Utils::Variable::VARYING_OUTPUT; |
| var_use = output_use; |
| } |
| |
| if (isFlatRequired(stage, test_case.m_type, storage, true)) |
| { |
| flat = "flat"; |
| } |
| |
| sprintf(buffer, "%d", test_case.m_component); |
| |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs_tested; |
| break; |
| case Utils::Shader::GEOMETRY: |
| source = gs_tested; |
| array = test_case.m_is_input ? "[]" : ""; |
| index = test_case.m_is_input ? "[0]" : ""; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| source = tcs_tested; |
| array = "[]"; |
| index = "[gl_InvocationID]"; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| source = tes_tested; |
| array = test_case.m_is_input ? "[]" : ""; |
| index = test_case.m_is_input ? "[0]" : ""; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs_tested; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| Utils::replaceToken("VAR_DEFINITION", position, var_definition, source); |
| position = 0; |
| Utils::replaceToken("COMPONENT", position, buffer, source); |
| Utils::replaceToken("FLAT", position, flat, source); |
| Utils::replaceToken("DIRECTION", position, direction, source); |
| Utils::replaceToken("ARRAY", position, array, source); |
| Utils::replaceToken("VARIABLE_USE", position, var_use, source); |
| |
| Utils::replaceAllTokens("TYPE", type_name, source); |
| Utils::replaceAllTokens("INDEX", index, source); |
| } |
| else |
| { |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs; |
| break; |
| case Utils::Shader::GEOMETRY: |
| source = gs; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| source = tcs; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| source = tes; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| } |
| |
| return source; |
| } |
| |
| /** Get description of test case |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return Test case description |
| **/ |
| std::string VaryingComponentWithoutLocationTest::getTestCaseName(GLuint test_case_index) |
| { |
| std::stringstream stream; |
| testCase& test_case = m_test_cases[test_case_index]; |
| |
| stream << "Stage: " << Utils::Shader::GetStageName(test_case.m_stage) |
| << " type: " << test_case.m_type.GetGLSLTypeName() << ", direction: "; |
| |
| if (true == test_case.m_is_input) |
| { |
| stream << "input"; |
| } |
| else |
| { |
| stream << "output"; |
| } |
| |
| stream << ", component: " << test_case.m_component; |
| |
| return stream.str(); |
| } |
| |
| /** Get number of test cases |
| * |
| * @return Number of test cases |
| **/ |
| GLuint VaryingComponentWithoutLocationTest::getTestCaseNumber() |
| { |
| return static_cast<GLuint>(m_test_cases.size()); |
| } |
| |
| /** Selects if "compute" stage is relevant for test |
| * |
| * @param ignored |
| * |
| * @return false |
| **/ |
| bool VaryingComponentWithoutLocationTest::isComputeRelevant(GLuint /* test_case_index */) |
| { |
| return false; |
| } |
| |
| /** Prepare all test cases |
| * |
| **/ |
| void VaryingComponentWithoutLocationTest::testInit() |
| { |
| const GLuint n_types = getTypesNumber(); |
| |
| for (GLuint i = 0; i < n_types; ++i) |
| { |
| const Utils::Type& type = getType(i); |
| const std::vector<GLuint>& valid_components = type.GetValidComponents(); |
| |
| if (valid_components.empty()) |
| { |
| continue; |
| } |
| |
| for (GLuint stage = 0; stage < Utils::Shader::STAGE_MAX; ++stage) |
| { |
| if (Utils::Shader::COMPUTE == stage) |
| { |
| continue; |
| } |
| |
| testCase test_case_in = { valid_components.back(), true, (Utils::Shader::STAGES)stage, type }; |
| testCase test_case_out = { valid_components.back(), false, (Utils::Shader::STAGES)stage, type }; |
| |
| m_test_cases.push_back(test_case_in); |
| |
| if (Utils::Shader::FRAGMENT != stage) |
| { |
| m_test_cases.push_back(test_case_out); |
| } |
| } |
| } |
| } |
| |
| /** Constructor |
| * |
| * @param context Test framework context |
| **/ |
| VaryingComponentOfInvalidTypeTest::VaryingComponentOfInvalidTypeTest(deqp::Context& context) |
| : NegativeTestBase(context, "varying_component_of_invalid_type", |
| "Test verifies that compiler reports error when component qualifier is used for invalid type") |
| { |
| } |
| |
| /** Source for given test case and stage |
| * |
| * @param test_case_index Index of test case |
| * @param stage Shader stage |
| * |
| * @return Shader source |
| **/ |
| std::string VaryingComponentOfInvalidTypeTest::getShaderSource(GLuint test_case_index, Utils::Shader::STAGES stage) |
| { |
| static const GLchar* block_definition_arr = "layout (location = 1COMPONENT) DIRECTION Goku {\n" |
| " FLAT TYPE member;\n" |
| "} gokuARRAY[1];\n"; |
| static const GLchar* block_definition_one = "layout (location = 1COMPONENT) DIRECTION Goku {\n" |
| " FLAT TYPE member;\n" |
| "} gokuARRAY;\n"; |
| static const GLchar* matrix_dvec3_dvec4_definition_arr = |
| "layout (location = 1COMPONENT) FLAT DIRECTION TYPE gokuARRAY[1];\n"; |
| static const GLchar* matrix_dvec3_dvec4_definition_one = |
| "layout (location = 1COMPONENT) FLAT DIRECTION TYPE gokuARRAY;\n"; |
| static const GLchar* struct_definition_arr = "struct Goku {\n" |
| " TYPE member;\n" |
| "};\n" |
| "\n" |
| "layout (location = 1COMPONENT) FLAT DIRECTION Goku gokuARRAY[1];\n"; |
| static const GLchar* struct_definition_one = "struct Goku {\n" |
| " TYPE member;\n" |
| "};\n" |
| "\n" |
| "layout (location = 1COMPONENT) FLAT DIRECTION Goku gokuARRAY;\n"; |
| static const GLchar* matrix_dvec3_dvec4_input_use_arr = " if (TYPE(0) == gokuINDEX[0])\n" |
| " {\n" |
| " result += vec4(1, 0.5, 0.25, 0.125);\n" |
| " }\n"; |
| static const GLchar* matrix_dvec3_dvec4_input_use_one = " if (TYPE(0) == gokuINDEX)\n" |
| " {\n" |
| " result += vec4(1, 0.5, 0.25, 0.125);\n" |
| " }\n"; |
| static const GLchar* matrix_dvec3_dvec4_output_use_arr = " gokuINDEX[0] = TYPE(0);\n" |
| " if (vec4(0) == result)\n" |
| " {\n" |
| " gokuINDEX[0] = TYPE(1);\n" |
| " }\n"; |
| static const GLchar* matrix_dvec3_dvec4_output_use_one = " gokuINDEX = TYPE(0);\n" |
| " if (vec4(0) == result)\n" |
| " {\n" |
| " gokuINDEX = TYPE(1);\n" |
| " }\n"; |
| static const GLchar* member_input_use_arr = " if (TYPE(0) == gokuINDEX[0].member)\n" |
| " {\n" |
| " result += vec4(1, 0.5, 0.25, 0.125);\n" |
| " }\n"; |
| static const GLchar* member_input_use_one = " if (TYPE(0) == gokuINDEX.member)\n" |
| " {\n" |
| " result += vec4(1, 0.5, 0.25, 0.125);\n" |
| " }\n"; |
| static const GLchar* member_output_use_arr = " gokuINDEX[0].member = TYPE(0);\n" |
| " if (vec4(0) == result)\n" |
| " {\n" |
| " gokuINDEX[0].member = TYPE(1);\n" |
| " }\n"; |
| static const GLchar* member_output_use_one = " gokuINDEX.member = TYPE(0);\n" |
| " if (vec4(0) == result)\n" |
| " {\n" |
| " gokuINDEX.member = TYPE(1);\n" |
| " }\n"; |
| static const GLchar* fs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 gs_fs;\n" |
| "out vec4 fs_out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " fs_out = gs_fs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* fs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 gs_fs;\n" |
| "out vec4 fs_out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = gs_fs;\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " fs_out += result;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* gs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| "in vec4 tes_gs[];\n" |
| "out vec4 gs_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| static const GLchar* gs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 tes_gs[];\n" |
| "out vec4 gs_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = tes_gs[0];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tcs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "in vec4 vs_tcs[];\n" |
| "out vec4 tcs_tes[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| "\n" |
| " tcs_tes[gl_InvocationID] = vs_tcs[gl_InvocationID];\n" |
| "\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tcs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 vs_tcs[];\n" |
| "out vec4 tcs_tes[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = vs_tcs[gl_InvocationID];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " tcs_tes[gl_InvocationID] = result;\n" |
| "\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tes = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(isolines, point_mode) in;\n" |
| "\n" |
| "in vec4 tcs_tes[];\n" |
| "out vec4 tes_gs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " tes_gs = tcs_tes[0];\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tes_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(isolines, point_mode) in;\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 tcs_tes[];\n" |
| "out vec4 tes_gs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = tcs_tes[0];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " tes_gs += result;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 vs_tcs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vs_tcs = in_vs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 vs_tcs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = in_vs;\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " vs_tcs += result;\n" |
| "}\n" |
| "\n"; |
| |
| std::string source; |
| testCase& test_case = m_test_cases[test_case_index]; |
| |
| if (test_case.m_stage == stage) |
| { |
| const GLchar* array = ""; |
| GLchar buffer[32]; |
| const GLchar* var_definition = 0; |
| const GLchar* direction = "in "; |
| const GLchar* index = ""; |
| size_t position = 0; |
| const GLchar* type_name = test_case.m_type.GetGLSLTypeName(); |
| const GLchar* var_use = 0; |
| Utils::Variable::STORAGE storage = Utils::Variable::VARYING_INPUT; |
| const GLchar* flat = ""; |
| |
| if (false == test_case.m_is_input) |
| { |
| direction = "out"; |
| storage = Utils::Variable::VARYING_OUTPUT; |
| |
| if (false == test_case.m_is_array) |
| { |
| switch (test_case.m_case) |
| { |
| case BLOCK: |
| var_definition = block_definition_one; |
| var_use = member_output_use_one; |
| break; |
| case MATRIX: |
| case DVEC3_DVEC4: |
| var_definition = matrix_dvec3_dvec4_definition_one; |
| var_use = matrix_dvec3_dvec4_output_use_one; |
| break; |
| case STRUCT: |
| var_definition = struct_definition_one; |
| var_use = member_output_use_one; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| } |
| else |
| { |
| switch (test_case.m_case) |
| { |
| case BLOCK: |
| var_definition = block_definition_arr; |
| var_use = member_output_use_arr; |
| break; |
| case MATRIX: |
| case DVEC3_DVEC4: |
| var_definition = matrix_dvec3_dvec4_definition_arr; |
| var_use = matrix_dvec3_dvec4_output_use_arr; |
| break; |
| case STRUCT: |
| var_definition = struct_definition_arr; |
| var_use = member_output_use_arr; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| } |
| } |
| else |
| { |
| if (false == test_case.m_is_array) |
| { |
| switch (test_case.m_case) |
| { |
| case BLOCK: |
| var_definition = block_definition_one; |
| var_use = Utils::Shader::VERTEX == stage ? member_input_use_one : "\n"; |
| break; |
| case MATRIX: |
| case DVEC3_DVEC4: |
| var_definition = matrix_dvec3_dvec4_definition_one; |
| var_use = Utils::Shader::VERTEX == stage ? matrix_dvec3_dvec4_input_use_one : "\n"; |
| break; |
| case STRUCT: |
| var_definition = struct_definition_one; |
| var_use = Utils::Shader::VERTEX == stage ? member_input_use_one : "\n"; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| } |
| else |
| { |
| switch (test_case.m_case) |
| { |
| case BLOCK: |
| var_definition = block_definition_arr; |
| var_use = Utils::Shader::VERTEX == stage ? member_input_use_arr : "\n"; |
| break; |
| case MATRIX: |
| case DVEC3_DVEC4: |
| var_definition = matrix_dvec3_dvec4_definition_arr; |
| var_use = Utils::Shader::VERTEX == stage ? matrix_dvec3_dvec4_input_use_arr : "\n"; |
| break; |
| case STRUCT: |
| var_definition = struct_definition_arr; |
| var_use = Utils::Shader::VERTEX == stage ? member_input_use_arr : "\n"; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| } |
| } |
| |
| if (isFlatRequired(stage, test_case.m_type, storage)) |
| { |
| flat = "flat"; |
| } |
| |
| #if DEBUG_NEG_REMOVE_ERROR |
| sprintf(buffer, " /* , component = %d */", test_case.m_component); |
| #else |
| sprintf(buffer, ", component = %d", test_case.m_component); |
| #endif /* DEBUG_NEG_REMOVE_ERROR */ |
| |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs_tested; |
| break; |
| case Utils::Shader::GEOMETRY: |
| source = gs_tested; |
| array = test_case.m_is_input ? "[]" : ""; |
| index = test_case.m_is_input ? "[0]" : ""; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| source = tcs_tested; |
| array = "[]"; |
| index = "[gl_InvocationID]"; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| source = tes_tested; |
| array = test_case.m_is_input ? "[]" : ""; |
| index = test_case.m_is_input ? "[0]" : ""; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs_tested; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| Utils::replaceToken("VAR_DEFINITION", position, var_definition, source); |
| position = 0; |
| Utils::replaceToken("COMPONENT", position, buffer, source); |
| Utils::replaceToken("DIRECTION", position, direction, source); |
| Utils::replaceToken("ARRAY", position, array, source); |
| Utils::replaceToken("VARIABLE_USE", position, var_use, source); |
| |
| Utils::replaceAllTokens("FLAT", flat, source); |
| Utils::replaceAllTokens("TYPE", type_name, source); |
| Utils::replaceAllTokens("INDEX", index, source); |
| } |
| else |
| { |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs; |
| break; |
| case Utils::Shader::GEOMETRY: |
| source = gs; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| source = tcs; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| source = tes; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| } |
| |
| return source; |
| } |
| |
| /** Get description of test case |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return Test case description |
| **/ |
| std::string VaryingComponentOfInvalidTypeTest::getTestCaseName(GLuint test_case_index) |
| { |
| std::stringstream stream; |
| testCase& test_case = m_test_cases[test_case_index]; |
| |
| stream << "Stage: " << Utils::Shader::GetStageName(test_case.m_stage) |
| << " type: " << test_case.m_type.GetGLSLTypeName(); |
| |
| if (true == test_case.m_is_array) |
| { |
| stream << "[1]"; |
| } |
| |
| stream << ", direction: "; |
| |
| if (true == test_case.m_is_input) |
| { |
| stream << "input"; |
| } |
| else |
| { |
| stream << "output"; |
| } |
| |
| stream << ", component: " << test_case.m_component; |
| |
| return stream.str(); |
| } |
| |
| /** Get number of test cases |
| * |
| * @return Number of test cases |
| **/ |
| GLuint VaryingComponentOfInvalidTypeTest::getTestCaseNumber() |
| { |
| return static_cast<GLuint>(m_test_cases.size()); |
| } |
| |
| /** Selects if "compute" stage is relevant for test |
| * |
| * @param ignored |
| * |
| * @return false |
| **/ |
| bool VaryingComponentOfInvalidTypeTest::isComputeRelevant(GLuint /* test_case_index */) |
| { |
| return false; |
| } |
| |
| /** Prepare all test cases |
| * |
| **/ |
| void VaryingComponentOfInvalidTypeTest::testInit() |
| { |
| const GLuint n_types = getTypesNumber(); |
| |
| for (GLuint i = 0; i < n_types; ++i) |
| { |
| const Utils::Type& type = getType(i); |
| const std::vector<GLuint>& valid_components = type.GetValidComponents(); |
| |
| for (GLuint stage = 0; stage < Utils::Shader::STAGE_MAX; ++stage) |
| { |
| if (Utils::Shader::COMPUTE == stage) |
| { |
| continue; |
| } |
| |
| /* matrices */ |
| if (1 != type.m_n_columns) |
| { |
| testCase test_case_in_arr = { MATRIX, 0, true, true, (Utils::Shader::STAGES)stage, type }; |
| testCase test_case_in_one = { MATRIX, 0, false, true, (Utils::Shader::STAGES)stage, type }; |
| testCase test_case_out_arr = { MATRIX, 0, true, false, (Utils::Shader::STAGES)stage, type }; |
| testCase test_case_out_one = { MATRIX, 0, false, false, (Utils::Shader::STAGES)stage, type }; |
| |
| m_test_cases.push_back(test_case_in_arr); |
| m_test_cases.push_back(test_case_in_one); |
| |
| if (Utils::Shader::FRAGMENT != stage) |
| { |
| m_test_cases.push_back(test_case_out_arr); |
| m_test_cases.push_back(test_case_out_one); |
| } |
| } |
| else if (Utils::Type::Double == type.m_basic_type && 2 < type.m_n_rows) /* dvec3 and dvec4 */ |
| { |
| testCase test_case_in_arr = { DVEC3_DVEC4, 0, true, true, (Utils::Shader::STAGES)stage, type }; |
| testCase test_case_in_one = { DVEC3_DVEC4, 0, false, true, (Utils::Shader::STAGES)stage, type }; |
| testCase test_case_out_arr = { DVEC3_DVEC4, 0, true, false, (Utils::Shader::STAGES)stage, type }; |
| testCase test_case_out_one = { DVEC3_DVEC4, 0, false, false, (Utils::Shader::STAGES)stage, type }; |
| |
| m_test_cases.push_back(test_case_in_arr); |
| m_test_cases.push_back(test_case_in_one); |
| |
| if (Utils::Shader::FRAGMENT != stage) |
| { |
| m_test_cases.push_back(test_case_out_arr); |
| m_test_cases.push_back(test_case_out_one); |
| } |
| } |
| else |
| { |
| if (valid_components.empty()) |
| { |
| TCU_FAIL("Unhandled type"); |
| } |
| |
| for (GLuint c = BLOCK; c < MAX_CASES; ++c) |
| { |
| testCase test_case_in_arr = { (CASES)c, valid_components.back(), true, |
| true, (Utils::Shader::STAGES)stage, type }; |
| testCase test_case_in_one = { (CASES)c, valid_components.back(), false, |
| true, (Utils::Shader::STAGES)stage, type }; |
| testCase test_case_out_arr = { (CASES)c, valid_components.back(), true, |
| false, (Utils::Shader::STAGES)stage, type }; |
| testCase test_case_out_one = { (CASES)c, valid_components.back(), false, |
| false, (Utils::Shader::STAGES)stage, type }; |
| |
| if (Utils::Shader::VERTEX != stage) |
| { |
| m_test_cases.push_back(test_case_in_arr); |
| m_test_cases.push_back(test_case_in_one); |
| } |
| |
| if (Utils::Shader::FRAGMENT != stage) |
| { |
| m_test_cases.push_back(test_case_out_arr); |
| m_test_cases.push_back(test_case_out_one); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| /** Constructor |
| * |
| * @param context Test framework context |
| **/ |
| InputComponentAliasingTest::InputComponentAliasingTest(deqp::Context& context) |
| : NegativeTestBase(context, "input_component_aliasing", |
| "Test verifies that compiler reports component aliasing as error") |
| { |
| } |
| |
| /** Source for given test case and stage |
| * |
| * @param test_case_index Index of test case |
| * @param stage Shader stage |
| * |
| * @return Shader source |
| **/ |
| std::string InputComponentAliasingTest::getShaderSource(GLuint test_case_index, Utils::Shader::STAGES stage) |
| { |
| static const GLchar* var_definition = |
| "layout (location = 1, component = COMPONENT) FLAT in TYPE gohanARRAY;\n" |
| #if DEBUG_NEG_REMOVE_ERROR |
| "/* layout (location = 1, component = COMPONENT) */ FLAT in TYPE gotenARRAY;\n"; |
| #else |
| "layout (location = 1, component = COMPONENT) FLAT in TYPE gotenARRAY;\n"; |
| #endif /* DEBUG_NEG_REMOVE_ERROR */ |
| static const GLchar* test_one = " if (TYPE(0) == gohanINDEX)\n" |
| " {\n" |
| " result += vec4(1, 0.5, 0.25, 0.125);\n" |
| " }\n"; |
| static const GLchar* fs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 gs_fs;\n" |
| "out vec4 fs_out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " fs_out = gs_fs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* fs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 gs_fs;\n" |
| "out vec4 fs_out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = gs_fs;\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " fs_out += result;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* gs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| "layout (location = 1, component = COMPONENT) FLAT out TYPE gohan;\n" |
| "\n" |
| "in vec4 tes_gs[];\n" |
| "out vec4 gs_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " gohan = TYPE(1);\n" |
| "\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| static const GLchar* gs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 tes_gs[];\n" |
| "out vec4 gs_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = tes_gs[0];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tcs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "layout (location = 1, component = COMPONENT) FLAT out TYPE gohan[];\n" |
| "\n" |
| "in vec4 vs_tcs[];\n" |
| "out vec4 tcs_tes[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " gohan[gl_InvocationID] = TYPE(1);\n" |
| "\n" |
| " tcs_tes[gl_InvocationID] = vs_tcs[gl_InvocationID];\n" |
| "\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tcs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 vs_tcs[];\n" |
| "out vec4 tcs_tes[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = vs_tcs[gl_InvocationID];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " tcs_tes[gl_InvocationID] = result;\n" |
| "\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tes = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(isolines, point_mode) in;\n" |
| "\n" |
| "layout (location = 1, component = COMPONENT) FLAT out TYPE gohan;\n" |
| "\n" |
| "in vec4 tcs_tes[];\n" |
| "out vec4 tes_gs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " gohan = TYPE(1);\n" |
| "\n" |
| " tes_gs = tcs_tes[0];\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tes_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(isolines, point_mode) in;\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 tcs_tes[];\n" |
| "out vec4 tes_gs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = tcs_tes[0];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " tes_gs += result;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout (location = 1, component = COMPONENT) FLAT out TYPE gohan;\n" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 vs_tcs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " gohan = TYPE(1);\n" |
| "\n" |
| " vs_tcs = in_vs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 vs_tcs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = in_vs;\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " vs_tcs += result;\n" |
| "}\n" |
| "\n"; |
| |
| std::string source; |
| testCase& test_case = m_test_cases[test_case_index]; |
| GLchar buffer_gohan[16]; |
| const GLchar* type_name = test_case.m_type.GetGLSLTypeName(); |
| |
| sprintf(buffer_gohan, "%d", test_case.m_component_gohan); |
| |
| if (test_case.m_stage == stage) |
| { |
| const GLchar* array = ""; |
| GLchar buffer_goten[16]; |
| const GLchar* flat = ""; |
| const GLchar* index = ""; |
| size_t position = 0; |
| const GLchar* var_use = test_one; |
| |
| if (isFlatRequired(stage, test_case.m_type, Utils::Variable::VARYING_INPUT, true)) |
| { |
| flat = "flat"; |
| } |
| |
| sprintf(buffer_goten, "%d", test_case.m_component_goten); |
| |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs_tested; |
| break; |
| case Utils::Shader::GEOMETRY: |
| source = gs_tested; |
| array = "[]"; |
| index = "[0]"; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| source = tcs_tested; |
| array = "[]"; |
| index = "[gl_InvocationID]"; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| source = tes_tested; |
| array = "[]"; |
| index = "[0]"; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs_tested; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| Utils::replaceToken("VAR_DEFINITION", position, var_definition, source); |
| position = 0; |
| Utils::replaceToken("COMPONENT", position, buffer_gohan, source); |
| Utils::replaceToken("ARRAY", position, array, source); |
| Utils::replaceToken("COMPONENT", position, buffer_goten, source); |
| Utils::replaceToken("ARRAY", position, array, source); |
| Utils::replaceToken("VARIABLE_USE", position, var_use, source); |
| |
| Utils::replaceAllTokens("FLAT", flat, source); |
| Utils::replaceAllTokens("TYPE", type_name, source); |
| Utils::replaceAllTokens("INDEX", index, source); |
| } |
| else |
| { |
| const GLchar* flat = ""; |
| |
| if (isFlatRequired(stage, test_case.m_type, Utils::Variable::VARYING_OUTPUT, true)) |
| { |
| flat = "flat"; |
| } |
| |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs; |
| break; |
| case Utils::Shader::GEOMETRY: |
| source = gs; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| source = tcs; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| source = tes; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| Utils::replaceAllTokens("FLAT", flat, source); |
| Utils::replaceAllTokens("COMPONENT", buffer_gohan, source); |
| Utils::replaceAllTokens("TYPE", type_name, source); |
| } |
| |
| return source; |
| } |
| |
| /** Get description of test case |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return Test case description |
| **/ |
| std::string InputComponentAliasingTest::getTestCaseName(GLuint test_case_index) |
| { |
| std::stringstream stream; |
| testCase& test_case = m_test_cases[test_case_index]; |
| |
| stream << "Stage: " << Utils::Shader::GetStageName(test_case.m_stage) |
| << " type: " << test_case.m_type.GetGLSLTypeName() << ", components: " << test_case.m_component_gohan |
| << " & " << test_case.m_component_goten; |
| |
| return stream.str(); |
| } |
| |
| /** Get number of test cases |
| * |
| * @return Number of test cases |
| **/ |
| GLuint InputComponentAliasingTest::getTestCaseNumber() |
| { |
| return static_cast<GLuint>(m_test_cases.size()); |
| } |
| |
| /** Selects if "compute" stage is relevant for test |
| * |
| * @param ignored |
| * |
| * @return false |
| **/ |
| bool InputComponentAliasingTest::isComputeRelevant(GLuint /* test_case_index */) |
| { |
| return false; |
| } |
| |
| /** Selects if compilation failure is expected result |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return false for VS that use only single variable, true otherwise |
| **/ |
| bool InputComponentAliasingTest::isFailureExpected(GLuint test_case_index) |
| { |
| testCase& test_case = m_test_cases[test_case_index]; |
| |
| return (Utils::Shader::VERTEX != test_case.m_stage); |
| } |
| |
| /** Prepare all test cases |
| * |
| **/ |
| void InputComponentAliasingTest::testInit() |
| { |
| const GLuint n_types = getTypesNumber(); |
| |
| for (GLuint i = 0; i < n_types; ++i) |
| { |
| const Utils::Type& type = getType(i); |
| const std::vector<GLuint>& valid_components = type.GetValidComponents(); |
| |
| if (valid_components.empty()) |
| { |
| continue; |
| } |
| |
| for (std::vector<GLuint>::const_iterator it_gohan = valid_components.begin(); |
| it_gohan != valid_components.end(); ++it_gohan) |
| { |
| const GLuint max_component = *it_gohan + type.GetNumComponents(); |
| for (std::vector<GLuint>::const_iterator it_goten = it_gohan; |
| it_goten != valid_components.end() && max_component > *it_goten; ++it_goten) |
| { |
| for (GLuint stage = 0; stage < Utils::Shader::STAGE_MAX; ++stage) |
| { |
| /* Skip compute shader */ |
| if (Utils::Shader::COMPUTE == stage) |
| { |
| continue; |
| } |
| |
| testCase test_case = { *it_gohan, *it_goten, (Utils::Shader::STAGES)stage, type }; |
| |
| m_test_cases.push_back(test_case); |
| } |
| } |
| } |
| } |
| } |
| |
| /** Constructor |
| * |
| * @param context Test framework context |
| **/ |
| OutputComponentAliasingTest::OutputComponentAliasingTest(deqp::Context& context) |
| : NegativeTestBase(context, "output_component_aliasing", |
| "Test verifies that compiler reports component aliasing as error") |
| { |
| } |
| |
| /** Source for given test case and stage |
| * |
| * @param test_case_index Index of test case |
| * @param stage Shader stage |
| * |
| * @return Shader source |
| **/ |
| std::string OutputComponentAliasingTest::getShaderSource(GLuint test_case_index, Utils::Shader::STAGES stage) |
| { |
| static const GLchar* var_definition = |
| "layout (location = 1, component = COMPONENT) FLAT out TYPE gohanARRAY;\n" |
| #if DEBUG_NEG_REMOVE_ERROR |
| "/* layout (location = 1, component = COMPONENT) */ FLAT out TYPE gotenARRAY;\n"; |
| #else |
| "layout (location = 1, component = COMPONENT) FLAT out TYPE gotenARRAY;\n"; |
| #endif /* DEBUG_NEG_REMOVE_ERROR */ |
| static const GLchar* l_test = " gohanINDEX = TYPE(1);\n" |
| " gotenINDEX = TYPE(0);\n"; |
| static const GLchar* fs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 gs_fs;\n" |
| "out vec4 fs_out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " fs_out = gs_fs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* fs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 gs_fs;\n" |
| "out vec4 fs_out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = gs_fs;\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " fs_out += result;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* gs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| "in vec4 tes_gs[];\n" |
| "out vec4 gs_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| static const GLchar* gs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 tes_gs[];\n" |
| "out vec4 gs_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = tes_gs[0];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tcs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "in vec4 vs_tcs[];\n" |
| "out vec4 tcs_tes[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| "\n" |
| " tcs_tes[gl_InvocationID] = vs_tcs[gl_InvocationID];\n" |
| "\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tcs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 vs_tcs[];\n" |
| "out vec4 tcs_tes[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = vs_tcs[gl_InvocationID];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " tcs_tes[gl_InvocationID] = result;\n" |
| "\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tes = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(isolines, point_mode) in;\n" |
| "\n" |
| "in vec4 tcs_tes[];\n" |
| "out vec4 tes_gs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " tes_gs = tcs_tes[0];\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tes_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(isolines, point_mode) in;\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 tcs_tes[];\n" |
| "out vec4 tes_gs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = tcs_tes[0];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " tes_gs += result;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 vs_tcs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vs_tcs = in_vs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 vs_tcs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = in_vs;\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " vs_tcs += result;\n" |
| "}\n" |
| "\n"; |
| |
| std::string source; |
| testCase& test_case = m_test_cases[test_case_index]; |
| |
| if (test_case.m_stage == stage) |
| { |
| const GLchar* array = ""; |
| GLchar buffer_gohan[16]; |
| GLchar buffer_goten[16]; |
| const GLchar* flat = ""; |
| const GLchar* index = ""; |
| size_t position = 0; |
| const GLchar* type_name = test_case.m_type.GetGLSLTypeName(); |
| |
| if (isFlatRequired(stage, test_case.m_type, Utils::Variable::VARYING_OUTPUT)) |
| { |
| flat = "flat"; |
| } |
| |
| sprintf(buffer_gohan, "%d", test_case.m_component_gohan); |
| sprintf(buffer_goten, "%d", test_case.m_component_goten); |
| |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs_tested; |
| break; |
| case Utils::Shader::GEOMETRY: |
| source = gs_tested; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| source = tcs_tested; |
| array = "[]"; |
| index = "[gl_InvocationID]"; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| source = tes_tested; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs_tested; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| Utils::replaceToken("VAR_DEFINITION", position, var_definition, source); |
| position = 0; |
| Utils::replaceToken("COMPONENT", position, buffer_gohan, source); |
| Utils::replaceToken("FLAT", position, flat, source); |
| Utils::replaceToken("ARRAY", position, array, source); |
| Utils::replaceToken("COMPONENT", position, buffer_goten, source); |
| Utils::replaceToken("FLAT", position, flat, source); |
| Utils::replaceToken("ARRAY", position, array, source); |
| Utils::replaceToken("VARIABLE_USE", position, l_test, source); |
| |
| Utils::replaceAllTokens("TYPE", type_name, source); |
| Utils::replaceAllTokens("INDEX", index, source); |
| } |
| else |
| { |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs; |
| break; |
| case Utils::Shader::GEOMETRY: |
| source = gs; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| source = tcs; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| source = tes; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| } |
| |
| return source; |
| } |
| |
| /** Get description of test case |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return Test case description |
| **/ |
| std::string OutputComponentAliasingTest::getTestCaseName(GLuint test_case_index) |
| { |
| std::stringstream stream; |
| testCase& test_case = m_test_cases[test_case_index]; |
| |
| stream << "Stage: " << Utils::Shader::GetStageName(test_case.m_stage) |
| << " type: " << test_case.m_type.GetGLSLTypeName() << ", components: " << test_case.m_component_gohan |
| << " & " << test_case.m_component_goten; |
| |
| return stream.str(); |
| } |
| |
| /** Get number of test cases |
| * |
| * @return Number of test cases |
| **/ |
| GLuint OutputComponentAliasingTest::getTestCaseNumber() |
| { |
| return static_cast<GLuint>(m_test_cases.size()); |
| } |
| |
| /** Selects if "compute" stage is relevant for test |
| * |
| * @param ignored |
| * |
| * @return false |
| **/ |
| bool OutputComponentAliasingTest::isComputeRelevant(GLuint /* test_case_index */) |
| { |
| return false; |
| } |
| |
| /** Prepare all test cases |
| * |
| **/ |
| void OutputComponentAliasingTest::testInit() |
| { |
| const GLuint n_types = getTypesNumber(); |
| |
| for (GLuint i = 0; i < n_types; ++i) |
| { |
| const Utils::Type& type = getType(i); |
| const std::vector<GLuint>& valid_components = type.GetValidComponents(); |
| |
| if (valid_components.empty()) |
| { |
| continue; |
| } |
| |
| for (std::vector<GLuint>::const_iterator it_gohan = valid_components.begin(); |
| it_gohan != valid_components.end(); ++it_gohan) |
| { |
| const GLuint max_component = *it_gohan + type.GetNumComponents(); |
| for (std::vector<GLuint>::const_iterator it_goten = it_gohan; |
| it_goten != valid_components.end() && max_component > *it_goten; ++it_goten) |
| { |
| for (GLuint stage = 0; stage < Utils::Shader::STAGE_MAX; ++stage) |
| { |
| /* Skip compute shader */ |
| if (Utils::Shader::COMPUTE == stage) |
| { |
| continue; |
| } |
| |
| if ((Utils::Shader::FRAGMENT == stage) && (Utils::Type::Double == type.m_basic_type)) |
| { |
| continue; |
| } |
| |
| testCase test_case = { *it_gohan, *it_goten, (Utils::Shader::STAGES)stage, type }; |
| |
| m_test_cases.push_back(test_case); |
| } |
| } |
| } |
| } |
| } |
| |
| /** Constructor |
| * |
| * @param context Test framework context |
| **/ |
| VaryingLocationAliasingWithMixedTypesTest::VaryingLocationAliasingWithMixedTypesTest(deqp::Context& context) |
| : NegativeTestBase(context, "varying_location_aliasing_with_mixed_types", |
| "Test verifies that compiler reports error when float/int types are mixed at one location") |
| { |
| } |
| |
| /** Source for given test case and stage |
| * |
| * @param test_case_index Index of test case |
| * @param stage Shader stage |
| * |
| * @return Shader source |
| **/ |
| std::string VaryingLocationAliasingWithMixedTypesTest::getShaderSource(GLuint test_case_index, |
| Utils::Shader::STAGES stage) |
| { |
| static const GLchar* var_definition = |
| "layout (location = 1, component = COMPONENT) FLAT DIRECTION TYPE gohanARRAY;\n" |
| "layout (location = 1, component = COMPONENT) FLAT DIRECTION TYPE gotenARRAY;\n"; |
| static const GLchar* input_use = " if ((TYPE(0) == gohanINDEX) &&\n" |
| " (TYPE(1) == gotenINDEX) )\n" |
| " {\n" |
| " result += vec4(1, 0.5, 0.25, 0.125);\n" |
| " }\n"; |
| static const GLchar* output_use = " gohanINDEX = TYPE(0);\n" |
| " gotenINDEX = TYPE(1);\n" |
| " if (vec4(0) == result)\n" |
| " {\n" |
| " gohanINDEX = TYPE(1);\n" |
| " gotenINDEX = TYPE(0);\n" |
| " }\n"; |
| static const GLchar* fs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 gs_fs;\n" |
| "out vec4 fs_out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " fs_out = gs_fs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* fs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 gs_fs;\n" |
| "out vec4 fs_out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = gs_fs;\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " fs_out += result;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* gs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| "in vec4 tes_gs[];\n" |
| "out vec4 gs_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| static const GLchar* gs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 tes_gs[];\n" |
| "out vec4 gs_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = tes_gs[0];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tcs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "in vec4 vs_tcs[];\n" |
| "out vec4 tcs_tes[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| "\n" |
| " tcs_tes[gl_InvocationID] = vs_tcs[gl_InvocationID];\n" |
| "\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tcs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 vs_tcs[];\n" |
| "out vec4 tcs_tes[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = vs_tcs[gl_InvocationID];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " tcs_tes[gl_InvocationID] = result;\n" |
| "\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tes = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(isolines, point_mode) in;\n" |
| "\n" |
| "in vec4 tcs_tes[];\n" |
| "out vec4 tes_gs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " tes_gs = tcs_tes[0];\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tes_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(isolines, point_mode) in;\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 tcs_tes[];\n" |
| "out vec4 tes_gs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = tcs_tes[0];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " tes_gs += result;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 vs_tcs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vs_tcs = in_vs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 vs_tcs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = in_vs;\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " vs_tcs += result;\n" |
| "}\n" |
| "\n"; |
| |
| std::string source; |
| testCase& test_case = m_test_cases[test_case_index]; |
| |
| if (test_case.m_stage == stage) |
| { |
| const GLchar* array = ""; |
| GLchar buffer_gohan[16]; |
| GLchar buffer_goten[16]; |
| const GLchar* direction = "in "; |
| const GLchar* flat_gohan = ""; |
| const GLchar* flat_goten = ""; |
| const GLchar* index = ""; |
| size_t position = 0; |
| size_t temp; |
| const GLchar* type_gohan_name = test_case.m_type_gohan.GetGLSLTypeName(); |
| const GLchar* type_goten_name = test_case.m_type_goten.GetGLSLTypeName(); |
| Utils::Variable::STORAGE storage = Utils::Variable::VARYING_INPUT; |
| const GLchar* var_use = Utils::Shader::VERTEX == stage ? input_use : "\n"; |
| |
| if (false == test_case.m_is_input) |
| { |
| direction = "out"; |
| storage = Utils::Variable::VARYING_OUTPUT; |
| var_use = output_use; |
| } |
| |
| /* If the interpolation qualifier would be different, the test |
| * would fail and we are testing here mixed types, not mixed |
| * interpolation qualifiers. |
| */ |
| if (isFlatRequired(stage, test_case.m_type_gohan, storage) || |
| isFlatRequired(stage, test_case.m_type_goten, storage)) |
| { |
| flat_gohan = "flat"; |
| flat_goten = "flat"; |
| } |
| |
| sprintf(buffer_gohan, "%d", test_case.m_component_gohan); |
| sprintf(buffer_goten, "%d", test_case.m_component_goten); |
| |
| #if DEBUG_NEG_REMOVE_ERROR |
| type_goten_name = Utils::Type::GetType(test_case.m_type_gohan.m_basic_type, 1, 1).GetGLSLTypeName(); |
| if (Utils::Type::Double == test_case.m_type_gohan.m_basic_type) |
| { |
| sprintf(buffer_goten, "%d", 0 == test_case.m_component_gohan ? 2 : 0); |
| } |
| #endif /* DEBUG_NEG_REMOVE_ERROR */ |
| |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs_tested; |
| break; |
| case Utils::Shader::GEOMETRY: |
| source = gs_tested; |
| array = test_case.m_is_input ? "[]" : ""; |
| index = test_case.m_is_input ? "[0]" : ""; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| source = tcs_tested; |
| array = "[]"; |
| index = "[gl_InvocationID]"; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| source = tes_tested; |
| array = test_case.m_is_input ? "[]" : ""; |
| index = test_case.m_is_input ? "[0]" : ""; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs_tested; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| Utils::replaceToken("VAR_DEFINITION", position, var_definition, source); |
| position = 0; |
| Utils::replaceToken("COMPONENT", position, buffer_gohan, source); |
| Utils::replaceToken("FLAT", position, flat_gohan, source); |
| Utils::replaceToken("DIRECTION", position, direction, source); |
| Utils::replaceToken("TYPE", position, type_gohan_name, source); |
| Utils::replaceToken("ARRAY", position, array, source); |
| Utils::replaceToken("COMPONENT", position, buffer_goten, source); |
| Utils::replaceToken("FLAT", position, flat_goten, source); |
| Utils::replaceToken("DIRECTION", position, direction, source); |
| Utils::replaceToken("TYPE", position, type_goten_name, source); |
| Utils::replaceToken("ARRAY", position, array, source); |
| |
| temp = position; |
| Utils::replaceToken("VARIABLE_USE", position, var_use, source); |
| position = temp; |
| if (!test_case.m_is_input) |
| { |
| Utils::replaceToken("TYPE", position, type_gohan_name, source); |
| Utils::replaceToken("TYPE", position, type_goten_name, source); |
| Utils::replaceToken("TYPE", position, type_gohan_name, source); |
| Utils::replaceToken("TYPE", position, type_goten_name, source); |
| } |
| else if (Utils::Shader::VERTEX == stage) |
| { |
| Utils::replaceToken("TYPE", position, type_gohan_name, source); |
| Utils::replaceToken("TYPE", position, type_goten_name, source); |
| } |
| |
| Utils::replaceAllTokens("INDEX", index, source); |
| } |
| else |
| { |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs; |
| break; |
| case Utils::Shader::GEOMETRY: |
| source = gs; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| source = tcs; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| source = tes; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| } |
| |
| return source; |
| } |
| |
| /** Get description of test case |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return Test case description |
| **/ |
| std::string VaryingLocationAliasingWithMixedTypesTest::getTestCaseName(GLuint test_case_index) |
| { |
| std::stringstream stream; |
| testCase& test_case = m_test_cases[test_case_index]; |
| |
| stream << "Stage: " << Utils::Shader::GetStageName(test_case.m_stage) << ", " |
| << test_case.m_type_gohan.GetGLSLTypeName() << " at " << test_case.m_component_gohan << ", " |
| << test_case.m_type_goten.GetGLSLTypeName() << " at " << test_case.m_component_goten << ". Direction: "; |
| |
| if (true == test_case.m_is_input) |
| { |
| stream << "input"; |
| } |
| else |
| { |
| stream << "output"; |
| } |
| |
| return stream.str(); |
| } |
| |
| /** Get number of test cases |
| * |
| * @return Number of test cases |
| **/ |
| GLuint VaryingLocationAliasingWithMixedTypesTest::getTestCaseNumber() |
| { |
| return static_cast<GLuint>(m_test_cases.size()); |
| } |
| |
| /** Selects if "compute" stage is relevant for test |
| * |
| * @param ignored |
| * |
| * @return false |
| **/ |
| bool VaryingLocationAliasingWithMixedTypesTest::isComputeRelevant(GLuint /* test_case_index */) |
| { |
| return false; |
| } |
| |
| /** Prepare all test cases |
| * |
| **/ |
| void VaryingLocationAliasingWithMixedTypesTest::testInit() |
| { |
| const GLuint n_types = getTypesNumber(); |
| |
| for (GLuint i = 0; i < n_types; ++i) |
| { |
| const Utils::Type& type_gohan = getType(i); |
| const std::vector<GLuint>& valid_components_gohan = type_gohan.GetValidComponents(); |
| |
| if (valid_components_gohan.empty()) |
| { |
| continue; |
| } |
| |
| for (GLuint j = 0; j < n_types; ++j) |
| { |
| const Utils::Type& type_goten = getType(j); |
| const std::vector<GLuint>& valid_components_goten = type_goten.GetValidComponents(); |
| |
| if (valid_components_goten.empty()) |
| { |
| continue; |
| } |
| |
| /* Skip valid combinations */ |
| if (Utils::Type::CanTypesShareLocation(type_gohan.m_basic_type, type_goten.m_basic_type)) |
| { |
| continue; |
| } |
| |
| for (std::vector<GLuint>::const_iterator it_gohan = valid_components_gohan.begin(); |
| it_gohan != valid_components_gohan.end(); ++it_gohan) |
| { |
| const GLuint min_component = *it_gohan + type_gohan.GetNumComponents(); |
| for (std::vector<GLuint>::const_iterator it_goten = valid_components_goten.begin(); |
| it_goten != valid_components_goten.end(); ++it_goten) |
| { |
| |
| if (min_component > *it_goten) |
| { |
| continue; |
| } |
| |
| for (GLuint stage = 0; stage < Utils::Shader::STAGE_MAX; ++stage) |
| { |
| /* Skip compute shader */ |
| if (Utils::Shader::COMPUTE == stage) |
| { |
| continue; |
| } |
| |
| if (Utils::Shader::VERTEX != stage) |
| { |
| testCase test_case_in = { *it_gohan, *it_goten, true, (Utils::Shader::STAGES)stage, |
| type_gohan, type_goten }; |
| |
| m_test_cases.push_back(test_case_in); |
| } |
| |
| /* Skip double outputs in fragment shader */ |
| if ((Utils::Shader::FRAGMENT != stage) || ((Utils::Type::Double != type_gohan.m_basic_type) && |
| (Utils::Type::Double != type_goten.m_basic_type))) |
| { |
| testCase test_case_out = { *it_gohan, *it_goten, false, (Utils::Shader::STAGES)stage, |
| type_gohan, type_goten }; |
| |
| m_test_cases.push_back(test_case_out); |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| /** Constructor |
| * |
| * @param context Test framework context |
| **/ |
| VaryingLocationAliasingWithMixedInterpolationTest::VaryingLocationAliasingWithMixedInterpolationTest( |
| deqp::Context& context) |
| : NegativeTestBase( |
| context, "varying_location_aliasing_with_mixed_interpolation", |
| "Test verifies that compiler reports error when interpolation qualifiers are mixed at one location") |
| { |
| } |
| |
| /** Source for given test case and stage |
| * |
| * @param test_case_index Index of test case |
| * @param stage Shader stage |
| * |
| * @return Shader source |
| **/ |
| std::string VaryingLocationAliasingWithMixedInterpolationTest::getShaderSource(GLuint test_case_index, |
| Utils::Shader::STAGES stage) |
| { |
| static const GLchar* var_definition = |
| "layout (location = 1, component = COMPONENT) INTERPOLATION DIRECTION TYPE gohanARRAY;\n" |
| "layout (location = 1, component = COMPONENT) INTERPOLATION DIRECTION TYPE gotenARRAY;\n"; |
| static const GLchar* input_use = " if ((TYPE(0) == gohanINDEX) &&\n" |
| " (TYPE(1) == gotenINDEX) )\n" |
| " {\n" |
| " result += vec4(1, 0.5, 0.25, 0.125);\n" |
| " }\n"; |
| static const GLchar* output_use = " gohanINDEX = TYPE(0);\n" |
| " gotenINDEX = TYPE(1);\n" |
| " if (vec4(0) == result)\n" |
| " {\n" |
| " gohanINDEX = TYPE(1);\n" |
| " gotenINDEX = TYPE(0);\n" |
| " }\n"; |
| static const GLchar* fs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 gs_fs;\n" |
| "out vec4 fs_out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " fs_out = gs_fs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* fs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 gs_fs;\n" |
| "out vec4 fs_out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = gs_fs;\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " fs_out = result;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* gs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| "in vec4 tes_gs[];\n" |
| "out vec4 gs_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| static const GLchar* gs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 tes_gs[];\n" |
| "out vec4 gs_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = tes_gs[0];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tcs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "in vec4 vs_tcs[];\n" |
| "out vec4 tcs_tes[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| "\n" |
| " tcs_tes[gl_InvocationID] = vs_tcs[gl_InvocationID];\n" |
| "\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tcs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 vs_tcs[];\n" |
| "out vec4 tcs_tes[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = vs_tcs[gl_InvocationID];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " tcs_tes[gl_InvocationID] = result;\n" |
| "\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tes = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(isolines, point_mode) in;\n" |
| "\n" |
| "in vec4 tcs_tes[];\n" |
| "out vec4 tes_gs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " tes_gs = tcs_tes[0];\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tes_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(isolines, point_mode) in;\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 tcs_tes[];\n" |
| "out vec4 tes_gs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = tcs_tes[0];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " tes_gs += result;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 vs_tcs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vs_tcs = in_vs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 vs_tcs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = in_vs;\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " vs_tcs += result;\n" |
| "}\n" |
| "\n"; |
| |
| std::string source; |
| testCase& test_case = m_test_cases[test_case_index]; |
| |
| if (test_case.m_stage == stage) |
| { |
| const GLchar* array = ""; |
| GLchar buffer_gohan[16]; |
| GLchar buffer_goten[16]; |
| const GLchar* direction = "in "; |
| const GLchar* index = ""; |
| const GLchar* int_gohan = getInterpolationQualifier(test_case.m_interpolation_gohan); |
| const GLchar* int_goten = getInterpolationQualifier(test_case.m_interpolation_goten); |
| #if DEBUG_NEG_REMOVE_ERROR |
| if (FLAT == test_case.m_interpolation_goten) |
| { |
| int_gohan = int_goten; |
| } |
| else |
| { |
| int_goten = int_gohan; |
| } |
| #endif /* DEBUG_NEG_REMOVE_ERROR */ |
| size_t position = 0; |
| size_t temp; |
| const GLchar* type_gohan_name = test_case.m_type_gohan.GetGLSLTypeName(); |
| const GLchar* type_goten_name = test_case.m_type_goten.GetGLSLTypeName(); |
| const GLchar* var_use = Utils::Shader::VERTEX == stage ? input_use : "\n"; |
| |
| if (false == test_case.m_is_input) |
| { |
| direction = "out"; |
| |
| var_use = output_use; |
| } |
| |
| sprintf(buffer_gohan, "%d", test_case.m_component_gohan); |
| sprintf(buffer_goten, "%d", test_case.m_component_goten); |
| |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs_tested; |
| break; |
| case Utils::Shader::GEOMETRY: |
| source = gs_tested; |
| array = test_case.m_is_input ? "[]" : ""; |
| index = test_case.m_is_input ? "[0]" : ""; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| source = tcs_tested; |
| array = "[]"; |
| index = "[gl_InvocationID]"; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| source = tes_tested; |
| array = test_case.m_is_input ? "[]" : ""; |
| index = test_case.m_is_input ? "[0]" : ""; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs_tested; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| Utils::replaceToken("VAR_DEFINITION", position, var_definition, source); |
| position = 0; |
| Utils::replaceToken("COMPONENT", position, buffer_gohan, source); |
| Utils::replaceToken("INTERPOLATION", position, int_gohan, source); |
| Utils::replaceToken("DIRECTION", position, direction, source); |
| Utils::replaceToken("TYPE", position, type_gohan_name, source); |
| Utils::replaceToken("ARRAY", position, array, source); |
| Utils::replaceToken("COMPONENT", position, buffer_goten, source); |
| Utils::replaceToken("INTERPOLATION", position, int_goten, source); |
| Utils::replaceToken("DIRECTION", position, direction, source); |
| Utils::replaceToken("TYPE", position, type_goten_name, source); |
| Utils::replaceToken("ARRAY", position, array, source); |
| |
| temp = position; |
| Utils::replaceToken("VARIABLE_USE", position, var_use, source); |
| position = temp; |
| if (!test_case.m_is_input) |
| { |
| Utils::replaceToken("TYPE", position, type_gohan_name, source); |
| Utils::replaceToken("TYPE", position, type_goten_name, source); |
| Utils::replaceToken("TYPE", position, type_gohan_name, source); |
| Utils::replaceToken("TYPE", position, type_goten_name, source); |
| } |
| else if (Utils::Shader::VERTEX == stage) |
| { |
| Utils::replaceToken("TYPE", position, type_gohan_name, source); |
| Utils::replaceToken("TYPE", position, type_goten_name, source); |
| } |
| |
| Utils::replaceAllTokens("INDEX", index, source); |
| } |
| else |
| { |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs; |
| break; |
| case Utils::Shader::GEOMETRY: |
| source = gs; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| source = tcs; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| source = tes; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| } |
| |
| return source; |
| } |
| |
| /** Get description of test case |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return Test case description |
| **/ |
| std::string VaryingLocationAliasingWithMixedInterpolationTest::getTestCaseName(GLuint test_case_index) |
| { |
| std::stringstream stream; |
| testCase& test_case = m_test_cases[test_case_index]; |
| |
| stream << "Stage: " << Utils::Shader::GetStageName(test_case.m_stage) << ", " |
| << getInterpolationQualifier(test_case.m_interpolation_gohan) << " " |
| << test_case.m_type_gohan.GetGLSLTypeName() << " at " << test_case.m_component_gohan << ", " |
| << getInterpolationQualifier(test_case.m_interpolation_goten) << " " |
| << test_case.m_type_goten.GetGLSLTypeName() << " at " << test_case.m_component_goten << ". Direction: "; |
| |
| if (true == test_case.m_is_input) |
| { |
| stream << "input"; |
| } |
| else |
| { |
| stream << "output"; |
| } |
| |
| return stream.str(); |
| } |
| |
| /** Get number of test cases |
| * |
| * @return Number of test cases |
| **/ |
| GLuint VaryingLocationAliasingWithMixedInterpolationTest::getTestCaseNumber() |
| { |
| return static_cast<GLuint>(m_test_cases.size()); |
| } |
| |
| /** Selects if "compute" stage is relevant for test |
| * |
| * @param ignored |
| * |
| * @return false |
| **/ |
| bool VaryingLocationAliasingWithMixedInterpolationTest::isComputeRelevant(GLuint /* test_case_index */) |
| { |
| return false; |
| } |
| |
| /** Prepare all test cases |
| * |
| **/ |
| void VaryingLocationAliasingWithMixedInterpolationTest::testInit() |
| { |
| const GLuint n_types = getTypesNumber(); |
| |
| for (GLuint i = 0; i < n_types; ++i) |
| { |
| const Utils::Type& type_gohan = getType(i); |
| const std::vector<GLuint>& valid_components_gohan = type_gohan.GetValidComponents(); |
| |
| if (valid_components_gohan.empty()) |
| { |
| continue; |
| } |
| |
| const GLuint gohan = valid_components_gohan.front(); |
| |
| for (GLuint j = 0; j < n_types; ++j) |
| { |
| const Utils::Type& type_goten = getType(j); |
| const std::vector<GLuint>& valid_components_goten = type_goten.GetValidComponents(); |
| |
| if (valid_components_goten.empty()) |
| { |
| continue; |
| } |
| |
| /* Just get the highest valid component for goten and |
| * check if we can use it. |
| */ |
| const GLuint min_component = gohan + type_gohan.GetNumComponents(); |
| const GLuint goten = valid_components_goten.back(); |
| |
| if (min_component > goten) |
| { |
| continue; |
| } |
| |
| /* Skip invalid combinations */ |
| if (!Utils::Type::CanTypesShareLocation(type_gohan.m_basic_type, type_goten.m_basic_type)) |
| { |
| continue; |
| } |
| |
| for (GLuint stage = 0; stage < Utils::Shader::STAGE_MAX; ++stage) |
| { |
| /* Skip compute shader */ |
| if (Utils::Shader::COMPUTE == stage) |
| { |
| continue; |
| } |
| |
| for (GLuint int_gohan = 0; int_gohan < INTERPOLATION_MAX; ++int_gohan) |
| { |
| for (GLuint int_goten = 0; int_goten < INTERPOLATION_MAX; ++int_goten) |
| { |
| /* Skip when both are the same */ |
| if (int_gohan == int_goten) |
| { |
| continue; |
| } |
| |
| /* Skip inputs in: vertex shader and whenever |
| * flat is mandatory and is not the chosen |
| * one. |
| */ |
| bool skip_inputs = Utils::Shader::VERTEX == stage; |
| skip_inputs |= |
| (FLAT != int_gohan && isFlatRequired(static_cast<Utils::Shader::STAGES>(stage), type_gohan, |
| Utils::Variable::VARYING_INPUT)); |
| skip_inputs |= |
| (FLAT != int_goten && isFlatRequired(static_cast<Utils::Shader::STAGES>(stage), type_goten, |
| Utils::Variable::VARYING_INPUT)); |
| |
| if (!skip_inputs) |
| { |
| testCase test_case_in = { gohan, |
| goten, |
| static_cast<INTERPOLATIONS>(int_gohan), |
| static_cast<INTERPOLATIONS>(int_goten), |
| true, |
| static_cast<Utils::Shader::STAGES>(stage), |
| type_gohan, |
| type_goten }; |
| m_test_cases.push_back(test_case_in); |
| } |
| |
| /* Skip outputs in fragment shader and |
| * whenever flat is mandatory and is not the |
| * chosen one. |
| */ |
| bool skip_outputs = Utils::Shader::FRAGMENT == stage; |
| skip_outputs |= |
| (FLAT != int_gohan && isFlatRequired(static_cast<Utils::Shader::STAGES>(stage), type_gohan, |
| Utils::Variable::VARYING_OUTPUT)); |
| skip_outputs |= |
| (FLAT != int_goten && isFlatRequired(static_cast<Utils::Shader::STAGES>(stage), type_goten, |
| Utils::Variable::VARYING_OUTPUT)); |
| |
| if (!skip_outputs) |
| { |
| testCase test_case_out = { gohan, |
| goten, |
| static_cast<INTERPOLATIONS>(int_gohan), |
| static_cast<INTERPOLATIONS>(int_goten), |
| false, |
| static_cast<Utils::Shader::STAGES>(stage), |
| type_gohan, |
| type_goten }; |
| m_test_cases.push_back(test_case_out); |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| /** Get interpolation qualifier |
| * |
| * @param interpolation Enumeration |
| * |
| * @return GLSL qualifier |
| **/ |
| const GLchar* VaryingLocationAliasingWithMixedInterpolationTest::getInterpolationQualifier(INTERPOLATIONS interpolation) |
| { |
| const GLchar* result = 0; |
| |
| switch (interpolation) |
| { |
| case SMOOTH: |
| result = "smooth"; |
| break; |
| case FLAT: |
| result = "flat"; |
| break; |
| case NO_PERSPECTIVE: |
| result = "noperspective"; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| return result; |
| } |
| |
| /** Constructor |
| * |
| * @param context Test framework context |
| **/ |
| VaryingLocationAliasingWithMixedAuxiliaryStorageTest::VaryingLocationAliasingWithMixedAuxiliaryStorageTest( |
| deqp::Context& context) |
| : NegativeTestBase( |
| context, "varying_location_aliasing_with_mixed_auxiliary_storage", |
| "Test verifies that compiler reports error when auxiliary storage qualifiers are mixed at one location") |
| { |
| } |
| |
| /** Source for given test case and stage |
| * |
| * @param test_case_index Index of test case |
| * @param stage Shader stage |
| * |
| * @return Shader source |
| **/ |
| std::string VaryingLocationAliasingWithMixedAuxiliaryStorageTest::getShaderSource(GLuint test_case_index, |
| Utils::Shader::STAGES stage) |
| { |
| static const GLchar* var_definition = |
| "layout (location = 1, component = COMPONENT) AUX INTERPOLATION DIRECTION TYPE gohanARRAY;\n" |
| "layout (location = 1, component = COMPONENT) AUX INTERPOLATION DIRECTION TYPE gotenARRAY;\n"; |
| static const GLchar* input_use = " if ((TYPE(0) == gohanINDEX_GOHAN) &&\n" |
| " (TYPE(1) == gotenINDEX_GOTEN) )\n" |
| " {\n" |
| " result += vec4(1, 0.5, 0.25, 0.125);\n" |
| " }\n"; |
| static const GLchar* output_use = " gohanINDEX_GOHAN = TYPE(0);\n" |
| " gotenINDEX_GOTEN = TYPE(1);\n" |
| " if (vec4(0) == result)\n" |
| " {\n" |
| " gohanINDEX_GOHAN = TYPE(1);\n" |
| " gotenINDEX_GOTEN = TYPE(0);\n" |
| " }\n"; |
| static const GLchar* fs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 gs_fs;\n" |
| "out vec4 fs_out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " fs_out = gs_fs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* fs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 gs_fs;\n" |
| "out vec4 fs_out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = gs_fs;\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " fs_out = result;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* gs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| "in vec4 tes_gs[];\n" |
| "out vec4 gs_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| static const GLchar* gs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 tes_gs[];\n" |
| "out vec4 gs_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = tes_gs[0];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tcs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "in vec4 vs_tcs[];\n" |
| "out vec4 tcs_tes[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| "\n" |
| " tcs_tes[gl_InvocationID] = vs_tcs[gl_InvocationID];\n" |
| "\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tcs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 vs_tcs[];\n" |
| "out vec4 tcs_tes[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = vs_tcs[gl_InvocationID];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " tcs_tes[gl_InvocationID] = result;\n" |
| "\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tes = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(isolines, point_mode) in;\n" |
| "\n" |
| "in vec4 tcs_tes[];\n" |
| "out vec4 tes_gs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " tes_gs = tcs_tes[0];\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tes_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(isolines, point_mode) in;\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 tcs_tes[];\n" |
| "out vec4 tes_gs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = tcs_tes[0];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " tes_gs += result;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 vs_tcs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vs_tcs = in_vs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 vs_tcs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = in_vs;\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " vs_tcs += result;\n" |
| "}\n" |
| "\n"; |
| |
| std::string source; |
| testCase& test_case = m_test_cases[test_case_index]; |
| |
| if (test_case.m_stage == stage) |
| { |
| const GLchar* array_gohan = ""; |
| const GLchar* array_goten = ""; |
| const GLchar* aux_gohan = getAuxiliaryQualifier(test_case.m_aux_gohan); |
| #if DEBUG_NEG_REMOVE_ERROR |
| const GLchar* aux_goten = aux_gohan; |
| #else |
| const GLchar* aux_goten = getAuxiliaryQualifier(test_case.m_aux_goten); |
| #endif /* DEBUG_NEG_REMOVE_ERROR */ |
| GLchar buffer_gohan[16]; |
| GLchar buffer_goten[16]; |
| const GLchar* direction = "in"; |
| const GLchar* index_gohan = ""; |
| const GLchar* index_goten = ""; |
| Utils::Variable::STORAGE storage = Utils::Variable::VARYING_INPUT; |
| const GLchar* interpolation = ""; |
| size_t position = 0; |
| size_t temp; |
| const GLchar* type_gohan_name = test_case.m_type_gohan.GetGLSLTypeName(); |
| const GLchar* type_goten_name = test_case.m_type_goten.GetGLSLTypeName(); |
| const GLchar* var_use = Utils::Shader::VERTEX == stage ? input_use : "\n"; |
| |
| if (false == test_case.m_is_input) |
| { |
| direction = "out"; |
| storage = Utils::Variable::VARYING_OUTPUT; |
| var_use = output_use; |
| } |
| |
| if (isFlatRequired(stage, test_case.m_type_gohan, storage) || |
| isFlatRequired(stage, test_case.m_type_goten, storage)) |
| { |
| interpolation = "flat"; |
| } |
| |
| sprintf(buffer_gohan, "%d", test_case.m_component_gohan); |
| sprintf(buffer_goten, "%d", test_case.m_component_goten); |
| |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs_tested; |
| break; |
| case Utils::Shader::GEOMETRY: |
| source = gs_tested; |
| array_gohan = test_case.m_is_input ? "[]" : ""; |
| index_gohan = test_case.m_is_input ? "[0]" : ""; |
| array_goten = test_case.m_is_input ? "[]" : ""; |
| index_goten = test_case.m_is_input ? "[0]" : ""; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| source = tcs_tested; |
| if (PATCH != test_case.m_aux_gohan) |
| { |
| array_gohan = "[]"; |
| index_gohan = "[gl_InvocationID]"; |
| } |
| #if DEBUG_NEG_REMOVE_ERROR |
| array_goten = array_gohan; |
| index_goten = index_gohan; |
| #else |
| if (PATCH != test_case.m_aux_goten) |
| { |
| array_goten = "[]"; |
| index_goten = "[gl_InvocationID]"; |
| } |
| #endif /* DEBUG_NEG_REMOVE_ERROR */ |
| break; |
| case Utils::Shader::TESS_EVAL: |
| source = tes_tested; |
| if (PATCH != test_case.m_aux_gohan) |
| { |
| array_gohan = test_case.m_is_input ? "[]" : ""; |
| index_gohan = test_case.m_is_input ? "[0]" : ""; |
| } |
| #if DEBUG_NEG_REMOVE_ERROR |
| array_goten = array_gohan; |
| index_goten = index_gohan; |
| #else |
| if (PATCH != test_case.m_aux_goten) |
| { |
| array_goten = test_case.m_is_input ? "[]" : ""; |
| index_goten = test_case.m_is_input ? "[0]" : ""; |
| } |
| #endif /* DEBUG_NEG_REMOVE_ERROR */ |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs_tested; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| Utils::replaceToken("VAR_DEFINITION", position, var_definition, source); |
| position = 0; |
| Utils::replaceToken("COMPONENT", position, buffer_gohan, source); |
| Utils::replaceToken("AUX", position, aux_gohan, source); |
| Utils::replaceToken("INTERPOLATION", position, interpolation, source); |
| Utils::replaceToken("DIRECTION", position, direction, source); |
| Utils::replaceToken("TYPE", position, type_gohan_name, source); |
| Utils::replaceToken("ARRAY", position, array_gohan, source); |
| Utils::replaceToken("COMPONENT", position, buffer_goten, source); |
| Utils::replaceToken("AUX", position, aux_goten, source); |
| Utils::replaceToken("INTERPOLATION", position, interpolation, source); |
| Utils::replaceToken("DIRECTION", position, direction, source); |
| Utils::replaceToken("TYPE", position, type_goten_name, source); |
| Utils::replaceToken("ARRAY", position, array_goten, source); |
| |
| temp = position; |
| Utils::replaceToken("VARIABLE_USE", position, var_use, source); |
| position = temp; |
| if (!test_case.m_is_input) |
| { |
| Utils::replaceToken("TYPE", position, type_gohan_name, source); |
| Utils::replaceToken("TYPE", position, type_goten_name, source); |
| Utils::replaceToken("TYPE", position, type_gohan_name, source); |
| Utils::replaceToken("TYPE", position, type_goten_name, source); |
| } |
| else if (Utils::Shader::VERTEX == stage) |
| { |
| Utils::replaceToken("TYPE", position, type_gohan_name, source); |
| Utils::replaceToken("TYPE", position, type_goten_name, source); |
| } |
| |
| Utils::replaceAllTokens("INDEX_GOHAN", index_gohan, source); |
| Utils::replaceAllTokens("INDEX_GOTEN", index_goten, source); |
| } |
| else |
| { |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs; |
| break; |
| case Utils::Shader::GEOMETRY: |
| source = gs; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| source = tcs; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| source = tes; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| } |
| |
| return source; |
| } |
| |
| /** Get description of test case |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return Test case description |
| **/ |
| std::string VaryingLocationAliasingWithMixedAuxiliaryStorageTest::getTestCaseName(GLuint test_case_index) |
| { |
| std::stringstream stream; |
| testCase& test_case = m_test_cases[test_case_index]; |
| |
| stream << "Stage: " << Utils::Shader::GetStageName(test_case.m_stage) << ", " |
| << getAuxiliaryQualifier(test_case.m_aux_gohan) << " " << test_case.m_type_gohan.GetGLSLTypeName() << " at " |
| << test_case.m_component_gohan << ", " << getAuxiliaryQualifier(test_case.m_aux_goten) << " " |
| << test_case.m_type_goten.GetGLSLTypeName() << " at " << test_case.m_component_goten << ". Direction: "; |
| |
| if (true == test_case.m_is_input) |
| { |
| stream << "input"; |
| } |
| else |
| { |
| stream << "output"; |
| } |
| |
| return stream.str(); |
| } |
| |
| /** Get number of test cases |
| * |
| * @return Number of test cases |
| **/ |
| GLuint VaryingLocationAliasingWithMixedAuxiliaryStorageTest::getTestCaseNumber() |
| { |
| return static_cast<GLuint>(m_test_cases.size()); |
| } |
| |
| /** Selects if "compute" stage is relevant for test |
| * |
| * @param ignored |
| * |
| * @return false |
| **/ |
| bool VaryingLocationAliasingWithMixedAuxiliaryStorageTest::isComputeRelevant(GLuint /* test_case_index */) |
| { |
| return false; |
| } |
| |
| /** Prepare all test cases |
| * |
| **/ |
| void VaryingLocationAliasingWithMixedAuxiliaryStorageTest::testInit() |
| { |
| const GLuint n_types = getTypesNumber(); |
| |
| for (GLuint i = 0; i < n_types; ++i) |
| { |
| const Utils::Type& type_gohan = getType(i); |
| const std::vector<GLuint>& valid_components_gohan = type_gohan.GetValidComponents(); |
| |
| if (valid_components_gohan.empty()) |
| { |
| continue; |
| } |
| |
| const GLuint gohan = valid_components_gohan.front(); |
| |
| for (GLuint j = 0; j < n_types; ++j) |
| { |
| const Utils::Type& type_goten = getType(j); |
| const std::vector<GLuint>& valid_components_goten = type_goten.GetValidComponents(); |
| |
| if (valid_components_goten.empty()) |
| { |
| continue; |
| } |
| |
| /* Just get the highest valid component for goten and |
| * check if we can use it. |
| */ |
| const GLuint min_component = gohan + type_gohan.GetNumComponents(); |
| const GLuint goten = valid_components_goten.back(); |
| |
| if (min_component > goten) |
| { |
| continue; |
| } |
| |
| /* Skip invalid combinations */ |
| if (!Utils::Type::CanTypesShareLocation(type_gohan.m_basic_type, type_goten.m_basic_type)) |
| { |
| continue; |
| } |
| |
| for (GLuint stage = 0; stage < Utils::Shader::STAGE_MAX; ++stage) |
| { |
| /* Skip compute shader */ |
| if (Utils::Shader::COMPUTE == stage) |
| { |
| continue; |
| } |
| |
| for (GLuint aux = 0; aux < AUXILIARY_MAX; ++aux) |
| { |
| Utils::Shader::STAGES const shader_stage = static_cast<Utils::Shader::STAGES>(stage); |
| AUXILIARIES const auxiliary = static_cast<AUXILIARIES>(aux); |
| |
| if (PATCH == auxiliary) |
| { |
| if (Utils::Shader::TESS_CTRL == shader_stage || Utils::Shader::TESS_EVAL == shader_stage) |
| { |
| bool direction = Utils::Shader::TESS_EVAL == shader_stage; |
| testCase test_case_patch_gohan = { gohan, goten, auxiliary, NONE, |
| direction, shader_stage, type_gohan, type_goten }; |
| testCase test_case_patch_goten = { gohan, goten, NONE, auxiliary, |
| direction, shader_stage, type_gohan, type_goten }; |
| |
| m_test_cases.push_back(test_case_patch_gohan); |
| m_test_cases.push_back(test_case_patch_goten); |
| } |
| continue; |
| } |
| |
| for (GLuint second_aux = 0; second_aux < AUXILIARY_MAX; ++second_aux) |
| { |
| AUXILIARIES const second_auxiliary = static_cast<AUXILIARIES>(second_aux); |
| |
| if (PATCH == second_auxiliary || auxiliary == second_auxiliary) |
| { |
| continue; |
| } |
| |
| if (Utils::Shader::FRAGMENT != shader_stage) |
| { |
| testCase test_case_out = { gohan, goten, auxiliary, second_auxiliary, |
| false, shader_stage, type_gohan, type_goten }; |
| |
| m_test_cases.push_back(test_case_out); |
| } |
| |
| if (Utils::Shader::VERTEX != shader_stage) |
| { |
| testCase test_case_in = { gohan, goten, auxiliary, second_auxiliary, |
| true, shader_stage, type_gohan, type_goten }; |
| |
| m_test_cases.push_back(test_case_in); |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| /** Get auxiliary storage qualifier |
| * |
| * @param aux Enumeration |
| * |
| * @return GLSL qualifier |
| **/ |
| const GLchar* VaryingLocationAliasingWithMixedAuxiliaryStorageTest::getAuxiliaryQualifier(AUXILIARIES aux) |
| { |
| const GLchar* result = 0; |
| |
| switch (aux) |
| { |
| case NONE: |
| result = ""; |
| break; |
| case PATCH: |
| result = "patch"; |
| break; |
| case CENTROID: |
| result = "centroid"; |
| break; |
| case SAMPLE: |
| result = "sample"; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| return result; |
| } |
| |
| /* Constants used by VertexAttribLocationAPITest */ |
| const GLuint VertexAttribLocationAPITest::m_goten_location = 6; |
| |
| /** Constructor |
| * |
| * @param context Test framework context |
| **/ |
| VertexAttribLocationAPITest::VertexAttribLocationAPITest(deqp::Context& context) |
| : TextureTestBase(context, "vertex_attrib_location_api", |
| "Test verifies that attribute locations API works as expected") |
| { |
| } |
| |
| /** Does BindAttribLocation for "goten" and relink program |
| * |
| * @param program Program object |
| * @param program_interface Interface of program |
| **/ |
| void VertexAttribLocationAPITest::prepareAttribLocation(Utils::Program& program, |
| Utils::ProgramInterface& program_interface) |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| gl.bindAttribLocation(program.m_id, m_goten_location, "goten"); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "BindAttribLocation"); |
| |
| program.Link(gl, program.m_id); |
| |
| /* We still need to get locations for gohan and chichi */ |
| TextureTestBase::prepareAttribLocation(program, program_interface); |
| } |
| |
| /** Get interface of program |
| * |
| * @param ignored |
| * @param program_interface Interface of program |
| * @param ignored |
| **/ |
| void VertexAttribLocationAPITest::getProgramInterface(GLuint /* test_case_index */, |
| Utils::ProgramInterface& program_interface, |
| Utils::VaryingPassthrough& /* varying_passthrough */) |
| { |
| Utils::ShaderInterface& si = program_interface.GetShaderInterface(Utils::Shader::VERTEX); |
| const Utils::Type& type = Utils::Type::vec4; |
| const GLuint type_size = type.GetSize(); |
| |
| /* Offsets */ |
| const GLuint chichi_offset = 0; |
| const GLuint goten_offset = chichi_offset + type_size; |
| const GLuint gohan_offset = goten_offset + type_size; |
| const GLuint goku_offset = gohan_offset + type_size; |
| |
| /* Locations */ |
| const GLuint goku_location = 2; |
| const GLuint goten_location = m_goten_location; |
| |
| /* Generate data */ |
| m_goku_data = type.GenerateDataPacked(); |
| m_gohan_data = type.GenerateDataPacked(); |
| m_goten_data = type.GenerateDataPacked(); |
| m_chichi_data = type.GenerateDataPacked(); |
| |
| /* Globals */ |
| si.m_globals = "const uint GOKU_LOCATION = 2;\n"; |
| |
| /* Attributes */ |
| si.Input("goku" /* name */, "layout (location = GOKU_LOCATION)" /* qualifiers */, 0 /* expected_componenet */, |
| goku_location /* expected_location */, type /* type */, GL_FALSE /* normalized */, |
| 0u /* n_array_elements */, 0u /* stride */, goku_offset /* offset */, (GLvoid*)&m_goku_data[0] /* data */, |
| m_goku_data.size() /* data_size */); |
| |
| si.Input("gohan" /* name */, "" /* qualifiers */, 0 /* expected_componenet */, |
| Utils::Variable::m_automatic_location /* expected_location */, type /* type */, GL_FALSE /* normalized */, |
| 0u /* n_array_elements */, 0u /* stride */, gohan_offset /* offset */, |
| (GLvoid*)&m_gohan_data[0] /* data */, m_gohan_data.size() /* data_size */); |
| |
| si.Input("goten" /* name */, "" /* qualifiers */, 0 /* expected_componenet */, |
| goten_location /* expected_location */, type /* type */, GL_FALSE /* normalized */, |
| 0u /* n_array_elements */, 0u /* stride */, goten_offset /* offset */, |
| (GLvoid*)&m_goten_data[0] /* data */, m_goten_data.size() /* data_size */); |
| |
| si.Input("chichi" /* name */, "" /* qualifiers */, 0 /* expected_componenet */, |
| Utils::Variable::m_automatic_location /* expected_location */, type /* type */, GL_FALSE /* normalized */, |
| 0u /* n_array_elements */, 0u /* stride */, chichi_offset /* offset */, |
| (GLvoid*)&m_chichi_data[0] /* data */, m_chichi_data.size() /* data_size */); |
| } |
| |
| /** Selects if "compute" stage is relevant for test |
| * |
| * @param ignored |
| * |
| * @return false |
| **/ |
| bool VertexAttribLocationAPITest::isComputeRelevant(GLuint /* test_case_index */) |
| { |
| return false; |
| } |
| |
| /* Constants used by FragmentDataLocationAPITest */ |
| const GLuint FragmentDataLocationAPITest::m_goten_location = 6; |
| |
| /** Constructor |
| * |
| * @param context Test framework context |
| **/ |
| FragmentDataLocationAPITest::FragmentDataLocationAPITest(deqp::Context& context) |
| : TextureTestBase(context, "fragment_data_location_api", |
| "Test verifies that fragment data locations API works as expected") |
| , m_goku(context) |
| , m_gohan(context) |
| , m_goten(context) |
| , m_chichi(context) |
| { |
| } |
| |
| /** Verifies contents of drawn images |
| * |
| * @param ignored |
| * @param ignored |
| * |
| * @return true if images are filled with expected values, false otherwise |
| **/ |
| bool FragmentDataLocationAPITest::checkResults(glw::GLuint /* test_case_index */, Utils::Texture& /* color_0 */) |
| { |
| static const GLuint size = m_width * m_height; |
| static const GLuint expected_goku = 0xff000000; |
| static const GLuint expected_gohan = 0xff0000ff; |
| static const GLuint expected_goten = 0xff00ff00; |
| static const GLuint expected_chichi = 0xffff0000; |
| |
| std::vector<GLuint> data; |
| data.resize(size); |
| |
| m_goku.Get(GL_RGBA, GL_UNSIGNED_BYTE, &data[0]); |
| |
| for (GLuint i = 0; i < size; ++i) |
| { |
| const GLuint color = data[i]; |
| |
| if (expected_goku != color) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "RGBA8[" << i << "]:" << color |
| << tcu::TestLog::EndMessage; |
| return false; |
| } |
| } |
| |
| m_gohan.Get(GL_RGBA, GL_UNSIGNED_BYTE, &data[0]); |
| |
| for (GLuint i = 0; i < size; ++i) |
| { |
| const GLuint color = data[i]; |
| |
| if (expected_gohan != color) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "RGBA8[" << i << "]:" << color |
| << tcu::TestLog::EndMessage; |
| return false; |
| } |
| } |
| |
| m_goten.Get(GL_RGBA, GL_UNSIGNED_BYTE, &data[0]); |
| |
| for (GLuint i = 0; i < size; ++i) |
| { |
| const GLuint color = data[i]; |
| |
| if (expected_goten != color) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "RGBA8[" << i << "]:" << color |
| << tcu::TestLog::EndMessage; |
| return false; |
| } |
| } |
| |
| m_chichi.Get(GL_RGBA, GL_UNSIGNED_BYTE, &data[0]); |
| |
| for (GLuint i = 0; i < size; ++i) |
| { |
| const GLuint color = data[i]; |
| |
| if (expected_chichi != color) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "RGBA8[" << i << "]:" << color |
| << tcu::TestLog::EndMessage; |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| /** Prepare code snippet that will set out variables |
| * |
| * @param ignored |
| * @param ignored |
| * @param stage Shader stage |
| * |
| * @return Code that pass in variables to next stage |
| **/ |
| std::string FragmentDataLocationAPITest::getPassSnippet(GLuint /* test_case_index */, |
| Utils::VaryingPassthrough& /* varying_passthrough */, |
| Utils::Shader::STAGES stage) |
| { |
| std::string result; |
| |
| /* Skip for compute shader */ |
| if (Utils::Shader::FRAGMENT != stage) |
| { |
| result = ""; |
| } |
| else |
| { |
| result = "chichi = vec4(0, 0, 1, 1);\n" |
| " goku = vec4(0, 0, 0, 1);\n" |
| " goten = vec4(0, 1, 0, 1);\n" |
| " gohan = vec4(1, 0, 0, 1);\n"; |
| } |
| |
| return result; |
| } |
| |
| /** Get interface of program |
| * |
| * @param ignored |
| * @param program_interface Interface of program |
| * @param ignored |
| **/ |
| void FragmentDataLocationAPITest::getProgramInterface(GLuint /* test_case_index */, |
| Utils::ProgramInterface& program_interface, |
| Utils::VaryingPassthrough& /* varying_passthrough */) |
| { |
| Utils::ShaderInterface& si = program_interface.GetShaderInterface(Utils::Shader::FRAGMENT); |
| const Utils::Type& type = Utils::Type::vec4; |
| |
| /* Locations */ |
| m_goku_location = 2; |
| |
| /* Globals */ |
| si.m_globals = "const uint GOKU_LOCATION = 2;\n"; |
| |
| /* Attributes */ |
| si.Output("goku" /* name */, "layout (location = GOKU_LOCATION)" /* qualifiers */, 0 /* expected_componenet */, |
| m_goku_location /* expected_location */, type /* type */, GL_FALSE /* normalized */, |
| 0u /* n_array_elements */, 0u /* stride */, 0u /* offset */, (GLvoid*)0 /* data */, 0u /* data_size */); |
| |
| si.Output("gohan" /* name */, "" /* qualifiers */, 0 /* expected_componenet */, |
| Utils::Variable::m_automatic_location /* expected_location */, type /* type */, GL_FALSE /* normalized */, |
| 0u /* n_array_elements */, 0u /* stride */, 0u /* offset */, (GLvoid*)0 /* data */, 0u /* data_size */); |
| |
| si.Output("goten" /* name */, "" /* qualifiers */, 0 /* expected_componenet */, |
| m_goten_location /* expected_location */, type /* type */, GL_FALSE /* normalized */, |
| 0u /* n_array_elements */, 0u /* stride */, 0u /* offset */, (GLvoid*)0 /* data */, 0u /* data_size */); |
| |
| si.Output("chichi" /* name */, "" /* qualifiers */, 0 /* expected_componenet */, |
| Utils::Variable::m_automatic_location /* expected_location */, type /* type */, GL_FALSE /* normalized */, |
| 0u /* n_array_elements */, 0u /* stride */, 0u /* offset */, (GLvoid*)0 /* data */, 0u /* data_size */); |
| } |
| |
| /** Selects if "compute" stage is relevant for test |
| * |
| * @param ignored |
| * |
| * @return false |
| **/ |
| bool FragmentDataLocationAPITest::isComputeRelevant(GLuint /* test_case_index */) |
| { |
| return false; |
| } |
| |
| /** Get locations for all outputs with automatic_location |
| * |
| * @param program Program object |
| * @param program_interface Interface of program |
| **/ |
| void FragmentDataLocationAPITest::prepareFragmentDataLoc(Utils::Program& program, |
| Utils::ProgramInterface& program_interface) |
| { |
| /* Bind location of goten */ |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| gl.bindFragDataLocation(program.m_id, m_goten_location, "goten"); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "BindFragDataLocation"); |
| |
| program.Link(gl, program.m_id); |
| |
| /* Prepare locations for gohan and chichi */ |
| TextureTestBase::prepareFragmentDataLoc(program, program_interface); |
| |
| /* Get all locations */ |
| Utils::ShaderInterface& si = program_interface.GetShaderInterface(Utils::Shader::FRAGMENT); |
| |
| Utils::Variable::PtrVector& outputs = si.m_outputs; |
| |
| for (Utils::Variable::PtrVector::iterator it = outputs.begin(); outputs.end() != it; ++it) |
| { |
| const Utils::Variable::Descriptor& desc = (*it)->m_descriptor; |
| |
| if (0 == desc.m_name.compare("gohan")) |
| { |
| m_gohan_location = desc.m_expected_location; |
| } |
| else if (0 == desc.m_name.compare("chichi")) |
| { |
| m_chichi_location = desc.m_expected_location; |
| } |
| |
| /* Locations of goku and goten are fixed */ |
| } |
| } |
| |
| /** Prepare framebuffer with single texture as color attachment |
| * |
| * @param framebuffer Framebuffer |
| * @param color_0_texture Texture that will used as color attachment |
| **/ |
| void FragmentDataLocationAPITest::prepareFramebuffer(Utils::Framebuffer& framebuffer, Utils::Texture& color_0_texture) |
| { |
| /* Let parent prepare its stuff */ |
| TextureTestBase::prepareFramebuffer(framebuffer, color_0_texture); |
| |
| /* Prepare data */ |
| std::vector<GLuint> texture_data; |
| texture_data.resize(m_width * m_height); |
| |
| for (GLuint i = 0; i < texture_data.size(); ++i) |
| { |
| texture_data[i] = 0x20406080; |
| } |
| |
| /* Prepare textures */ |
| m_goku.Init(Utils::Texture::TEX_2D, m_width, m_height, 0, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, &texture_data[0]); |
| |
| m_gohan.Init(Utils::Texture::TEX_2D, m_width, m_height, 0, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, &texture_data[0]); |
| |
| m_goten.Init(Utils::Texture::TEX_2D, m_width, m_height, 0, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, &texture_data[0]); |
| |
| m_chichi.Init(Utils::Texture::TEX_2D, m_width, m_height, 0, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, &texture_data[0]); |
| |
| /* Attach textures to framebuffer */ |
| framebuffer.Bind(); |
| framebuffer.AttachTexture(GL_COLOR_ATTACHMENT0 + m_goku_location, m_goku.m_id, m_width, m_height); |
| framebuffer.AttachTexture(GL_COLOR_ATTACHMENT0 + m_gohan_location, m_gohan.m_id, m_width, m_height); |
| framebuffer.AttachTexture(GL_COLOR_ATTACHMENT0 + m_goten_location, m_goten.m_id, m_width, m_height); |
| framebuffer.AttachTexture(GL_COLOR_ATTACHMENT0 + m_chichi_location, m_chichi.m_id, m_width, m_height); |
| |
| /* Set up drawbuffers */ |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| // The fragment shader can have more than 4 color outputs, but it only care about 4 (goku, gohan, goten, chichi). |
| // We will first initialize all draw buffers to NONE and then set the real value for the 4 outputs we care about |
| GLint maxDrawBuffers = 0; |
| gl.getIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers); |
| |
| std::vector<GLenum> buffers(maxDrawBuffers, GL_NONE); |
| buffers[m_chichi_location] = GLenum(GL_COLOR_ATTACHMENT0 + m_chichi_location); |
| buffers[m_goten_location] = GLenum(GL_COLOR_ATTACHMENT0 + m_goten_location); |
| buffers[m_goku_location] = GLenum(GL_COLOR_ATTACHMENT0 + m_goku_location); |
| buffers[m_gohan_location] = GLenum(GL_COLOR_ATTACHMENT0 + m_gohan_location); |
| |
| gl.drawBuffers(maxDrawBuffers, buffers.data()); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "DrawBuffers"); |
| } |
| |
| /** Constructor |
| * |
| * @param context Test framework context |
| **/ |
| XFBInputTest::XFBInputTest(deqp::Context& context) |
| : NegativeTestBase(context, "xfb_input", |
| "Test verifies that compiler reports error when xfb qualifiers are used with input") |
| { |
| } |
| |
| /** Source for given test case and stage |
| * |
| * @param test_case_index Index of test case |
| * @param stage Shader stage |
| * |
| * @return Shader source |
| **/ |
| std::string XFBInputTest::getShaderSource(GLuint test_case_index, Utils::Shader::STAGES stage) |
| { |
| #if DEBUG_NEG_REMOVE_ERROR |
| static const GLchar* buffer_var_definition = "/* layout (xfb_buffer = 2) */ in vec4 gohanARRAY;\n"; |
| static const GLchar* offset_var_definition = "/* layout (xfb_offset = 16) */ in vec4 gohanARRAY;\n"; |
| static const GLchar* stride_var_definition = "/* layout (xfb_stride = 32) */ in vec4 gohanARRAY;\n"; |
| #else |
| static const GLchar* buffer_var_definition = "layout (xfb_buffer = 2) in vec4 gohanARRAY;\n"; |
| static const GLchar* offset_var_definition = "layout (xfb_offset = 16) in vec4 gohanARRAY;\n"; |
| static const GLchar* stride_var_definition = "layout (xfb_stride = 32) in vec4 gohanARRAY;\n"; |
| #endif /* DEBUG_NEG_REMOVE_ERROR */ |
| static const GLchar* fs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 gs_fs;\n" |
| "out vec4 fs_out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " fs_out = gs_fs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* fs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 gs_fs;\n" |
| "out vec4 fs_out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = gs_fs;\n" |
| "\n" |
| " fs_out = result;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* gs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| "in vec4 tes_gs[];\n" |
| "out vec4 gs_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = tes_gs[0];\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| static const GLchar* gs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 tes_gs[];\n" |
| "out vec4 gs_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = tes_gs[0];\n" |
| "\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tcs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "in vec4 vs_tcs[];\n" |
| "out vec4 tcs_tes[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| "\n" |
| " tcs_tes[gl_InvocationID] = vs_tcs[gl_InvocationID];\n" |
| "\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tcs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 vs_tcs[];\n" |
| "out vec4 tcs_tes[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = vs_tcs[gl_InvocationID];\n" |
| "\n" |
| " tcs_tes[gl_InvocationID] = result;\n" |
| "\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tes = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(isolines, point_mode) in;\n" |
| "\n" |
| "in vec4 tcs_tes[];\n" |
| "out vec4 tes_gs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " tes_gs = tcs_tes[0];\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tes_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(isolines, point_mode) in;\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 tcs_tes[];\n" |
| "out vec4 tes_gs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = tcs_tes[0];\n" |
| "\n" |
| " tes_gs += result;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 vs_tcs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vs_tcs = in_vs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 vs_tcs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = in_vs;\n" |
| "\n" |
| " vs_tcs += result;\n" |
| "}\n" |
| "\n"; |
| |
| std::string source; |
| testCase& test_case = m_test_cases[test_case_index]; |
| |
| if (test_case.m_stage == stage) |
| { |
| const GLchar* array = ""; |
| size_t position = 0; |
| const GLchar* var_definition = 0; |
| |
| switch (test_case.m_qualifier) |
| { |
| case BUFFER: |
| var_definition = buffer_var_definition; |
| break; |
| case OFFSET: |
| var_definition = offset_var_definition; |
| break; |
| case STRIDE: |
| var_definition = stride_var_definition; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs_tested; |
| break; |
| case Utils::Shader::GEOMETRY: |
| source = gs_tested; |
| array = "[]"; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| source = tcs_tested; |
| array = "[]"; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| source = tes_tested; |
| array = "[]"; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs_tested; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| Utils::replaceToken("VAR_DEFINITION", position, var_definition, source); |
| position = 0; |
| Utils::replaceToken("ARRAY", position, array, source); |
| } |
| else |
| { |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs; |
| break; |
| case Utils::Shader::GEOMETRY: |
| source = gs; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| source = tcs; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| source = tes; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| } |
| |
| return source; |
| } |
| |
| /** Get description of test case |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return Test case description |
| **/ |
| std::string XFBInputTest::getTestCaseName(GLuint test_case_index) |
| { |
| std::stringstream stream; |
| testCase& test_case = m_test_cases[test_case_index]; |
| |
| stream << "Stage: " << Utils::Shader::GetStageName(test_case.m_stage) << ", qualifier: "; |
| |
| switch (test_case.m_qualifier) |
| { |
| case BUFFER: |
| stream << "xfb_buffer"; |
| break; |
| case OFFSET: |
| stream << "xfb_offset"; |
| break; |
| case STRIDE: |
| stream << "xfb_stride"; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| return stream.str(); |
| } |
| |
| /** Get number of test cases |
| * |
| * @return Number of test cases |
| **/ |
| GLuint XFBInputTest::getTestCaseNumber() |
| { |
| return static_cast<GLuint>(m_test_cases.size()); |
| } |
| |
| /** Selects if "compute" stage is relevant for test |
| * |
| * @param ignored |
| * |
| * @return false |
| **/ |
| bool XFBInputTest::isComputeRelevant(GLuint /* test_case_index */) |
| { |
| return false; |
| } |
| |
| /** Prepare all test cases |
| * |
| **/ |
| void XFBInputTest::testInit() |
| { |
| for (GLuint qualifier = 0; qualifier < QUALIFIERS_MAX; ++qualifier) |
| { |
| for (GLuint stage = 0; stage < Utils::Shader::STAGE_MAX; ++stage) |
| { |
| if (Utils::Shader::COMPUTE == stage) |
| { |
| continue; |
| } |
| |
| testCase test_case = { (QUALIFIERS)qualifier, (Utils::Shader::STAGES)stage }; |
| |
| m_test_cases.push_back(test_case); |
| } |
| } |
| } |
| |
| /* Constants used by XFBAllStagesTest */ |
| const GLuint XFBAllStagesTest::m_gs_index = 3; |
| |
| /** Constructor |
| * |
| * @param context Test context |
| **/ |
| XFBAllStagesTest::XFBAllStagesTest(deqp::Context& context) |
| : BufferTestBase(context, "xfb_all_stages", |
| "Test verifies that only last stage in vertex processing can output to transform feedback") |
| { |
| /* Nothing to be done here */ |
| } |
| |
| /** Get descriptors of buffers necessary for test |
| * |
| * @param ignored |
| * @param out_descriptors Descriptors of buffers used by test |
| **/ |
| void XFBAllStagesTest::getBufferDescriptors(glw::GLuint /* test_case_index */, |
| bufferDescriptor::Vector& out_descriptors) |
| { |
| static const GLuint n_stages = 4; |
| const Utils::Type& vec4 = Utils::Type::vec4; |
| |
| /* Data */ |
| tcu::Vec4 sum; |
| |
| /* Test uses single uniform and xfb per stage + uniform for fragment shader */ |
| out_descriptors.resize(n_stages * 2 + 1); |
| |
| /* */ |
| for (GLuint i = 0; i < n_stages; ++i) |
| { |
| /* Get references */ |
| bufferDescriptor& uniform = out_descriptors[i + 0]; |
| bufferDescriptor& xfb = out_descriptors[i + n_stages]; |
| |
| /* Index */ |
| uniform.m_index = i; |
| xfb.m_index = i; |
| |
| /* Target */ |
| uniform.m_target = Utils::Buffer::Uniform; |
| xfb.m_target = Utils::Buffer::Transform_feedback; |
| |
| /* Data */ |
| const tcu::Vec4 var(Utils::GetRandFloat(), Utils::GetRandFloat(), Utils::GetRandFloat(), Utils::GetRandFloat()); |
| |
| sum += var; |
| |
| uniform.m_initial_data.resize(vec4.GetSize()); |
| memcpy(&uniform.m_initial_data[0], var.getPtr(), vec4.GetSize()); |
| |
| xfb.m_initial_data = vec4.GenerateDataPacked(); |
| |
| if (m_gs_index != i) |
| { |
| xfb.m_expected_data = xfb.m_initial_data; |
| } |
| else |
| { |
| xfb.m_expected_data.resize(vec4.GetSize()); |
| memcpy(&xfb.m_expected_data[0], sum.getPtr(), vec4.GetSize()); |
| } |
| } |
| |
| /* FS */ |
| { |
| /* Get reference */ |
| bufferDescriptor& uniform = out_descriptors[n_stages * 2]; |
| |
| /* Index */ |
| uniform.m_index = n_stages; |
| |
| /* Target */ |
| uniform.m_target = Utils::Buffer::Uniform; |
| |
| /* Data */ |
| const tcu::Vec4 var(Utils::GetRandFloat(), Utils::GetRandFloat(), Utils::GetRandFloat(), Utils::GetRandFloat()); |
| |
| uniform.m_initial_data.resize(vec4.GetSize()); |
| memcpy(&uniform.m_initial_data[0], var.getPtr(), vec4.GetSize()); |
| } |
| } |
| |
| /** Get body of main function for given shader stage |
| * |
| * @param ignored |
| * @param stage Shader stage |
| * @param out_assignments Set to empty |
| * @param out_calculations Set to empty |
| **/ |
| void XFBAllStagesTest::getShaderBody(glw::GLuint /* test_case_index */, Utils::Shader::STAGES stage, |
| std::string& out_assignments, std::string& out_calculations) |
| { |
| out_calculations = ""; |
| |
| static const GLchar* vs = " vs_tcs = uni_vs;\n"; |
| static const GLchar* tcs = " tcs_tes[gl_InvocationID] = uni_tcs + vs_tcs[gl_InvocationID];\n"; |
| static const GLchar* tes = " tes_gs = uni_tes + tcs_tes[0];\n"; |
| static const GLchar* gs = " gs_fs = uni_gs + tes_gs[0];\n"; |
| static const GLchar* fs = " fs_out = uni_fs + gs_fs;\n"; |
| |
| const GLchar* assignments = 0; |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| assignments = fs; |
| break; |
| case Utils::Shader::GEOMETRY: |
| assignments = gs; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| assignments = tcs; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| assignments = tes; |
| break; |
| case Utils::Shader::VERTEX: |
| assignments = vs; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| out_assignments = assignments; |
| } |
| |
| /** Get interface of shader |
| * |
| * @param ignored |
| * @param stage Shader stage |
| * @param out_interface Set to "" |
| **/ |
| void XFBAllStagesTest::getShaderInterface(glw::GLuint /* test_case_index */, Utils::Shader::STAGES stage, |
| std::string& out_interface) |
| { |
| static const GLchar* vs = "layout(xfb_buffer = 0, xfb_offset = 0) out vec4 vs_tcs;\n" |
| "layout(binding = 0) uniform vs_block {\n" |
| " vec4 uni_vs;\n" |
| "};\n"; |
| static const GLchar* tcs = " in vec4 vs_tcs[];\n" |
| "layout(xfb_buffer = 1, xfb_offset = 0) out vec4 tcs_tes[1];\n" |
| "layout(binding = 1) uniform tcs_block {\n" |
| " vec4 uni_tcs;\n" |
| "};\n"; |
| static const GLchar* tes = " in vec4 tcs_tes[];\n" |
| "layout(xfb_buffer = 2, xfb_offset = 0) out vec4 tes_gs;\n" |
| "layout(binding = 2) uniform tes_block {\n" |
| " vec4 uni_tes;\n" |
| "};\n"; |
| static const GLchar* gs = " in vec4 tes_gs[];\n" |
| "layout(xfb_buffer = 3, xfb_offset = 0) out vec4 gs_fs;\n" |
| "layout(binding = 3) uniform gs_block {\n" |
| " vec4 uni_gs;\n" |
| "};\n"; |
| static const GLchar* fs = " in vec4 gs_fs;\n" |
| " out vec4 fs_out;\n" |
| "layout(binding = 4) uniform fs_block {\n" |
| " vec4 uni_fs;\n" |
| "};\n"; |
| |
| const GLchar* interface = 0; |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| interface = fs; |
| break; |
| case Utils::Shader::GEOMETRY: |
| interface = gs; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| interface = tcs; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| interface = tes; |
| break; |
| case Utils::Shader::VERTEX: |
| interface = vs; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| out_interface = interface; |
| } |
| |
| /* Constants used by XFBStrideOfEmptyListTest */ |
| const GLuint XFBStrideOfEmptyListTest::m_stride = 64; |
| |
| /** Constructor |
| * |
| * @param context Test context |
| **/ |
| XFBStrideOfEmptyListTest::XFBStrideOfEmptyListTest(deqp::Context& context) |
| : BufferTestBase( |
| context, "xfb_stride_of_empty_list", |
| "Test verifies correct behavior when xfb_stride qualifier is specified but no xfb_offset is specified") |
| { |
| /* Nothing to be done here */ |
| } |
| |
| /** Execute drawArrays for single vertex |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return true if proper error is reported |
| **/ |
| bool XFBStrideOfEmptyListTest::executeDrawCall(bool /* tesEnabled */, GLuint test_case_index) |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| bool result = true; |
| |
| /* Draw */ |
| gl.disable(GL_RASTERIZER_DISCARD); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Disable"); |
| |
| gl.beginTransformFeedback(GL_POINTS); |
| GLenum error = gl.getError(); |
| switch (test_case_index) |
| { |
| case VALID: |
| if (GL_NO_ERROR != error) |
| { |
| gl.endTransformFeedback(); |
| GLU_EXPECT_NO_ERROR(error, "BeginTransformFeedback"); |
| } |
| |
| gl.drawArrays(GL_PATCHES, 0 /* first */, 1 /* count */); |
| error = gl.getError(); |
| |
| gl.endTransformFeedback(); |
| GLU_EXPECT_NO_ERROR(error, "DrawArrays"); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "EndTransformFeedback"); |
| |
| break; |
| |
| case FIRST_MISSING: |
| if (GL_NO_ERROR == error) |
| { |
| gl.endTransformFeedback(); |
| } |
| |
| if (GL_INVALID_OPERATION != error) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "XFB at index 0, that is written by GS, is missing. It was expected that " |
| "INVALID_OPERATION will generated by BeginTransformFeedback. Got: " |
| << glu::getErrorStr(error) << tcu::TestLog::EndMessage; |
| |
| result = false; |
| } |
| |
| break; |
| |
| case SECOND_MISSING: |
| if (GL_NO_ERROR != error) |
| { |
| gl.endTransformFeedback(); |
| GLU_EXPECT_NO_ERROR(error, "BeginTransformFeedback"); |
| } |
| |
| gl.drawArrays(GL_PATCHES, 0 /* first */, 1 /* count */); |
| error = gl.getError(); |
| |
| gl.endTransformFeedback(); |
| GLU_EXPECT_NO_ERROR(error, "DrawArrays"); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "EndTransformFeedback"); |
| |
| break; |
| } |
| |
| /* Done */ |
| return result; |
| } |
| |
| /** Get descriptors of buffers necessary for test |
| * |
| * @param test_case_index Index of test case |
| * @param out_descriptors Descriptors of buffers used by test |
| **/ |
| void XFBStrideOfEmptyListTest::getBufferDescriptors(glw::GLuint test_case_index, |
| bufferDescriptor::Vector& out_descriptors) |
| { |
| switch (test_case_index) |
| { |
| case VALID: |
| { |
| /* Test needs single uniform and two xfbs */ |
| out_descriptors.resize(3); |
| |
| /* Get references */ |
| bufferDescriptor& uniform = out_descriptors[0]; |
| bufferDescriptor& xfb_0 = out_descriptors[1]; |
| bufferDescriptor& xfb_1 = out_descriptors[2]; |
| |
| /* Index */ |
| uniform.m_index = 0; |
| xfb_0.m_index = 0; |
| xfb_1.m_index = 1; |
| |
| /* Target */ |
| uniform.m_target = Utils::Buffer::Uniform; |
| xfb_0.m_target = Utils::Buffer::Transform_feedback; |
| xfb_1.m_target = Utils::Buffer::Transform_feedback; |
| |
| /* Data */ |
| uniform.m_initial_data = Utils::Type::vec4.GenerateDataPacked(); |
| |
| xfb_0.m_initial_data = Utils::Type::vec4.GenerateDataPacked(); |
| xfb_0.m_expected_data = uniform.m_initial_data; |
| |
| /* Data, contents are the same as no modification is expected */ |
| xfb_1.m_initial_data.resize(m_stride); |
| xfb_1.m_expected_data.resize(m_stride); |
| |
| for (GLuint i = 0; i < m_stride; ++i) |
| { |
| xfb_1.m_initial_data[0] = (glw::GLubyte)i; |
| xfb_1.m_expected_data[0] = (glw::GLubyte)i; |
| } |
| } |
| |
| break; |
| |
| case FIRST_MISSING: |
| { |
| /* Test needs single uniform and two xfbs */ |
| out_descriptors.resize(2); |
| |
| /* Get references */ |
| bufferDescriptor& uniform = out_descriptors[0]; |
| bufferDescriptor& xfb_1 = out_descriptors[1]; |
| |
| /* Index */ |
| uniform.m_index = 0; |
| xfb_1.m_index = 1; |
| |
| /* Target */ |
| uniform.m_target = Utils::Buffer::Uniform; |
| xfb_1.m_target = Utils::Buffer::Transform_feedback; |
| |
| /* Data */ |
| uniform.m_initial_data = Utils::Type::vec4.GenerateDataPacked(); |
| |
| /* Draw call will not be executed, contents does not matter */ |
| xfb_1.m_initial_data.resize(m_stride); |
| } |
| |
| break; |
| |
| case SECOND_MISSING: |
| { |
| /* Test needs single uniform and two xfbs */ |
| out_descriptors.resize(2); |
| |
| /* Get references */ |
| bufferDescriptor& uniform = out_descriptors[0]; |
| bufferDescriptor& xfb_0 = out_descriptors[1]; |
| |
| /* Index */ |
| uniform.m_index = 0; |
| xfb_0.m_index = 0; |
| |
| /* Target */ |
| uniform.m_target = Utils::Buffer::Uniform; |
| xfb_0.m_target = Utils::Buffer::Transform_feedback; |
| |
| /* Data */ |
| uniform.m_initial_data = Utils::Type::vec4.GenerateDataPacked(); |
| |
| xfb_0.m_initial_data = Utils::Type::vec4.GenerateDataPacked(); |
| xfb_0.m_expected_data = uniform.m_initial_data; |
| } |
| |
| break; |
| } |
| } |
| |
| /** Get body of main function for given shader stage |
| * |
| * @param ignored |
| * @param stage Shader stage |
| * @param out_assignments Set to empty |
| * @param out_calculations Set to empty |
| **/ |
| void XFBStrideOfEmptyListTest::getShaderBody(GLuint /* test_case_index */, Utils::Shader::STAGES stage, |
| std::string& out_assignments, std::string& out_calculations) |
| { |
| out_calculations = ""; |
| |
| static const GLchar* gs = " gs_fs = uni_gs;\n"; |
| static const GLchar* fs = " fs_out = vec4(gs_fs);\n"; |
| |
| const GLchar* assignments = ""; |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| assignments = fs; |
| break; |
| case Utils::Shader::GEOMETRY: |
| assignments = gs; |
| break; |
| default: |
| break; |
| } |
| |
| out_assignments = assignments; |
| } |
| |
| /** Get interface of shader |
| * |
| * @param ignored |
| * @param stage Shader stage |
| * @param out_interface Set to "" |
| **/ |
| void XFBStrideOfEmptyListTest::getShaderInterface(GLuint /* test_case_index */, Utils::Shader::STAGES stage, |
| std::string& out_interface) |
| { |
| static const GLchar* gs = "layout (xfb_buffer = 0, xfb_offset = 0) out vec4 gs_fs;\n" |
| "layout (xfb_buffer = 1, xfb_stride = 64) out;\n" |
| "\n" |
| "layout (binding = 0) uniform gs_block {\n" |
| " vec4 uni_gs;\n" |
| "};\n"; |
| static const GLchar* fs = "in vec4 gs_fs;\n" |
| "out vec4 fs_out;\n"; |
| |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| out_interface = fs; |
| break; |
| case Utils::Shader::GEOMETRY: |
| out_interface = gs; |
| break; |
| default: |
| out_interface = ""; |
| return; |
| } |
| } |
| |
| /** Returns buffer details in human readable form. |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return Case description |
| **/ |
| std::string XFBStrideOfEmptyListTest::getTestCaseName(GLuint test_case_index) |
| { |
| std::string result; |
| |
| switch (test_case_index) |
| { |
| case VALID: |
| result = "Valid case"; |
| break; |
| case FIRST_MISSING: |
| result = "Missing xfb at index 0"; |
| break; |
| case SECOND_MISSING: |
| result = "Missing xfb at index 1"; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| return result; |
| } |
| |
| /** Get number of test cases |
| * |
| * @return 3 |
| **/ |
| GLuint XFBStrideOfEmptyListTest::getTestCaseNumber() |
| { |
| return 3; |
| } |
| |
| /* Constants used by XFBStrideOfEmptyListTest */ |
| const GLuint XFBStrideOfEmptyListAndAPITest::m_stride = 64; |
| |
| /** Constructor |
| * |
| * @param context Test context |
| **/ |
| XFBStrideOfEmptyListAndAPITest::XFBStrideOfEmptyListAndAPITest(deqp::Context& context) |
| : BufferTestBase(context, "xfb_stride_of_empty_list_and_api", |
| "Test verifies that xfb_stride qualifier is not overriden by API") |
| { |
| /* Nothing to be done here */ |
| } |
| |
| /** Execute drawArrays for single vertex |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return true if proper error is reported |
| **/ |
| bool XFBStrideOfEmptyListAndAPITest::executeDrawCall(bool /* tesEnabled */, GLuint test_case_index) |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| bool result = true; |
| |
| /* Draw */ |
| gl.disable(GL_RASTERIZER_DISCARD); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Disable"); |
| |
| gl.beginTransformFeedback(GL_POINTS); |
| GLenum error = gl.getError(); |
| switch (test_case_index) |
| { |
| case VALID: |
| if (GL_NO_ERROR != error) |
| { |
| gl.endTransformFeedback(); |
| GLU_EXPECT_NO_ERROR(error, "BeginTransformFeedback"); |
| } |
| |
| gl.drawArrays(GL_PATCHES, 0 /* first */, 1 /* count */); |
| error = gl.getError(); |
| |
| gl.endTransformFeedback(); |
| GLU_EXPECT_NO_ERROR(error, "DrawArrays"); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "EndTransformFeedback"); |
| |
| break; |
| |
| case FIRST_MISSING: |
| if (GL_NO_ERROR != error) |
| { |
| gl.endTransformFeedback(); |
| GLU_EXPECT_NO_ERROR(error, "BeginTransformFeedback"); |
| } |
| |
| gl.drawArrays(GL_PATCHES, 0 /* first */, 1 /* count */); |
| error = gl.getError(); |
| |
| gl.endTransformFeedback(); |
| GLU_EXPECT_NO_ERROR(error, "DrawArrays"); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "EndTransformFeedback"); |
| |
| break; |
| |
| case SECOND_MISSING: |
| if (GL_NO_ERROR == error) |
| { |
| gl.endTransformFeedback(); |
| } |
| |
| if (GL_INVALID_OPERATION != error) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "XFB at index 1, that is declared as empty, is missing. It was expected " |
| "that INVALID_OPERATION will generated by BeginTransformFeedback. Got: " |
| << glu::getErrorStr(error) << tcu::TestLog::EndMessage; |
| |
| result = false; |
| } |
| |
| break; |
| } |
| |
| /* Done */ |
| return result; |
| } |
| |
| /** Get descriptors of buffers necessary for test |
| * |
| * @param test_case_index Index of test case |
| * @param out_descriptors Descriptors of buffers used by test |
| **/ |
| void XFBStrideOfEmptyListAndAPITest::getBufferDescriptors(glw::GLuint test_case_index, |
| bufferDescriptor::Vector& out_descriptors) |
| { |
| switch (test_case_index) |
| { |
| case VALID: |
| { |
| /* Test needs single uniform and two xfbs */ |
| out_descriptors.resize(3); |
| |
| /* Get references */ |
| bufferDescriptor& uniform = out_descriptors[0]; |
| bufferDescriptor& xfb_0 = out_descriptors[1]; |
| bufferDescriptor& xfb_1 = out_descriptors[2]; |
| |
| /* Index */ |
| uniform.m_index = 0; |
| xfb_0.m_index = 0; |
| xfb_1.m_index = 1; |
| |
| /* Target */ |
| uniform.m_target = Utils::Buffer::Uniform; |
| xfb_0.m_target = Utils::Buffer::Transform_feedback; |
| xfb_1.m_target = Utils::Buffer::Transform_feedback; |
| |
| /* Data */ |
| uniform.m_initial_data = Utils::Type::vec4.GenerateDataPacked(); |
| |
| /* Data, contents are the same as no modification is expected */ |
| xfb_0.m_initial_data.resize(m_stride); |
| xfb_0.m_expected_data.resize(m_stride); |
| |
| for (GLuint i = 0; i < m_stride; ++i) |
| { |
| xfb_0.m_initial_data[0] = (glw::GLubyte)i; |
| xfb_0.m_expected_data[0] = (glw::GLubyte)i; |
| } |
| |
| xfb_1.m_initial_data = Utils::Type::vec4.GenerateDataPacked(); |
| xfb_1.m_expected_data = uniform.m_initial_data; |
| } |
| |
| break; |
| |
| case FIRST_MISSING: |
| { |
| /* Test needs single uniform and two xfbs */ |
| out_descriptors.resize(2); |
| |
| /* Get references */ |
| bufferDescriptor& uniform = out_descriptors[0]; |
| bufferDescriptor& xfb_1 = out_descriptors[1]; |
| |
| /* Index */ |
| uniform.m_index = 0; |
| xfb_1.m_index = 1; |
| |
| /* Target */ |
| uniform.m_target = Utils::Buffer::Uniform; |
| xfb_1.m_target = Utils::Buffer::Transform_feedback; |
| |
| /* Data */ |
| uniform.m_initial_data = Utils::Type::vec4.GenerateDataPacked(); |
| |
| /* Data, contents are the same as no modification is expected */ |
| xfb_1.m_initial_data = Utils::Type::vec4.GenerateDataPacked(); |
| xfb_1.m_expected_data = uniform.m_initial_data; |
| } |
| |
| break; |
| |
| case SECOND_MISSING: |
| { |
| /* Test needs single uniform and two xfbs */ |
| out_descriptors.resize(2); |
| |
| /* Get references */ |
| bufferDescriptor& uniform = out_descriptors[0]; |
| bufferDescriptor& xfb_0 = out_descriptors[1]; |
| |
| /* Index */ |
| uniform.m_index = 0; |
| xfb_0.m_index = 0; |
| |
| /* Target */ |
| uniform.m_target = Utils::Buffer::Uniform; |
| xfb_0.m_target = Utils::Buffer::Transform_feedback; |
| |
| /* Data */ |
| uniform.m_initial_data = Utils::Type::vec4.GenerateDataPacked(); |
| |
| /* Draw call will not be executed, contents does not matter */ |
| xfb_0.m_initial_data = Utils::Type::vec4.GenerateDataPacked(); |
| } |
| |
| break; |
| } |
| } |
| |
| /** Get list of names of varyings that will be registered with TransformFeedbackVaryings |
| * |
| * @param ignored |
| * @param captured_varyings Vector of varying names to be captured |
| **/ |
| void XFBStrideOfEmptyListAndAPITest::getCapturedVaryings(glw::GLuint /* test_case_index */, |
| Utils::Program::NameVector& captured_varyings, |
| GLint* xfb_components) |
| { |
| captured_varyings.push_back("gs_fs1"); |
| captured_varyings.push_back("gs_fs2"); |
| *xfb_components = 4; |
| } |
| |
| /** Get body of main function for given shader stage |
| * |
| * @param ignored |
| * @param stage Shader stage |
| * @param out_assignments Set to empty |
| * @param out_calculations Set to empty |
| **/ |
| void XFBStrideOfEmptyListAndAPITest::getShaderBody(GLuint /* test_case_index */, Utils::Shader::STAGES stage, |
| std::string& out_assignments, std::string& out_calculations) |
| { |
| out_calculations = ""; |
| |
| static const GLchar* gs = " gs_fs1 = -uni_gs;\n" |
| " gs_fs2 = uni_gs;\n"; |
| static const GLchar* fs = " fs_out = vec4(gs_fs2);\n"; |
| |
| const GLchar* assignments = ""; |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| assignments = fs; |
| break; |
| case Utils::Shader::GEOMETRY: |
| assignments = gs; |
| break; |
| default: |
| break; |
| } |
| |
| out_assignments = assignments; |
| } |
| |
| /** Get interface of shader |
| * |
| * @param ignored |
| * @param stage Shader stage |
| * @param out_interface Set to "" |
| **/ |
| void XFBStrideOfEmptyListAndAPITest::getShaderInterface(GLuint /* test_case_index */, Utils::Shader::STAGES stage, |
| std::string& out_interface) |
| { |
| static const GLchar* gs = "layout (xfb_buffer = 0, xfb_stride = 64) out vec4 gs_fs1;\n" |
| "layout (xfb_buffer = 1, xfb_offset = 0) out vec4 gs_fs2;\n" |
| "\n" |
| "layout(binding = 0) uniform gs_block {\n" |
| " vec4 uni_gs;\n" |
| "};\n"; |
| static const GLchar* fs = "in vec4 gs_fs2;\n" |
| "out vec4 fs_out;\n"; |
| |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| out_interface = fs; |
| break; |
| case Utils::Shader::GEOMETRY: |
| out_interface = gs; |
| break; |
| default: |
| out_interface = ""; |
| return; |
| } |
| } |
| |
| /** Returns buffer details in human readable form. |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return Case description |
| **/ |
| std::string XFBStrideOfEmptyListAndAPITest::getTestCaseName(GLuint test_case_index) |
| { |
| std::string result; |
| |
| switch (test_case_index) |
| { |
| case VALID: |
| result = "Valid case"; |
| break; |
| case FIRST_MISSING: |
| result = "Missing xfb at index 0"; |
| break; |
| case SECOND_MISSING: |
| result = "Missing xfb at index 1"; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| return result; |
| } |
| |
| /** Get number of test cases |
| * |
| * @return 2 |
| **/ |
| GLuint XFBStrideOfEmptyListAndAPITest::getTestCaseNumber() |
| { |
| return 3; |
| } |
| |
| /** Constructor |
| * |
| * @param context Test framework context |
| **/ |
| XFBTooSmallStrideTest::XFBTooSmallStrideTest(deqp::Context& context) |
| : NegativeTestBase(context, "xfb_too_small_stride", |
| "Test verifies that compiler reports error when xfb_stride sets not enough space") |
| { |
| } |
| |
| /** Source for given test case and stage |
| * |
| * @param test_case_index Index of test case |
| * @param stage Shader stage |
| * |
| * @return Shader source |
| **/ |
| std::string XFBTooSmallStrideTest::getShaderSource(GLuint test_case_index, Utils::Shader::STAGES stage) |
| { |
| #if DEBUG_NEG_REMOVE_ERROR |
| static const GLchar* array_var_definition = "layout (xfb_buffer = 0 /*, xfb_stride = 32 */ ) out;\n" |
| #else |
| static const GLchar* array_var_definition = "layout (xfb_buffer = 0, xfb_stride = 32) out;\n" |
| #endif /* DEBUG_NEG_REMOVE_ERROR */ |
| "\n" |
| "layout (xfb_offset = 16) out vec4 gohan[4];\n"; |
| #if DEBUG_NEG_REMOVE_ERROR |
| static const GLchar* block_var_definition = "layout (xfb_buffer = 0 /*, xfb_stride = 32 */ ) out;\n" |
| #else |
| static const GLchar* block_var_definition = "layout (xfb_buffer = 0, xfb_stride = 32) out;\n" |
| #endif /* DEBUG_NEG_REMOVE_ERROR */ |
| "\n" |
| "layout (xfb_offset = 0) out Goku {\n" |
| " vec4 gohan;\n" |
| " vec4 goten;\n" |
| " vec4 chichi;\n" |
| "} goku;\n"; |
| #if DEBUG_NEG_REMOVE_ERROR |
| static const GLchar* offset_var_definition = "layout (xfb_buffer = 0 /*, xfb_stride = 40 */ ) out;\n" |
| #else |
| static const GLchar* offset_var_definition = "layout (xfb_buffer = 0, xfb_stride = 40) out;\n" |
| #endif /* DEBUG_NEG_REMOVE_ERROR */ |
| "\n" |
| "layout (xfb_offset = 32) out vec4 gohan;\n"; |
| // The test considers gohan overflows the buffer 0, but according to spec, it is valid to declare the variable with qualifier "layout (xfb_offset = 16, xfb_stride = 32) out vec4 gohan;" |
| // To make the shader failed to compile, change xfb_stride to a value that is smaller than 32 |
| #if DEBUG_NEG_REMOVE_ERROR |
| static const GLchar* stride_var_definition = "layout (xfb_buffer = 0 /*, xfb_stride = 28 */ ) out;\n" |
| "\n" |
| "layout (xfb_offset = 16 /*, xfb_stride = 28 */ ) out vec4 gohan;\n"; |
| #else |
| static const GLchar* stride_var_definition = "layout (xfb_buffer = 0, xfb_stride = 28) out;\n" |
| "\n" |
| "layout (xfb_offset = 16, xfb_stride = 28) out vec4 gohan;\n"; |
| #endif /* DEBUG_NEG_REMOVE_ERROR */ |
| static const GLchar* array_use = " gohan[0] = result / 2;\n" |
| " gohan[1] = result / 4;\n" |
| " gohan[2] = result / 6;\n" |
| " gohan[3] = result / 8;\n"; |
| static const GLchar* block_use = " goku.gohan = result / 2;\n" |
| " goku.goten = result / 4;\n" |
| " goku.chichi = result / 6;\n"; |
| static const GLchar* output_use = "gohan = result / 4;\n"; |
| static const GLchar* fs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 any_fs;\n" |
| "out vec4 fs_out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " fs_out = any_fs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* gs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 vs_any[];\n" |
| "out vec4 any_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = vs_any[0];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " any_fs = result;\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " any_fs = result;\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| " any_fs = result;\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " any_fs = result;\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tcs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "in vec4 vs_any[];\n" |
| "out vec4 tcs_tes[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| "\n" |
| " tcs_tes[gl_InvocationID] = vs_any[gl_InvocationID];\n" |
| "\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tes_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(isolines, point_mode) in;\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 tcs_tes[];\n" |
| "out vec4 any_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = tcs_tes[0];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " any_fs += result;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 vs_any;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vs_any = in_vs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 any_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = in_vs;\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " any_fs += result;\n" |
| "}\n" |
| "\n"; |
| |
| std::string source; |
| testCase& test_case = m_test_cases[test_case_index]; |
| |
| if (test_case.m_stage == stage) |
| { |
| size_t position = 0; |
| const GLchar* var_definition = 0; |
| const GLchar* var_use = 0; |
| |
| switch (test_case.m_case) |
| { |
| case OFFSET: |
| var_definition = offset_var_definition; |
| var_use = output_use; |
| break; |
| case STRIDE: |
| var_definition = stride_var_definition; |
| var_use = output_use; |
| break; |
| case BLOCK: |
| var_definition = block_var_definition; |
| var_use = block_use; |
| break; |
| case ARRAY: |
| var_definition = array_var_definition; |
| var_use = array_use; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| switch (stage) |
| { |
| case Utils::Shader::GEOMETRY: |
| source = gs_tested; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| source = tes_tested; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs_tested; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| Utils::replaceToken("VAR_DEFINITION", position, var_definition, source); |
| position = 0; |
| Utils::replaceToken("VARIABLE_USE", position, var_use, source); |
| } |
| else |
| { |
| switch (test_case.m_stage) |
| { |
| case Utils::Shader::GEOMETRY: |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs; |
| break; |
| default: |
| source = ""; |
| } |
| break; |
| case Utils::Shader::TESS_EVAL: |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| source = tcs; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs; |
| break; |
| default: |
| source = ""; |
| } |
| break; |
| case Utils::Shader::VERTEX: |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs; |
| break; |
| default: |
| source = ""; |
| } |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| break; |
| } |
| } |
| |
| return source; |
| } |
| |
| /** Get description of test case |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return Test case description |
| **/ |
| std::string XFBTooSmallStrideTest::getTestCaseName(GLuint test_case_index) |
| { |
| std::stringstream stream; |
| testCase& test_case = m_test_cases[test_case_index]; |
| |
| stream << "Stage: " << Utils::Shader::GetStageName(test_case.m_stage) << ", case: "; |
| |
| switch (test_case.m_case) |
| { |
| case OFFSET: |
| stream << "buffer stride: 40, vec4 offset: 32"; |
| break; |
| case STRIDE: |
| stream << "buffer stride: 32, vec4 off 16 stride: 32"; |
| break; |
| case BLOCK: |
| stream << "buffer stride: 32, block 3xvec4 offset 0"; |
| break; |
| case ARRAY: |
| stream << "buffer stride: 32, vec4[4] offset 16"; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| return stream.str(); |
| } |
| |
| /** Get number of test cases |
| * |
| * @return Number of test cases |
| **/ |
| GLuint XFBTooSmallStrideTest::getTestCaseNumber() |
| { |
| return static_cast<GLuint>(m_test_cases.size()); |
| } |
| |
| /** Selects if "compute" stage is relevant for test |
| * |
| * @param ignored |
| * |
| * @return false |
| **/ |
| bool XFBTooSmallStrideTest::isComputeRelevant(GLuint /* test_case_index */) |
| { |
| return false; |
| } |
| |
| /** Prepare all test cases |
| * |
| **/ |
| void XFBTooSmallStrideTest::testInit() |
| { |
| for (GLuint c = 0; c < CASE_MAX; ++c) |
| { |
| for (GLuint stage = 0; stage < Utils::Shader::STAGE_MAX; ++stage) |
| { |
| /* |
| It is invalid to define transform feedback output in TCS, according to spec: |
| The data captured in transform feedback mode depends on the active programs on each of the shader stages. |
| If a program is active for the geometry shader stage, transform feedback captures the vertices of each |
| primitive emitted by the geometry shader. Otherwise, if a program is active for the tessellation evaluation |
| shader stage, transform feedback captures each primitive produced by the tessellation primitive generator, |
| whose vertices are processed by the tessellation evaluation shader. Otherwise, transform feedback captures |
| each primitive processed by the vertex shader. |
| */ |
| if ((Utils::Shader::COMPUTE == stage) || (Utils::Shader::TESS_CTRL == stage) || |
| (Utils::Shader::FRAGMENT == stage)) |
| { |
| continue; |
| } |
| |
| testCase test_case = { (CASES)c, (Utils::Shader::STAGES)stage }; |
| |
| m_test_cases.push_back(test_case); |
| } |
| } |
| } |
| |
| /** Constructor |
| * |
| * @param context Test framework context |
| **/ |
| XFBVariableStrideTest::XFBVariableStrideTest(deqp::Context& context) |
| : NegativeTestBase(context, "xfb_variable_stride", "Test verifies that stride qualifier is respected") |
| { |
| } |
| |
| /** Source for given test case and stage |
| * |
| * @param test_case_index Index of test case |
| * @param stage Shader stage |
| * |
| * @return Shader source |
| **/ |
| std::string XFBVariableStrideTest::getShaderSource(GLuint test_case_index, Utils::Shader::STAGES stage) |
| { |
| static const GLchar* invalid_var_definition = "const uint type_size = SIZE;\n" |
| "\n" |
| #if DEBUG_NEG_REMOVE_ERROR |
| "layout (xfb_stride = 2 * type_size) out;\n" |
| #else |
| "layout (xfb_stride = type_size) out;\n" |
| #endif /* DEBUG_NEG_REMOVE_ERROR */ |
| "\n" |
| "layout (xfb_offset = 0) out TYPE goku;\n" |
| "layout (xfb_offset = type_size) out TYPE vegeta;\n"; |
| static const GLchar* valid_var_definition = "const uint type_size = SIZE;\n" |
| "\n" |
| "layout (xfb_stride = type_size) out;\n" |
| "\n" |
| "layout (xfb_offset = 0) out TYPE goku;\n"; |
| static const GLchar* invalid_use = " goku = TYPE(1);\n" |
| " vegeta = TYPE(0);\n" |
| " if (vec4(0) == result)\n" |
| " {\n" |
| " goku = TYPE(0);\n" |
| " vegeta = TYPE(1);\n" |
| " }\n"; |
| static const GLchar* valid_use = " goku = TYPE(1);\n" |
| " if (vec4(0) == result)\n" |
| " {\n" |
| " goku = TYPE(0);\n" |
| " }\n"; |
| static const GLchar* fs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 any_fs;\n" |
| "out vec4 fs_out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " fs_out = any_fs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* gs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 vs_any[];\n" |
| "out vec4 any_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = vs_any[0];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " any_fs = result;\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " any_fs = result;\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| " any_fs = result;\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " any_fs = result;\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tcs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "in vec4 vs_any[];\n" |
| "out vec4 tcs_tes[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| "\n" |
| " tcs_tes[gl_InvocationID] = vs_any[gl_InvocationID];\n" |
| "\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tes_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(isolines, point_mode) in;\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 tcs_tes[];\n" |
| "out vec4 any_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = tcs_tes[0];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " any_fs = result;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 vs_any;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vs_any = in_vs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 any_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = in_vs;\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " any_fs = result;\n" |
| "}\n" |
| "\n"; |
| |
| std::string source; |
| testCase& test_case = m_test_cases[test_case_index]; |
| |
| if (test_case.m_stage == stage) |
| { |
| GLchar buffer[16]; |
| size_t position = 0; |
| const GLchar* type_name = test_case.m_type.GetGLSLTypeName(); |
| const GLchar* var_definition = 0; |
| const GLchar* var_use = 0; |
| |
| sprintf(buffer, "%d", test_case.m_type.GetSize()); |
| |
| switch (test_case.m_case) |
| { |
| case VALID: |
| var_definition = valid_var_definition; |
| var_use = valid_use; |
| break; |
| case INVALID: |
| var_definition = invalid_var_definition; |
| var_use = invalid_use; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| switch (stage) |
| { |
| case Utils::Shader::GEOMETRY: |
| source = gs_tested; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| source = tes_tested; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs_tested; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| Utils::replaceToken("VAR_DEFINITION", position, var_definition, source); |
| position = 0; |
| Utils::replaceToken("SIZE", position, buffer, source); |
| Utils::replaceToken("VARIABLE_USE", position, var_use, source); |
| |
| Utils::replaceAllTokens("TYPE", type_name, source); |
| } |
| else |
| { |
| switch (test_case.m_stage) |
| { |
| case Utils::Shader::GEOMETRY: |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs; |
| break; |
| default: |
| source = ""; |
| } |
| break; |
| case Utils::Shader::TESS_EVAL: |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| source = tcs; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs; |
| break; |
| default: |
| source = ""; |
| } |
| break; |
| case Utils::Shader::VERTEX: |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs; |
| break; |
| default: |
| source = ""; |
| } |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| break; |
| } |
| } |
| |
| return source; |
| } |
| |
| /** Get description of test case |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return Test case description |
| **/ |
| std::string XFBVariableStrideTest::getTestCaseName(GLuint test_case_index) |
| { |
| std::stringstream stream; |
| testCase& test_case = m_test_cases[test_case_index]; |
| |
| stream << "Stage: " << Utils::Shader::GetStageName(test_case.m_stage) |
| << ", type: " << test_case.m_type.GetGLSLTypeName() << ", case: "; |
| |
| switch (test_case.m_case) |
| { |
| case VALID: |
| stream << "valid"; |
| break; |
| case INVALID: |
| stream << "invalid"; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| return stream.str(); |
| } |
| |
| /** Get number of test cases |
| * |
| * @return Number of test cases |
| **/ |
| GLuint XFBVariableStrideTest::getTestCaseNumber() |
| { |
| return static_cast<GLuint>(m_test_cases.size()); |
| } |
| |
| /** Selects if "compute" stage is relevant for test |
| * |
| * @param ignored |
| * |
| * @return false |
| **/ |
| bool XFBVariableStrideTest::isComputeRelevant(GLuint /* test_case_index */) |
| { |
| return false; |
| } |
| |
| /** Selects if compilation failure is expected result |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return true |
| **/ |
| bool XFBVariableStrideTest::isFailureExpected(GLuint test_case_index) |
| { |
| testCase& test_case = m_test_cases[test_case_index]; |
| |
| return (INVALID == test_case.m_case); |
| } |
| |
| /** Prepare all test cases |
| * |
| **/ |
| void XFBVariableStrideTest::testInit() |
| { |
| const GLuint n_types = getTypesNumber(); |
| |
| for (GLuint i = 0; i < n_types; ++i) |
| { |
| for (GLuint stage = 0; stage < Utils::Shader::STAGE_MAX; ++stage) |
| { |
| if ((Utils::Shader::COMPUTE == stage) || (Utils::Shader::TESS_CTRL == stage) || |
| (Utils::Shader::FRAGMENT == stage)) |
| { |
| continue; |
| } |
| |
| const Utils::Type& type = getType(i); |
| for (GLuint c = 0; c < CASE_MAX; ++c) |
| { |
| testCase test_case = { static_cast<CASES>(c), static_cast<Utils::Shader::STAGES>(stage), type }; |
| |
| m_test_cases.push_back(test_case); |
| } |
| } |
| } |
| } |
| |
| /** Constructor |
| * |
| * @param context Test framework context |
| **/ |
| XFBBlockStrideTest::XFBBlockStrideTest(deqp::Context& context) |
| : TestBase(context, "xfb_block_stride", "Test verifies that stride qualifier is respected for blocks") |
| { |
| } |
| |
| /** Source for given test case and stage |
| * |
| * @param test_case_index Index of test case |
| * @param stage Shader stage |
| * |
| * @return Shader source |
| **/ |
| std::string XFBBlockStrideTest::getShaderSource(GLuint test_case_index, Utils::Shader::STAGES stage) |
| { |
| static const GLchar* var_definition = "layout (xfb_offset = 0, xfb_stride = 128) out Goku {\n" |
| " vec4 gohan;\n" |
| " vec4 goten;\n" |
| " vec4 chichi;\n" |
| "} gokuARRAY;\n"; |
| static const GLchar* var_use = " gokuINDEX.gohan = vec4(1, 0, 0, 0);\n" |
| " gokuINDEX.goten = vec4(0, 0, 1, 0);\n" |
| " gokuINDEX.chichi = vec4(0, 1, 0, 0);\n" |
| " if (vec4(0) == result)\n" |
| " {\n" |
| " gokuINDEX.gohan = vec4(0, 1, 1, 1);\n" |
| " gokuINDEX.goten = vec4(1, 1, 0, 1);\n" |
| " gokuINDEX.chichi = vec4(1, 0, 1, 1);\n" |
| " }\n"; |
| static const GLchar* gs_tested = |
| "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "out gl_PerVertex \n" |
| "{ \n" |
| " vec4 gl_Position; \n" // gl_Position must be redeclared in separable program mode |
| "}; \n" |
| "in vec4 tes_gs[];\n" |
| "out vec4 gs_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = tes_gs[0];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tcs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "in vec4 vs_tcs[];\n" |
| "out vec4 tcs_tes[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| "\n" |
| " tcs_tes[gl_InvocationID] = vs_tcs[gl_InvocationID];\n" |
| "\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| #if 0 |
| static const GLchar* tcs_tested = |
| "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 vs_tcs[];\n" |
| "out vec4 tcs_tes[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = vs_tcs[gl_InvocationID];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " tcs_tes[gl_InvocationID] = result;\n" |
| "\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| #endif |
| static const GLchar* tes_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(isolines, point_mode) in;\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 tcs_tes[];\n" |
| "out vec4 tes_gs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = tcs_tes[0];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " tes_gs += result;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 vs_tcs;\n" |
| "out vec4 tes_gs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vs_tcs = tes_gs = in_vs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 vs_tcs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = in_vs;\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " vs_tcs += result;\n" |
| "}\n" |
| "\n"; |
| |
| std::string source; |
| Utils::Shader::STAGES test_case = m_test_cases[test_case_index]; |
| |
| if (test_case == stage) |
| { |
| const GLchar* array = ""; |
| const GLchar* index = ""; |
| size_t position = 0; |
| size_t temp; |
| // It is a compile time error to apply xfb_offset to the declaration of an unsized array(GLSL4.5 spec: Page73) |
| // change array = "[]" to "[1]" |
| switch (stage) |
| { |
| case Utils::Shader::GEOMETRY: |
| source = gs_tested; |
| array = "[1]"; |
| index = "[0]"; |
| break; |
| /* |
| It is invalid to define transform feedback output in HS |
| */ |
| #if 0 |
| case Utils::Shader::TESS_CTRL: |
| source = tcs_tested; |
| array = "[]"; |
| index = "[gl_InvocationID]"; |
| break; |
| #endif |
| case Utils::Shader::TESS_EVAL: |
| source = tes_tested; |
| array = "[1]"; |
| index = "[0]"; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs_tested; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| temp = position; |
| Utils::replaceToken("VAR_DEFINITION", position, var_definition, source); |
| position = temp; |
| Utils::replaceToken("ARRAY", position, array, source); |
| Utils::replaceToken("VARIABLE_USE", position, var_use, source); |
| |
| Utils::replaceAllTokens("INDEX", index, source); |
| } |
| else |
| { |
| switch (test_case) |
| { |
| case Utils::Shader::GEOMETRY: |
| switch (stage) |
| { |
| case Utils::Shader::VERTEX: |
| source = vs; |
| break; |
| default: |
| source = ""; |
| } |
| break; |
| case Utils::Shader::TESS_CTRL: |
| switch (stage) |
| { |
| case Utils::Shader::VERTEX: |
| source = vs; |
| break; |
| default: |
| source = ""; |
| } |
| break; |
| case Utils::Shader::TESS_EVAL: |
| switch (stage) |
| { |
| case Utils::Shader::TESS_CTRL: |
| source = tcs; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs; |
| break; |
| default: |
| source = ""; |
| } |
| break; |
| case Utils::Shader::VERTEX: |
| source = ""; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| break; |
| } |
| } |
| |
| return source; |
| } |
| |
| /** Get description of test case |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return Test case description |
| **/ |
| std::string XFBBlockStrideTest::getTestCaseName(GLuint test_case_index) |
| { |
| std::stringstream stream; |
| |
| stream << "Stage: " << Utils::Shader::GetStageName(m_test_cases[test_case_index]); |
| |
| return stream.str(); |
| } |
| |
| /** Get number of test cases |
| * |
| * @return Number of test cases |
| **/ |
| GLuint XFBBlockStrideTest::getTestCaseNumber() |
| { |
| return static_cast<GLuint>(m_test_cases.size()); |
| } |
| |
| /** Inspects program for xfb stride |
| * |
| * @param program Program to query |
| * |
| * @return true if query results match expected values, false otherwise |
| **/ |
| bool XFBBlockStrideTest::inspectProgram(Utils::Program& program) |
| { |
| GLint stride = 0; |
| |
| program.GetResource(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, GL_TRANSFORM_FEEDBACK_BUFFER_STRIDE, |
| 1 /* buf_size */, &stride); |
| |
| return (128 == stride); |
| } |
| |
| /** Runs test case |
| * |
| * @param test_case_index Id of test case |
| * |
| * @return true if test case pass, false otherwise |
| **/ |
| bool XFBBlockStrideTest::testCase(GLuint test_case_index) |
| { |
| const std::string& gs_source = getShaderSource(test_case_index, Utils::Shader::GEOMETRY); |
| Utils::Program program(m_context); |
| const std::string& tcs_source = getShaderSource(test_case_index, Utils::Shader::TESS_CTRL); |
| const std::string& tes_source = getShaderSource(test_case_index, Utils::Shader::TESS_EVAL); |
| bool test_case_result = true; |
| const std::string& vs_source = getShaderSource(test_case_index, Utils::Shader::VERTEX); |
| |
| program.Init("" /* cs */, "", gs_source, tcs_source, tes_source, vs_source, true /* separable */); |
| |
| test_case_result = inspectProgram(program); |
| |
| return test_case_result; |
| } |
| |
| /** Prepare all test cases |
| * |
| **/ |
| void XFBBlockStrideTest::testInit() |
| { |
| for (GLuint stage = 0; stage < Utils::Shader::STAGE_MAX; ++stage) |
| { |
| if ((Utils::Shader::COMPUTE == stage) || (Utils::Shader::TESS_CTRL == stage) || |
| (Utils::Shader::FRAGMENT == stage)) |
| { |
| continue; |
| } |
| |
| m_test_cases.push_back((Utils::Shader::STAGES)stage); |
| } |
| } |
| |
| /** Constructor |
| * |
| * @param context Test context |
| **/ |
| XFBBlockMemberStrideTest::XFBBlockMemberStrideTest(deqp::Context& context) |
| : BufferTestBase(context, "xfb_block_member_stride", |
| "Test verifies that xfb_stride qualifier is respected for block member") |
| { |
| /* Nothing to be done here */ |
| } |
| |
| /** Get descriptors of buffers necessary for test |
| * |
| * @param ignored |
| * @param out_descriptors Descriptors of buffers used by test |
| **/ |
| void XFBBlockMemberStrideTest::getBufferDescriptors(glw::GLuint /* test_case_index */, |
| bufferDescriptor::Vector& out_descriptors) |
| { |
| const Utils::Type& vec4 = Utils::Type::vec4; |
| |
| /* Test needs single uniform and xfb */ |
| out_descriptors.resize(2); |
| |
| /* Get references */ |
| bufferDescriptor& uniform = out_descriptors[0]; |
| bufferDescriptor& xfb = out_descriptors[1]; |
| |
| /* Index */ |
| uniform.m_index = 0; |
| xfb.m_index = 0; |
| |
| /* Target */ |
| uniform.m_target = Utils::Buffer::Uniform; |
| xfb.m_target = Utils::Buffer::Transform_feedback; |
| |
| /* Data */ |
| static const GLuint vec4_size = 16; |
| const std::vector<GLubyte>& gohan_data = vec4.GenerateDataPacked(); |
| const std::vector<GLubyte>& goten_data = vec4.GenerateDataPacked(); |
| const std::vector<GLubyte>& chichi_data = vec4.GenerateDataPacked(); |
| |
| /* Uniform data */ |
| uniform.m_initial_data.resize(3 * vec4_size); |
| memcpy(&uniform.m_initial_data[0] + 0, &gohan_data[0], vec4_size); |
| memcpy(&uniform.m_initial_data[0] + vec4_size, &goten_data[0], vec4_size); |
| memcpy(&uniform.m_initial_data[0] + 2 * vec4_size, &chichi_data[0], vec4_size); |
| |
| /* XFB data */ |
| xfb.m_initial_data.resize(4 * vec4_size); |
| xfb.m_expected_data.resize(4 * vec4_size); |
| |
| for (GLuint i = 0; i < 4 * vec4_size; ++i) |
| { |
| xfb.m_initial_data[i] = (glw::GLubyte)i; |
| xfb.m_expected_data[i] = (glw::GLubyte)i; |
| } |
| |
| // the xfb_offset of "chichi" should be 32 |
| memcpy(&xfb.m_expected_data[0] + 0, &gohan_data[0], vec4_size); |
| memcpy(&xfb.m_expected_data[0] + vec4_size, &goten_data[0], vec4_size); |
| memcpy(&xfb.m_expected_data[0] + 2 * vec4_size, &chichi_data[0], vec4_size); |
| } |
| |
| /** Get body of main function for given shader stage |
| * |
| * @param ignored |
| * @param stage Shader stage |
| * @param out_assignments Set to empty |
| * @param out_calculations Set to empty |
| **/ |
| void XFBBlockMemberStrideTest::getShaderBody(GLuint /* test_case_index */, Utils::Shader::STAGES stage, |
| std::string& out_assignments, std::string& out_calculations) |
| { |
| out_calculations = ""; |
| |
| static const GLchar* gs = " gohan = uni_gohan;\n" |
| " goten = uni_goten;\n" |
| " chichi = uni_chichi;\n"; |
| static const GLchar* fs = " fs_out = gohan + goten + chichi;\n"; |
| |
| const GLchar* assignments = ""; |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| assignments = fs; |
| break; |
| case Utils::Shader::GEOMETRY: |
| assignments = gs; |
| break; |
| default: |
| break; |
| } |
| |
| out_assignments = assignments; |
| } |
| |
| /** Get interface of shader |
| * |
| * @param ignored |
| * @param stage Shader stage |
| * @param out_interface Set to "" |
| **/ |
| void XFBBlockMemberStrideTest::getShaderInterface(GLuint /* test_case_index */, Utils::Shader::STAGES stage, |
| std::string& out_interface) |
| { |
| static const GLchar* gs = "layout (xfb_buffer = 0, xfb_offset = 0) out Goku {\n" |
| " vec4 gohan;\n" |
| " layout (xfb_stride = 48) vec4 goten;\n" |
| " vec4 chichi;\n" |
| "};\n" |
| "layout(binding = 0) uniform gs_block {\n" |
| " vec4 uni_gohan;\n" |
| " vec4 uni_goten;\n" |
| " vec4 uni_chichi;\n" |
| "};\n"; |
| static const GLchar* fs = "in Goku {\n" |
| " vec4 gohan;\n" |
| " vec4 goten;\n" |
| " vec4 chichi;\n" |
| "};\n" |
| "out vec4 fs_out;\n"; |
| |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| out_interface = fs; |
| break; |
| case Utils::Shader::GEOMETRY: |
| out_interface = gs; |
| break; |
| default: |
| out_interface = ""; |
| return; |
| } |
| } |
| |
| /** Inspects program to check if all resources are as expected |
| * |
| * @param ignored |
| * @param program Program instance |
| * @param out_stream Error message |
| * |
| * @return true if everything is ok, false otherwise |
| **/ |
| bool XFBBlockMemberStrideTest::inspectProgram(GLuint /* test_case_index*/, Utils::Program& program, |
| std::stringstream& out_stream) |
| { |
| const GLuint gohan_id = program.GetResourceIndex("gohan", GL_TRANSFORM_FEEDBACK_VARYING); |
| const GLuint goten_id = program.GetResourceIndex("goten", GL_TRANSFORM_FEEDBACK_VARYING); |
| const GLuint chichi_id = program.GetResourceIndex("chichi", GL_TRANSFORM_FEEDBACK_VARYING); |
| |
| GLint gohan_offset = 0; |
| GLint goten_offset = 0; |
| GLint chichi_offset = 0; |
| |
| program.GetResource(GL_TRANSFORM_FEEDBACK_VARYING, gohan_id, GL_OFFSET, 1, &gohan_offset); |
| program.GetResource(GL_TRANSFORM_FEEDBACK_VARYING, goten_id, GL_OFFSET, 1, &goten_offset); |
| program.GetResource(GL_TRANSFORM_FEEDBACK_VARYING, chichi_id, GL_OFFSET, 1, &chichi_offset); |
| |
| // the xfb_offset of "chichi" should be 32 |
| if ((0 != gohan_offset) || (16 != goten_offset) || (32 != chichi_offset)) |
| { |
| out_stream << "Got wrong offset: [" << gohan_offset << ", " << goten_offset << ", " << chichi_offset |
| << "] expected: [0, 16, 32]"; |
| return false; |
| } |
| |
| return true; |
| } |
| |
| /** Constructor |
| * |
| * @param context Test framework context |
| **/ |
| XFBDuplicatedStrideTest::XFBDuplicatedStrideTest(deqp::Context& context) |
| : NegativeTestBase(context, "xfb_duplicated_stride", |
| "Test verifies that compiler reports error when conflicting stride qualifiers are used") |
| { |
| } |
| |
| /** Source for given test case and stage |
| * |
| * @param test_case_index Index of test case |
| * @param stage Shader stage |
| * |
| * @return Shader source |
| **/ |
| std::string XFBDuplicatedStrideTest::getShaderSource(GLuint test_case_index, Utils::Shader::STAGES stage) |
| { |
| static const GLchar* invalid_var_definition = "const uint valid_stride = 64;\n" |
| #if DEBUG_NEG_REMOVE_ERROR |
| "const uint conflicting_stride = 64;\n" |
| #else |
| "const uint conflicting_stride = 128;\n" |
| #endif /* DEBUG_NEG_REMOVE_ERROR */ |
| "\n" |
| "layout (xfb_buffer = 0, xfb_stride = valid_stride) out;\n" |
| "layout (xfb_buffer = 0, xfb_stride = conflicting_stride) out;\n"; |
| static const GLchar* valid_var_definition = "const uint valid_stride = 64;\n" |
| "\n" |
| "layout (xfb_buffer = 0, xfb_stride = valid_stride) out;\n" |
| "layout (xfb_buffer = 0, xfb_stride = valid_stride) out;\n"; |
| static const GLchar* fs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 any_fs;\n" |
| "out vec4 fs_out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " fs_out = any_fs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* gs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 vs_any[];\n" |
| "out vec4 any_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = vs_any[0];\n" |
| "\n" |
| " any_fs = result;\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " any_fs = result;\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| " any_fs = result;\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " any_fs = result;\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tcs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "in vec4 vs_any[];\n" |
| "out vec4 tcs_tes[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| "\n" |
| " tcs_tes[gl_InvocationID] = vs_any[gl_InvocationID];\n" |
| "\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tes_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(isolines, point_mode) in;\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 tcs_tes[];\n" |
| "out vec4 any_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = tcs_tes[0];\n" |
| "\n" |
| " any_fs = result;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 vs_any;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vs_any = in_vs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 any_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = in_vs;\n" |
| "\n" |
| " any_fs += result;\n" |
| "}\n" |
| "\n"; |
| |
| std::string source; |
| testCase& test_case = m_test_cases[test_case_index]; |
| |
| if (test_case.m_stage == stage) |
| { |
| size_t position = 0; |
| const GLchar* var_definition = 0; |
| |
| switch (test_case.m_case) |
| { |
| case VALID: |
| var_definition = valid_var_definition; |
| break; |
| case INVALID: |
| var_definition = invalid_var_definition; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| switch (stage) |
| { |
| case Utils::Shader::GEOMETRY: |
| source = gs_tested; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| source = tes_tested; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs_tested; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| Utils::replaceToken("VAR_DEFINITION", position, var_definition, source); |
| } |
| else |
| { |
| switch (test_case.m_stage) |
| { |
| case Utils::Shader::GEOMETRY: |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs; |
| break; |
| default: |
| source = ""; |
| } |
| break; |
| case Utils::Shader::TESS_EVAL: |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| source = tcs; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs; |
| break; |
| default: |
| source = ""; |
| } |
| break; |
| case Utils::Shader::VERTEX: |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs; |
| break; |
| default: |
| source = ""; |
| } |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| break; |
| } |
| } |
| |
| return source; |
| } |
| |
| /** Get description of test case |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return Test case description |
| **/ |
| std::string XFBDuplicatedStrideTest::getTestCaseName(GLuint test_case_index) |
| { |
| std::stringstream stream; |
| testCase& test_case = m_test_cases[test_case_index]; |
| |
| stream << "Stage: " << Utils::Shader::GetStageName(test_case.m_stage) << ", case: "; |
| |
| switch (test_case.m_case) |
| { |
| case VALID: |
| stream << "valid"; |
| break; |
| case INVALID: |
| stream << "invalid"; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| return stream.str(); |
| } |
| |
| /** Get number of test cases |
| * |
| * @return Number of test cases |
| **/ |
| GLuint XFBDuplicatedStrideTest::getTestCaseNumber() |
| { |
| return static_cast<GLuint>(m_test_cases.size()); |
| } |
| |
| /** Selects if "compute" stage is relevant for test |
| * |
| * @param ignored |
| * |
| * @return false |
| **/ |
| bool XFBDuplicatedStrideTest::isComputeRelevant(GLuint /* test_case_index */) |
| { |
| return false; |
| } |
| |
| /** Selects if compilation failure is expected result |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return true |
| **/ |
| bool XFBDuplicatedStrideTest::isFailureExpected(GLuint test_case_index) |
| { |
| testCase& test_case = m_test_cases[test_case_index]; |
| |
| return (INVALID == test_case.m_case); |
| } |
| |
| /** Prepare all test cases |
| * |
| **/ |
| void XFBDuplicatedStrideTest::testInit() |
| { |
| for (GLuint c = 0; c < CASE_MAX; ++c) |
| { |
| for (GLuint stage = 0; stage < Utils::Shader::STAGE_MAX; ++stage) |
| { |
| if ((Utils::Shader::COMPUTE == stage) || (Utils::Shader::TESS_CTRL == stage) || |
| (Utils::Shader::FRAGMENT == stage)) |
| { |
| continue; |
| } |
| |
| testCase test_case = { (CASES)c, (Utils::Shader::STAGES)stage }; |
| |
| m_test_cases.push_back(test_case); |
| } |
| } |
| } |
| |
| /** Constructor |
| * |
| * @param context Test framework context |
| **/ |
| XFBGetProgramResourceAPITest::XFBGetProgramResourceAPITest(deqp::Context& context) |
| : TestBase(context, "xfb_get_program_resource_api", |
| "Test verifies that get program resource reports correct results for XFB") |
| { |
| } |
| |
| /** Source for given test case and stage |
| * |
| * @param test_case_index Index of test case |
| * @param stage Shader stage |
| * |
| * @return Shader source |
| **/ |
| std::string XFBGetProgramResourceAPITest::getShaderSource(GLuint test_case_index, Utils::Shader::STAGES stage) |
| { |
| static const GLchar* api_var_definition = "out TYPE b0_v1ARRAY;\n" |
| "out TYPE b1_v1ARRAY;\n" |
| "out TYPE b0_v3ARRAY;\n" |
| "out TYPE b0_v0ARRAY;\n"; |
| static const GLchar* xfb_var_definition = |
| "const uint type_size = SIZE;\n" |
| "\n" |
| "layout (xfb_buffer = 1, xfb_stride = 4 * type_size) out;\n" |
| "\n" |
| "layout (xfb_buffer = 0, xfb_offset = 1 * type_size) out TYPE b0_v1ARRAY;\n" |
| "layout (xfb_buffer = 1, xfb_offset = 1 * type_size) out TYPE b1_v1ARRAY;\n" |
| "layout (xfb_buffer = 0, xfb_offset = 3 * type_size) out TYPE b0_v3ARRAY;\n" |
| "layout (xfb_buffer = 0, xfb_offset = 0 * type_size) out TYPE b0_v0ARRAY;\n"; |
| static const GLchar* var_use = " b0_v1INDEX = TYPE(0);\n" |
| " b1_v1INDEX = TYPE(1);\n" |
| " b0_v3INDEX = TYPE(0);\n" |
| " b0_v0INDEX = TYPE(1);\n" |
| " if (vec4(0) == result)\n" |
| " {\n" |
| " b0_v1INDEX = TYPE(1);\n" |
| " b1_v1INDEX = TYPE(0);\n" |
| " b0_v3INDEX = TYPE(1);\n" |
| " b0_v0INDEX = TYPE(0);\n" |
| " }\n"; |
| static const GLchar* gs_tested = |
| "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "out gl_PerVertex \n" |
| "{ \n" |
| " vec4 gl_Position; \n" // gl_Position must be redeclared in separable program mode |
| "}; \n" |
| "in vec4 tes_gs[];\n" |
| "out vec4 gs_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = tes_gs[0];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| #if 0 |
| static const GLchar* tcs_tested = |
| "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 vs_tcs[];\n" |
| "out vec4 tcs_tes[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = vs_tcs[gl_InvocationID];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " tcs_tes[gl_InvocationID] = result;\n" |
| "\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| #endif |
| static const GLchar* tes_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(isolines, point_mode) in;\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 tcs_tes[];\n" |
| "out vec4 tes_gs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = tcs_tes[0];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " tes_gs = result;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 vs_tcs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = in_vs;\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " vs_tcs = result;\n" |
| "}\n" |
| "\n"; |
| |
| std::string source; |
| const test_Case& test_case = m_test_cases[test_case_index]; |
| |
| if (test_case.m_stage == stage) |
| { |
| const GLchar* array = ""; |
| GLchar buffer[16]; |
| const GLchar* index = ""; |
| size_t position = 0; |
| size_t temp; |
| const GLchar* type_name = test_case.m_type.GetGLSLTypeName(); |
| const GLchar* var_definition = 0; |
| |
| sprintf(buffer, "%d", test_case.m_type.GetSize()); |
| |
| if (XFB == test_case.m_case) |
| { |
| var_definition = xfb_var_definition; |
| } |
| else |
| { |
| var_definition = api_var_definition; |
| } |
| |
| // It is a compile time error to apply xfb_offset to the declaration of an unsized array(GLSL4.5 spec: Page73) |
| // change array = "[]" to "[1]" |
| switch (stage) |
| { |
| case Utils::Shader::GEOMETRY: |
| source = gs_tested; |
| array = "[1]"; |
| index = "[0]"; |
| break; |
| // It is invalid to output transform feedback varyings in tessellation control shader |
| #if 0 |
| case Utils::Shader::TESS_CTRL: |
| source = tcs_tested; |
| array = "[]"; |
| index = "[gl_InvocationID]"; |
| break; |
| #endif |
| case Utils::Shader::TESS_EVAL: |
| source = tes_tested; |
| array = "[1]"; |
| index = "[0]"; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs_tested; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| temp = position; |
| Utils::replaceToken("VAR_DEFINITION", position, var_definition, source); |
| if (XFB == test_case.m_case) |
| { |
| position = temp; |
| Utils::replaceToken("SIZE", position, buffer, source); |
| } |
| Utils::replaceToken("VARIABLE_USE", position, var_use, source); |
| |
| Utils::replaceAllTokens("ARRAY", array, source); |
| Utils::replaceAllTokens("INDEX", index, source); |
| Utils::replaceAllTokens("TYPE", type_name, source); |
| } |
| else |
| { |
| source = ""; |
| } |
| |
| return source; |
| } |
| |
| /** Get description of test case |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return Test case description |
| **/ |
| std::string XFBGetProgramResourceAPITest::getTestCaseName(GLuint test_case_index) |
| { |
| std::stringstream stream; |
| const test_Case& test_case = m_test_cases[test_case_index]; |
| |
| stream << "Stage: " << Utils::Shader::GetStageName(test_case.m_stage) |
| << ", type: " << test_case.m_type.GetGLSLTypeName() << ", case: "; |
| |
| switch (test_case.m_case) |
| { |
| case INTERLEAVED: |
| stream << "interleaved"; |
| break; |
| case SEPARATED: |
| stream << "separated"; |
| break; |
| case XFB: |
| stream << "xfb"; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| return stream.str(); |
| } |
| |
| /** Get number of test cases |
| * |
| * @return Number of test cases |
| **/ |
| GLuint XFBGetProgramResourceAPITest::getTestCaseNumber() |
| { |
| return static_cast<GLuint>(m_test_cases.size()); |
| } |
| |
| /** Inspects program for offset, buffer index, buffer stride and type |
| * |
| * @param test_case_index Index of test case |
| * @param program Program to query |
| * |
| * @return true if query results match expected values, false otherwise |
| **/ |
| bool XFBGetProgramResourceAPITest::inspectProgram(glw::GLuint test_case_index, Utils::Program& program) |
| { |
| GLint b0_stride = 0; |
| GLint b1_stride = 0; |
| GLint b0_v0_buf = 0; |
| GLint b0_v0_offset = 0; |
| GLint b0_v0_type = 0; |
| GLint b0_v1_buf = 0; |
| GLint b0_v1_offset = 0; |
| GLint b0_v1_type = 0; |
| GLint b0_v3_buf = 0; |
| GLint b0_v3_offset = 0; |
| GLint b0_v3_type = 0; |
| GLint b1_v1_buf = 0; |
| GLint b1_v1_offset = 0; |
| GLint b1_v1_type = 0; |
| const test_Case& test_case = m_test_cases[test_case_index]; |
| const GLenum type_enum = test_case.m_type.GetTypeGLenum(); |
| const GLint type_size = test_case.m_type.GetSize(); |
| |
| GLuint b0_v0_index = program.GetResourceIndex("b0_v0", GL_TRANSFORM_FEEDBACK_VARYING); |
| GLuint b0_v1_index = program.GetResourceIndex("b0_v1", GL_TRANSFORM_FEEDBACK_VARYING); |
| GLuint b0_v3_index = program.GetResourceIndex("b0_v3", GL_TRANSFORM_FEEDBACK_VARYING); |
| GLuint b1_v1_index = program.GetResourceIndex("b1_v1", GL_TRANSFORM_FEEDBACK_VARYING); |
| |
| program.GetResource(GL_TRANSFORM_FEEDBACK_VARYING, b0_v0_index, GL_OFFSET, 1 /* buf_size */, &b0_v0_offset); |
| program.GetResource(GL_TRANSFORM_FEEDBACK_VARYING, b0_v1_index, GL_OFFSET, 1 /* buf_size */, &b0_v1_offset); |
| program.GetResource(GL_TRANSFORM_FEEDBACK_VARYING, b0_v3_index, GL_OFFSET, 1 /* buf_size */, &b0_v3_offset); |
| program.GetResource(GL_TRANSFORM_FEEDBACK_VARYING, b1_v1_index, GL_OFFSET, 1 /* buf_size */, &b1_v1_offset); |
| |
| program.GetResource(GL_TRANSFORM_FEEDBACK_VARYING, b0_v0_index, GL_TYPE, 1 /* buf_size */, &b0_v0_type); |
| program.GetResource(GL_TRANSFORM_FEEDBACK_VARYING, b0_v1_index, GL_TYPE, 1 /* buf_size */, &b0_v1_type); |
| program.GetResource(GL_TRANSFORM_FEEDBACK_VARYING, b0_v3_index, GL_TYPE, 1 /* buf_size */, &b0_v3_type); |
| program.GetResource(GL_TRANSFORM_FEEDBACK_VARYING, b1_v1_index, GL_TYPE, 1 /* buf_size */, &b1_v1_type); |
| |
| program.GetResource(GL_TRANSFORM_FEEDBACK_VARYING, b0_v0_index, GL_TRANSFORM_FEEDBACK_BUFFER_INDEX, |
| 1 /* buf_size */, &b0_v0_buf); |
| program.GetResource(GL_TRANSFORM_FEEDBACK_VARYING, b0_v1_index, GL_TRANSFORM_FEEDBACK_BUFFER_INDEX, |
| 1 /* buf_size */, &b0_v1_buf); |
| program.GetResource(GL_TRANSFORM_FEEDBACK_VARYING, b0_v3_index, GL_TRANSFORM_FEEDBACK_BUFFER_INDEX, |
| 1 /* buf_size */, &b0_v3_buf); |
| program.GetResource(GL_TRANSFORM_FEEDBACK_VARYING, b1_v1_index, GL_TRANSFORM_FEEDBACK_BUFFER_INDEX, |
| 1 /* buf_size */, &b1_v1_buf); |
| |
| program.GetResource(GL_TRANSFORM_FEEDBACK_BUFFER, b0_v0_buf, GL_TRANSFORM_FEEDBACK_BUFFER_STRIDE, 1 /* buf_size */, |
| &b0_stride); |
| program.GetResource(GL_TRANSFORM_FEEDBACK_BUFFER, b1_v1_buf, GL_TRANSFORM_FEEDBACK_BUFFER_STRIDE, 1 /* buf_size */, |
| &b1_stride); |
| |
| if (SEPARATED != test_case.m_case) |
| { |
| return (((GLint)(4 * type_size) == b0_stride) && ((GLint)(4 * type_size) == b1_stride) && |
| ((GLint)(0) == b0_v0_buf) && ((GLint)(0 * type_size) == b0_v0_offset) && |
| ((GLint)(type_enum) == b0_v0_type) && ((GLint)(0) == b0_v1_buf) && |
| ((GLint)(1 * type_size) == b0_v1_offset) && ((GLint)(type_enum) == b0_v1_type) && |
| ((GLint)(0) == b0_v3_buf) && ((GLint)(3 * type_size) == b0_v3_offset) && |
| ((GLint)(type_enum) == b0_v3_type) && ((GLint)(1) == b1_v1_buf) && |
| ((GLint)(1 * type_size) == b1_v1_offset) && ((GLint)(type_enum) == b1_v1_type)); |
| } |
| else |
| { |
| return (((GLint)(1 * type_size) == b0_stride) && ((GLint)(1 * type_size) == b1_stride) && |
| ((GLint)(0) == b0_v0_buf) && ((GLint)(0) == b0_v0_offset) && ((GLint)(type_enum) == b0_v0_type) && |
| ((GLint)(1) == b0_v1_buf) && ((GLint)(0) == b0_v1_offset) && ((GLint)(type_enum) == b0_v1_type) && |
| ((GLint)(2) == b0_v3_buf) && ((GLint)(0) == b0_v3_offset) && ((GLint)(type_enum) == b0_v3_type) && |
| ((GLint)(3) == b1_v1_buf) && ((GLint)(0) == b1_v1_offset) && ((GLint)(type_enum) == b1_v1_type)); |
| } |
| } |
| |
| /** Insert gl_SkipComponents |
| * |
| * @param num_components How many gl_SkipComponents1 need to be inserted |
| * @param varyings The transform feedback varyings string vector |
| * |
| **/ |
| void XFBGetProgramResourceAPITest::insertSkipComponents(int num_components, Utils::Program::NameVector& varyings) |
| { |
| int num_component_4 = num_components / 4; |
| int num_component_1 = num_components % 4; |
| for (int i = 0; i < num_component_4; i++) |
| { |
| varyings.push_back("gl_SkipComponents4"); |
| } |
| switch (num_component_1) |
| { |
| case 1: |
| varyings.push_back("gl_SkipComponents1"); |
| break; |
| case 2: |
| varyings.push_back("gl_SkipComponents2"); |
| break; |
| case 3: |
| varyings.push_back("gl_SkipComponents3"); |
| break; |
| default: |
| break; |
| } |
| } |
| |
| /** Runs test case |
| * |
| * @param test_case_index Id of test case |
| * |
| * @return true if test case pass, false otherwise |
| **/ |
| bool XFBGetProgramResourceAPITest::testCase(GLuint test_case_index) |
| { |
| const std::string& gs_source = getShaderSource(test_case_index, Utils::Shader::GEOMETRY); |
| Utils::Program program(m_context); |
| const std::string& tcs_source = getShaderSource(test_case_index, Utils::Shader::TESS_CTRL); |
| const std::string& tes_source = getShaderSource(test_case_index, Utils::Shader::TESS_EVAL); |
| const test_Case& test_case = m_test_cases[test_case_index]; |
| bool test_case_result = true; |
| const std::string& vs_source = getShaderSource(test_case_index, Utils::Shader::VERTEX); |
| |
| // According to spec: gl_SkipComponents1 ~ gl_SkipComponents4 is treated as specifying a one- to four-component floating point output variables with undefined values. |
| // No data will be recorded for such strings, but the offset assigned to the next variable in varyings and the stride of the assigned bingding point will be affected. |
| |
| if (INTERLEAVED == test_case.m_case) |
| { |
| /* |
| layout (xfb_buffer = 0, xfb_offset = 1 * type_size) out type b0_v1; |
| layout (xfb_buffer = 1, xfb_offset = 1 * type_size) out type b1_v1; |
| layout (xfb_buffer = 0, xfb_offset = 3 * type_size) out type b0_v3; |
| layout (xfb_buffer = 0, xfb_offset = 0 * type_size) out type b0_v0; |
| |
| Note: the type can be float, double, mat2, mat3x2, dmat2, dmat3x2..., so to make the each variable of "captured_varyings" has the same xfb_offset with the above shaders, |
| we need to calculate how many "gl_SkipComponents" need to be inserted. |
| */ |
| Utils::Program::NameVector captured_varyings; |
| captured_varyings.push_back("b0_v0"); |
| captured_varyings.push_back("b0_v1"); |
| // Compute how many gl_SkipComponents to be inserted |
| int numComponents = test_case.m_type.GetSize() / 4; |
| insertSkipComponents(numComponents, captured_varyings); |
| captured_varyings.push_back("b0_v3"); |
| captured_varyings.push_back("gl_NextBuffer"); |
| insertSkipComponents(numComponents, captured_varyings); |
| captured_varyings.push_back("b1_v1"); |
| insertSkipComponents(numComponents * 2, captured_varyings); |
| |
| program.Init("" /* cs */, "", gs_source, tcs_source, tes_source, vs_source, captured_varyings, true, |
| true /* separable */); |
| } |
| else if (SEPARATED == test_case.m_case) |
| { |
| Utils::Program::NameVector captured_varyings; |
| |
| captured_varyings.push_back("b0_v0"); |
| captured_varyings.push_back("b0_v1"); |
| captured_varyings.push_back("b0_v3"); |
| captured_varyings.push_back("b1_v1"); |
| |
| program.Init("" /* cs */, "", gs_source, tcs_source, tes_source, vs_source, captured_varyings, false, |
| true /* separable */); |
| } |
| else |
| { |
| |
| program.Init("" /* cs */, "", gs_source, tcs_source, tes_source, vs_source, true /* separable */); |
| } |
| |
| test_case_result = inspectProgram(test_case_index, program); |
| |
| return test_case_result; |
| } |
| |
| /** Prepare all test cases |
| * |
| **/ |
| void XFBGetProgramResourceAPITest::testInit() |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| const GLuint n_types = getTypesNumber(); |
| GLint max_xfb_int; |
| GLint max_xfb_sep; |
| |
| gl.getIntegerv(GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS, &max_xfb_int); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv"); |
| |
| gl.getIntegerv(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS, &max_xfb_sep); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv"); |
| |
| GLint max_varyings; |
| gl.getIntegerv(GL_MAX_VARYING_COMPONENTS, &max_varyings); |
| |
| for (GLuint i = 0; i < n_types; ++i) |
| { |
| // When i == 7, the type is dmat4, i == 9 the type is dmat4x3, the number of output components exceeds the maximum value that AMD's driver supported, |
| // the MAX_VARYING_COMPONENTS is 32 in our driver, but when the variable type is dmat4 or dmat4x3, the number of output component is 33, to make the |
| // shader valid, we can either skip the dmat4, dmat4x3 or query the implementation-dependent value MAX_VARYING_COMPONENTS before generating the shader |
| // to guarantee the number of varying not exceeded. |
| /* |
| layout (xfb_buffer = 1, xfb_stride = 4 * type_size) out; |
| layout (xfb_buffer = 0, xfb_offset = 1 * type_size) out type b0_v1; |
| layout (xfb_buffer = 1, xfb_offset = 1 * type_size) out type b1_v1; |
| layout (xfb_buffer = 0, xfb_offset = 3 * type_size) out type b0_v3; |
| layout (xfb_buffer = 0, xfb_offset = 0 * type_size) out type b0_v0; |
| in vec4 in_vs; |
| out vec4 vs_tcs; |
| */ |
| if (i == 7 || i == 9) |
| continue; |
| const Utils::Type& type = getType(i); |
| if (4 * type.GetNumComponents() + 4 > (GLuint)max_varyings) |
| { |
| continue; |
| } |
| for (GLuint stage = 0; stage < Utils::Shader::STAGE_MAX; ++stage) |
| { |
| /* |
| It is invalid to define transform feedback output in HS |
| */ |
| if ((Utils::Shader::COMPUTE == stage) || (Utils::Shader::TESS_CTRL == stage) || |
| (Utils::Shader::FRAGMENT == stage)) |
| { |
| continue; |
| } |
| |
| test_Case test_case_int = { INTERLEAVED, (Utils::Shader::STAGES)stage, type }; |
| test_Case test_case_sep = { SEPARATED, (Utils::Shader::STAGES)stage, type }; |
| test_Case test_case_xfb = { XFB, (Utils::Shader::STAGES)stage, type }; |
| |
| if ((int)type.GetSize() <= max_xfb_int) |
| { |
| m_test_cases.push_back(test_case_xfb); |
| m_test_cases.push_back(test_case_int); |
| } |
| |
| if ((int)type.GetSize() <= max_xfb_sep) |
| { |
| m_test_cases.push_back(test_case_sep); |
| } |
| } |
| } |
| } |
| |
| /** Constructor |
| * |
| * @param context Test context |
| **/ |
| XFBOverrideQualifiersWithAPITest::XFBOverrideQualifiersWithAPITest(deqp::Context& context) |
| : BufferTestBase(context, "xfb_override_qualifiers_with_api", |
| "Test verifies that xfb_offset qualifier is not overriden with API") |
| { |
| /* Nothing to be done here */ |
| } |
| |
| /** Get descriptors of buffers necessary for test |
| * |
| * @param test_case_index Index of test case |
| * @param out_descriptors Descriptors of buffers used by test |
| **/ |
| void XFBOverrideQualifiersWithAPITest::getBufferDescriptors(glw::GLuint test_case_index, |
| bufferDescriptor::Vector& out_descriptors) |
| { |
| const Utils::Type& type = getType(test_case_index); |
| |
| /* Test needs single uniform and xfb */ |
| out_descriptors.resize(2); |
| |
| /* Get references */ |
| bufferDescriptor& uniform = out_descriptors[0]; |
| bufferDescriptor& xfb = out_descriptors[1]; |
| |
| /* Index */ |
| uniform.m_index = 0; |
| xfb.m_index = 0; |
| |
| /* Target */ |
| uniform.m_target = Utils::Buffer::Uniform; |
| xfb.m_target = Utils::Buffer::Transform_feedback; |
| |
| /* Data */ |
| const GLuint gen_start = Utils::s_rand; |
| const std::vector<GLubyte>& vegeta_data = type.GenerateData(); |
| const std::vector<GLubyte>& trunks_data = type.GenerateData(); |
| const std::vector<GLubyte>& goku_data = type.GenerateData(); |
| |
| Utils::s_rand = gen_start; |
| const std::vector<GLubyte>& vegeta_data_pck = type.GenerateDataPacked(); |
| type.GenerateDataPacked(); // generate the data for trunks |
| const std::vector<GLubyte>& goku_data_pck = type.GenerateDataPacked(); |
| |
| const GLuint type_size = static_cast<GLuint>(vegeta_data.size()); |
| const GLuint type_size_pck = static_cast<GLuint>(vegeta_data_pck.size()); |
| |
| /* Uniform data */ |
| uniform.m_initial_data.resize(3 * type_size); |
| memcpy(&uniform.m_initial_data[0] + 0, &vegeta_data[0], type_size); |
| memcpy(&uniform.m_initial_data[0] + type_size, &trunks_data[0], type_size); |
| memcpy(&uniform.m_initial_data[0] + 2 * type_size, &goku_data[0], type_size); |
| |
| /* XFB data */ |
| xfb.m_initial_data.resize(3 * type_size_pck); |
| xfb.m_expected_data.resize(3 * type_size_pck); |
| |
| for (GLuint i = 0; i < 3 * type_size_pck; ++i) |
| { |
| xfb.m_initial_data[i] = (glw::GLubyte)i; |
| xfb.m_expected_data[i] = (glw::GLubyte)i; |
| } |
| |
| memcpy(&xfb.m_expected_data[0] + 0, &goku_data_pck[0], type_size_pck); |
| memcpy(&xfb.m_expected_data[0] + 2 * type_size_pck, &vegeta_data_pck[0], type_size_pck); |
| } |
| |
| /** Get list of names of varyings that will be registered with TransformFeedbackVaryings |
| * |
| * @param ignored |
| * @param captured_varyings List of names |
| **/ |
| void XFBOverrideQualifiersWithAPITest::getCapturedVaryings(glw::GLuint test_case_index, |
| Utils::Program::NameVector& captured_varyings, |
| GLint* xfb_components) |
| { |
| captured_varyings.resize(1); |
| |
| captured_varyings[0] = "trunks"; |
| |
| /* The test captures 3 varyings of type 'type' */ |
| Utils::Type type = getType(test_case_index); |
| GLint type_size = type.GetSize(false); |
| *xfb_components = 3 * type_size / 4; |
| } |
| |
| /** Get body of main function for given shader stage |
| * |
| * @param test_case_index Index of test case |
| * @param stage Shader stage |
| * @param out_assignments Set to empty |
| * @param out_calculations Set to empty |
| **/ |
| void XFBOverrideQualifiersWithAPITest::getShaderBody(GLuint test_case_index, Utils::Shader::STAGES stage, |
| std::string& out_assignments, std::string& out_calculations) |
| { |
| out_calculations = ""; |
| |
| static const GLchar* gs = " vegeta = uni_vegeta;\n" |
| " trunks = uni_trunks;\n" |
| " goku = uni_goku;\n"; |
| static const GLchar* fs = " fs_out = vec4(0);\n" |
| " if (TYPE(1) == goku + trunks + vegeta)\n" |
| " {\n" |
| " fs_out = vec4(1);\n" |
| " }\n"; |
| |
| const GLchar* assignments = ""; |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| assignments = fs; |
| break; |
| case Utils::Shader::GEOMETRY: |
| assignments = gs; |
| break; |
| default: |
| break; |
| } |
| |
| out_assignments = assignments; |
| |
| if (Utils::Shader::FRAGMENT == stage) |
| { |
| const Utils::Type& type = getType(test_case_index); |
| |
| Utils::replaceAllTokens("TYPE", type.GetGLSLTypeName(), out_assignments); |
| } |
| } |
| |
| /** Get interface of shader |
| * |
| * @param test_case_index Index of test case |
| * @param stage Shader stage |
| * @param out_interface Set to "" |
| **/ |
| void XFBOverrideQualifiersWithAPITest::getShaderInterface(GLuint test_case_index, Utils::Shader::STAGES stage, |
| std::string& out_interface) |
| { |
| static const GLchar* gs = "const uint sizeof_type = SIZE;\n" |
| "\n" |
| "layout (xfb_offset = 2 * sizeof_type) flat out TYPE vegeta;\n" |
| " flat out TYPE trunks;\n" |
| "layout (xfb_offset = 0) flat out TYPE goku;\n" |
| "\n" |
| /* |
| There is no packing qualifier for uniform block gs_block, according to spec, it should be "shared" by default, |
| the definition equals to "layout(binding=0, shared)", if the block is declared as shared, each block member will |
| not be packed, and each block member's layout in memory is implementation dependent, so we can't use the API |
| glBufferData() to update the UBO directly, we need to query each block member's offset first, then upload the |
| data to the corresponding offset, otherwise we can't get the correct data from UBO; to make the test passed, |
| we need to add the qualifier std140, and change the declaration as layout(binding=0, std140), which can make |
| sure all the block members are packed and the application can upload the data by glBufferData() directly. |
| */ |
| "layout(binding = 0, std140) uniform gs_block {\n" |
| " TYPE uni_vegeta;\n" |
| " TYPE uni_trunks;\n" |
| " TYPE uni_goku;\n" |
| "};\n"; |
| static const GLchar* fs = "flat in TYPE vegeta;\n" |
| "flat in TYPE trunks;\n" |
| "flat in TYPE goku;\n" |
| "\n" |
| "out vec4 fs_out;\n"; |
| |
| const Utils::Type& type = getType(test_case_index); |
| |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| out_interface = fs; |
| break; |
| case Utils::Shader::GEOMETRY: |
| out_interface = gs; |
| break; |
| default: |
| out_interface = ""; |
| return; |
| } |
| |
| if (Utils::Shader::GEOMETRY == stage) |
| { |
| GLchar buffer[16]; |
| size_t position = 0; |
| const GLuint type_size = type.GetSize(); |
| |
| sprintf(buffer, "%d", type_size); |
| |
| Utils::replaceToken("SIZE", position, buffer, out_interface); |
| } |
| |
| Utils::replaceAllTokens("TYPE", type.GetGLSLTypeName(), out_interface); |
| } |
| |
| /** Get type name |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return Name of type test in test_case_index |
| **/ |
| std::string XFBOverrideQualifiersWithAPITest::getTestCaseName(glw::GLuint test_case_index) |
| { |
| return getTypeName(test_case_index); |
| } |
| |
| /** Returns number of types to test |
| * |
| * @return Number of types, 34 |
| **/ |
| glw::GLuint XFBOverrideQualifiersWithAPITest::getTestCaseNumber() |
| { |
| return getTypesNumber(); |
| } |
| |
| /** Inspects program to check if all resources are as expected |
| * |
| * @param test_case_index Index of test case |
| * @param program Program instance |
| * @param out_stream Error message |
| * |
| * @return true if everything is ok, false otherwise |
| **/ |
| bool XFBOverrideQualifiersWithAPITest::inspectProgram(GLuint test_case_index, Utils::Program& program, |
| std::stringstream& out_stream) |
| { |
| GLint stride = 0; |
| const Utils::Type& type = getType(test_case_index); |
| const GLuint type_size = type.GetSize(false); |
| |
| program.GetResource(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, GL_TRANSFORM_FEEDBACK_BUFFER_STRIDE, |
| 1 /* buf_size */, &stride); |
| |
| if ((GLint)(3 * type_size) != stride) |
| { |
| out_stream << "Stride is: " << stride << " expected: " << (3 * type_size); |
| |
| return false; |
| } |
| |
| return true; |
| } |
| |
| /** Constructor |
| * |
| * @param context Test context |
| **/ |
| XFBVertexStreamsTest::XFBVertexStreamsTest(deqp::Context& context) |
| : BufferTestBase(context, "xfb_vertex_streams", |
| "Test verifies that xfb qualifier works with multiple output streams") |
| { |
| /* Nothing to be done here */ |
| } |
| |
| /** Get descriptors of buffers necessary for test |
| * |
| * @param ignored |
| * @param out_descriptors Descriptors of buffers used by test |
| **/ |
| void XFBVertexStreamsTest::getBufferDescriptors(glw::GLuint /* test_case_index */, |
| bufferDescriptor::Vector& out_descriptors) |
| { |
| const Utils::Type& type = Utils::Type::vec4; |
| |
| /* Test needs single uniform and three xfbs */ |
| out_descriptors.resize(4); |
| |
| /* Get references */ |
| bufferDescriptor& uniform = out_descriptors[0]; |
| bufferDescriptor& xfb_1 = out_descriptors[1]; |
| bufferDescriptor& xfb_2 = out_descriptors[2]; |
| bufferDescriptor& xfb_3 = out_descriptors[3]; |
| |
| /* Index */ |
| uniform.m_index = 0; |
| xfb_1.m_index = 1; |
| xfb_2.m_index = 2; |
| xfb_3.m_index = 3; |
| |
| /* Target */ |
| uniform.m_target = Utils::Buffer::Uniform; |
| xfb_1.m_target = Utils::Buffer::Transform_feedback; |
| xfb_2.m_target = Utils::Buffer::Transform_feedback; |
| xfb_3.m_target = Utils::Buffer::Transform_feedback; |
| |
| /* Data */ |
| const std::vector<GLubyte>& goku_data = type.GenerateData(); |
| const std::vector<GLubyte>& gohan_data = type.GenerateData(); |
| const std::vector<GLubyte>& goten_data = type.GenerateData(); |
| const std::vector<GLubyte>& picolo_data = type.GenerateData(); |
| const std::vector<GLubyte>& vegeta_data = type.GenerateData(); |
| const std::vector<GLubyte>& bulma_data = type.GenerateData(); |
| |
| const GLuint type_size = static_cast<GLuint>(vegeta_data.size()); |
| |
| /* Uniform data */ |
| uniform.m_initial_data.resize(6 * type_size); |
| memcpy(&uniform.m_initial_data[0] + 0, &goku_data[0], type_size); |
| memcpy(&uniform.m_initial_data[0] + type_size, &gohan_data[0], type_size); |
| memcpy(&uniform.m_initial_data[0] + 2 * type_size, &goten_data[0], type_size); |
| memcpy(&uniform.m_initial_data[0] + 3 * type_size, &picolo_data[0], type_size); |
| memcpy(&uniform.m_initial_data[0] + 4 * type_size, &vegeta_data[0], type_size); |
| memcpy(&uniform.m_initial_data[0] + 5 * type_size, &bulma_data[0], type_size); |
| |
| /* XFB data */ |
| static const GLuint xfb_stride = 64; |
| xfb_1.m_initial_data.resize(xfb_stride); |
| xfb_1.m_expected_data.resize(xfb_stride); |
| xfb_2.m_initial_data.resize(xfb_stride); |
| xfb_2.m_expected_data.resize(xfb_stride); |
| xfb_3.m_initial_data.resize(xfb_stride); |
| xfb_3.m_expected_data.resize(xfb_stride); |
| |
| for (GLuint i = 0; i < xfb_stride; ++i) |
| { |
| xfb_1.m_initial_data[i] = (glw::GLubyte)i; |
| xfb_1.m_expected_data[i] = (glw::GLubyte)i; |
| xfb_2.m_initial_data[i] = (glw::GLubyte)i; |
| xfb_2.m_expected_data[i] = (glw::GLubyte)i; |
| xfb_3.m_initial_data[i] = (glw::GLubyte)i; |
| xfb_3.m_expected_data[i] = (glw::GLubyte)i; |
| } |
| |
| memcpy(&xfb_1.m_expected_data[0] + 48, &goku_data[0], type_size); |
| memcpy(&xfb_1.m_expected_data[0] + 32, &gohan_data[0], type_size); |
| memcpy(&xfb_1.m_expected_data[0] + 16, &goten_data[0], type_size); |
| memcpy(&xfb_3.m_expected_data[0] + 48, &picolo_data[0], type_size); |
| memcpy(&xfb_3.m_expected_data[0] + 32, &vegeta_data[0], type_size); |
| memcpy(&xfb_2.m_expected_data[0] + 32, &bulma_data[0], type_size); |
| } |
| |
| /** Get body of main function for given shader stage |
| * |
| * @param ignored |
| * @param stage Shader stage |
| * @param out_assignments Set to empty |
| * @param out_calculations Set to empty |
| **/ |
| void XFBVertexStreamsTest::getShaderBody(GLuint /* test_case_index */, Utils::Shader::STAGES stage, |
| std::string& out_assignments, std::string& out_calculations) |
| { |
| out_calculations = ""; |
| |
| // the shader declares the output variables with different "stream" qualifier, to make the data can export to |
| // each stream, we must call the function EmitStreamVertex() and EndStreamPrimitive() to make each vertex emitted |
| // by the GS is assigned to specific stream. |
| static const GLchar* gs = " goku = uni_goku;\n" |
| " gohan = uni_gohan;\n" |
| " goten = uni_goten;\n" |
| " EmitStreamVertex(0);\n" |
| " EndStreamPrimitive(0);\n" |
| " picolo = uni_picolo;\n" |
| " vegeta = uni_vegeta;\n" |
| " EmitStreamVertex(1);\n" |
| " EndStreamPrimitive(1);\n" |
| " bulma = uni_bulma;\n" |
| " EmitStreamVertex(2);\n" |
| " EndStreamPrimitive(2);\n"; |
| |
| static const GLchar* fs = " fs_out = gohan + goku + goten;\n"; |
| |
| const GLchar* assignments = ""; |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| assignments = fs; |
| break; |
| case Utils::Shader::GEOMETRY: |
| assignments = gs; |
| break; |
| default: |
| break; |
| } |
| |
| out_assignments = assignments; |
| } |
| |
| /** Get interface of shader |
| * |
| * @param ignored |
| * @param stage Shader stage |
| * @param out_interface Set to "" |
| **/ |
| void XFBVertexStreamsTest::getShaderInterface(GLuint /* test_case_index */, Utils::Shader::STAGES stage, |
| std::string& out_interface) |
| { |
| static const GLchar* gs = "layout (xfb_buffer = 1, xfb_stride = 64) out;\n" |
| "layout (xfb_buffer = 2, xfb_stride = 64) out;\n" |
| "layout (xfb_buffer = 3, xfb_stride = 64) out;\n" |
| "\n" |
| "layout (stream = 0, xfb_buffer = 1, xfb_offset = 48) out vec4 goku;\n" |
| "layout (stream = 0, xfb_buffer = 1, xfb_offset = 32) out vec4 gohan;\n" |
| "layout (stream = 0, xfb_buffer = 1, xfb_offset = 16) out vec4 goten;\n" |
| "layout (stream = 1, xfb_buffer = 3, xfb_offset = 48) out vec4 picolo;\n" |
| "layout (stream = 1, xfb_buffer = 3, xfb_offset = 32) out vec4 vegeta;\n" |
| "layout (stream = 2, xfb_buffer = 2, xfb_offset = 32) out vec4 bulma;\n" |
| "\n" |
| "layout(binding = 0) uniform gs_block {\n" |
| " vec4 uni_goku;\n" |
| " vec4 uni_gohan;\n" |
| " vec4 uni_goten;\n" |
| " vec4 uni_picolo;\n" |
| " vec4 uni_vegeta;\n" |
| " vec4 uni_bulma;\n" |
| "};\n"; |
| /* |
| Fixed incorrect usage of in/out qualifier, the following variable should be input symbols for fragment shader |
| */ |
| static const GLchar* fs = "in vec4 goku;\n" |
| "in vec4 gohan;\n" |
| "in vec4 goten;\n" |
| "\n" |
| "out vec4 fs_out;\n"; |
| |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| out_interface = fs; |
| break; |
| case Utils::Shader::GEOMETRY: |
| out_interface = gs; |
| break; |
| default: |
| out_interface = ""; |
| return; |
| } |
| } |
| |
| /** Constructor |
| * |
| * @param context Test framework context |
| **/ |
| XFBMultipleVertexStreamsTest::XFBMultipleVertexStreamsTest(deqp::Context& context) |
| : NegativeTestBase( |
| context, "xfb_multiple_vertex_streams", |
| "Test verifies that compiler reports error when multiple streams are captured with same xfb_buffer") |
| { |
| } |
| |
| /** Source for given test case and stage |
| * |
| * @param ignored |
| * @param stage Shader stage |
| * |
| * @return Shader source |
| **/ |
| std::string XFBMultipleVertexStreamsTest::getShaderSource(GLuint /* test_case_index */, Utils::Shader::STAGES stage) |
| { |
| static const GLchar* var_definition = "const uint valid_stride = 64;\n" |
| "\n" |
| "layout (xfb_buffer = 1, xfb_stride = valid_stride) out;\n" |
| "layout (xfb_buffer = 3, xfb_stride = valid_stride) out;\n" |
| "\n" |
| "\n" |
| #if DEBUG_NEG_REMOVE_ERROR |
| "layout (stream = 0, xfb_buffer = 1, xfb_offset = 48) out vec4 goku;\n" |
| "layout (stream = 1, xfb_buffer = 3, xfb_offset = 32) out vec4 gohan;\n" |
| "layout (stream = 2, xfb_buffer = 2, xfb_offset = 16) out vec4 goten;\n"; |
| #else |
| "layout (stream = 0, xfb_buffer = 1, xfb_offset = 48) out vec4 goku;\n" |
| "layout (stream = 1, xfb_buffer = 1, xfb_offset = 32) out vec4 gohan;\n" |
| "layout (stream = 2, xfb_buffer = 1, xfb_offset = 16) out vec4 goten;\n"; |
| #endif /* DEBUG_NEG_REMOVE_ERROR */ |
| static const GLchar* var_use = " goku = result / 2;\n" |
| " gohan = result / 4;\n" |
| " goten = result / 6;\n"; |
| static const GLchar* fs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 gs_fs;\n" |
| "in vec4 goku;\n" |
| "out vec4 fs_out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " fs_out = gs_fs + goku;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* gs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 vs_gs[];\n" |
| "out vec4 gs_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = vs_gs[0];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " gs_fs = result;\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 vs_gs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vs_gs = in_vs;\n" |
| "}\n" |
| "\n"; |
| |
| std::string source; |
| |
| if (Utils::Shader::GEOMETRY == stage) |
| { |
| size_t position = 0; |
| |
| source = gs; |
| |
| Utils::replaceToken("VAR_DEFINITION", position, var_definition, source); |
| Utils::replaceToken("VARIABLE_USE", position, var_use, source); |
| } |
| else |
| { |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs; |
| break; |
| default: |
| source = ""; |
| } |
| } |
| |
| return source; |
| } |
| |
| /** Selects if "compute" stage is relevant for test |
| * |
| * @param ignored |
| * |
| * @return false |
| **/ |
| bool XFBMultipleVertexStreamsTest::isComputeRelevant(GLuint /* test_case_index */) |
| { |
| return false; |
| } |
| |
| /** Constructor |
| * |
| * @param context Test framework context |
| **/ |
| XFBExceedBufferLimitTest::XFBExceedBufferLimitTest(deqp::Context& context) |
| : NegativeTestBase(context, "xfb_exceed_buffer_limit", |
| "Test verifies that compiler reports error when xfb_buffer qualifier exceeds limit") |
| { |
| } |
| |
| /** Source for given test case and stage |
| * |
| * @param test_case_index Index of test case |
| * @param stage Shader stage |
| * |
| * @return Shader source |
| **/ |
| std::string XFBExceedBufferLimitTest::getShaderSource(GLuint test_case_index, Utils::Shader::STAGES stage) |
| { |
| static const GLchar* block_var_definition = "const uint buffer_index = MAX_BUFFER;\n" |
| "\n" |
| #if DEBUG_NEG_REMOVE_ERROR |
| "layout (xfb_buffer = 0, xfb_offset = 0) out Goku {\n" |
| #else |
| "layout (xfb_buffer = buffer_index, xfb_offset = 0) out Goku {\n" |
| #endif /* DEBUG_NEG_REMOVE_ERROR */ |
| " vec4 member;\n" |
| "} goku;\n"; |
| static const GLchar* global_var_definition = "const uint buffer_index = MAX_BUFFER;\n" |
| "\n" |
| #if DEBUG_NEG_REMOVE_ERROR |
| "layout (xfb_buffer = 0) out;\n"; |
| #else |
| "layout (xfb_buffer = buffer_index) out;\n"; |
| #endif /* DEBUG_NEG_REMOVE_ERROR */ |
| static const GLchar* vector_var_definition = "const uint buffer_index = MAX_BUFFER;\n" |
| "\n" |
| #if DEBUG_NEG_REMOVE_ERROR |
| "layout (xfb_buffer = 0) out vec4 goku;\n"; |
| #else |
| "layout (xfb_buffer = buffer_index) out vec4 goku;\n"; |
| #endif /* DEBUG_NEG_REMOVE_ERROR */ |
| static const GLchar* block_use = " goku.member = result / 2;\n"; |
| static const GLchar* global_use = ""; |
| static const GLchar* vector_use = " goku = result / 2;\n"; |
| static const GLchar* fs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 any_fs;\n" |
| "out vec4 fs_out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " fs_out = any_fs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* gs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 vs_any[];\n" |
| "out vec4 any_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = vs_any[0];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " any_fs = result;\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " any_fs = result;\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| " any_fs = result;\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " any_fs = result;\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tcs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "in vec4 vs_any[];\n" |
| "out vec4 tcs_tes[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| "\n" |
| " tcs_tes[gl_InvocationID] = vs_any[gl_InvocationID];\n" |
| "\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tes_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(isolines, point_mode) in;\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 tcs_tes[];\n" |
| "out vec4 any_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = tcs_tes[0];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " any_fs += result;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 vs_any;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vs_any = in_vs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 any_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = in_vs;\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " any_fs = result;\n" |
| "}\n" |
| "\n"; |
| |
| std::string source; |
| testCase& test_case = m_test_cases[test_case_index]; |
| |
| if (test_case.m_stage == stage) |
| { |
| GLchar buffer[16]; |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| GLint max_n_xfb = 0; |
| size_t position = 0; |
| const GLchar* var_definition = 0; |
| const GLchar* var_use = 0; |
| |
| gl.getIntegerv(GL_MAX_TRANSFORM_FEEDBACK_BUFFERS, &max_n_xfb); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv"); |
| |
| sprintf(buffer, "%d", max_n_xfb); |
| |
| switch (test_case.m_case) |
| { |
| case BLOCK: |
| var_definition = block_var_definition; |
| var_use = block_use; |
| break; |
| case GLOBAL: |
| var_definition = global_var_definition; |
| var_use = global_use; |
| break; |
| case VECTOR: |
| var_definition = vector_var_definition; |
| var_use = vector_use; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| switch (stage) |
| { |
| case Utils::Shader::GEOMETRY: |
| source = gs_tested; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| source = tes_tested; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs_tested; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| Utils::replaceToken("VAR_DEFINITION", position, var_definition, source); |
| position = 0; |
| Utils::replaceToken("MAX_BUFFER", position, buffer, source); |
| Utils::replaceToken("VARIABLE_USE", position, var_use, source); |
| } |
| else |
| { |
| switch (test_case.m_stage) |
| { |
| case Utils::Shader::GEOMETRY: |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs; |
| break; |
| default: |
| source = ""; |
| } |
| break; |
| case Utils::Shader::TESS_EVAL: |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| source = tcs; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs; |
| break; |
| default: |
| source = ""; |
| } |
| break; |
| case Utils::Shader::VERTEX: |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs; |
| break; |
| default: |
| source = ""; |
| } |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| break; |
| } |
| } |
| |
| return source; |
| } |
| |
| /** Get description of test case |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return Test case description |
| **/ |
| std::string XFBExceedBufferLimitTest::getTestCaseName(GLuint test_case_index) |
| { |
| std::stringstream stream; |
| testCase& test_case = m_test_cases[test_case_index]; |
| |
| stream << "Stage: " << Utils::Shader::GetStageName(test_case.m_stage) << ", case: "; |
| |
| switch (test_case.m_case) |
| { |
| case BLOCK: |
| stream << "BLOCK"; |
| break; |
| case GLOBAL: |
| stream << "GLOBAL"; |
| break; |
| case VECTOR: |
| stream << "VECTOR"; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| return stream.str(); |
| } |
| |
| /** Get number of test cases |
| * |
| * @return Number of test cases |
| **/ |
| GLuint XFBExceedBufferLimitTest::getTestCaseNumber() |
| { |
| return static_cast<GLuint>(m_test_cases.size()); |
| } |
| |
| /** Selects if "compute" stage is relevant for test |
| * |
| * @param ignored |
| * |
| * @return false |
| **/ |
| bool XFBExceedBufferLimitTest::isComputeRelevant(GLuint /* test_case_index */) |
| { |
| return false; |
| } |
| |
| /** Prepare all test cases |
| * |
| **/ |
| void XFBExceedBufferLimitTest::testInit() |
| { |
| for (GLuint c = 0; c < CASE_MAX; ++c) |
| { |
| for (GLuint stage = 0; stage < Utils::Shader::STAGE_MAX; ++stage) |
| { |
| if ((Utils::Shader::COMPUTE == stage) || (Utils::Shader::TESS_CTRL == stage) || |
| (Utils::Shader::FRAGMENT == stage)) |
| { |
| continue; |
| } |
| |
| testCase test_case = { (CASES)c, (Utils::Shader::STAGES)stage }; |
| |
| m_test_cases.push_back(test_case); |
| } |
| } |
| } |
| |
| /** Constructor |
| * |
| * @param context Test framework context |
| **/ |
| XFBExceedOffsetLimitTest::XFBExceedOffsetLimitTest(deqp::Context& context) |
| : NegativeTestBase(context, "xfb_exceed_offset_limit", |
| "Test verifies that compiler reports error when xfb_offset qualifier exceeds limit") |
| { |
| } |
| |
| /** Source for given test case and stage |
| * |
| * @param test_case_index Index of test case |
| * @param stage Shader stage |
| * |
| * @return Shader source |
| **/ |
| std::string XFBExceedOffsetLimitTest::getShaderSource(GLuint test_case_index, Utils::Shader::STAGES stage) |
| { |
| static const GLchar* block_var_definition = "const uint overflow_offset = MAX_SIZE + 16;\n" |
| "\n" |
| #if DEBUG_NEG_REMOVE_ERROR |
| "layout (xfb_buffer = 0, xfb_offset = 0) out Goku {\n" |
| #else |
| "layout (xfb_buffer = 0, xfb_offset = overflow_offset + 16) out Goku " |
| "{\n" |
| #endif /* DEBUG_NEG_REMOVE_ERROR */ |
| " vec4 member;\n" |
| "} goku;\n"; |
| static const GLchar* global_var_definition = "const uint overflow_offset = MAX_SIZE + 16;\n" |
| "\n" |
| #if DEBUG_NEG_REMOVE_ERROR |
| "layout (xfb_buffer = 0, xfb_stride = 0) out;\n"; |
| #else |
| "layout (xfb_buffer = 0, xfb_stride = overflow_offset) out;\n"; |
| #endif /* DEBUG_NEG_REMOVE_ERROR */ |
| static const GLchar* vector_var_definition = "const uint overflow_offset = MAX_SIZE + 16;\n" |
| "\n" |
| #if DEBUG_NEG_REMOVE_ERROR |
| "layout (xfb_buffer = 0, xfb_offset = 0) out vec4 goku;\n"; |
| #else |
| "layout (xfb_buffer = 0, xfb_offset = overflow_offset) out vec4 " |
| "goku;\n"; |
| #endif /* DEBUG_NEG_REMOVE_ERROR */ |
| static const GLchar* block_use = " goku.member = result / 2;\n"; |
| static const GLchar* global_use = ""; |
| static const GLchar* vector_use = " goku = result / 2;\n"; |
| static const GLchar* fs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 any_fs;\n" |
| "out vec4 fs_out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " fs_out = any_fs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* gs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 vs_any[];\n" |
| "out vec4 any_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = vs_any[0];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " any_fs = result;\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " any_fs = result;\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| " any_fs = result;\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " any_fs = result;\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tcs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "in vec4 vs_any[];\n" |
| "out vec4 tcs_tes[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| "\n" |
| " tcs_tes[gl_InvocationID] = vs_any[gl_InvocationID];\n" |
| "\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tes_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(isolines, point_mode) in;\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 tcs_tes[];\n" |
| "out vec4 any_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = tcs_tes[0];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " any_fs += result;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 vs_any;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vs_any = in_vs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 any_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = in_vs;\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " any_fs = result;\n" |
| "}\n" |
| "\n"; |
| |
| std::string source; |
| testCase& test_case = m_test_cases[test_case_index]; |
| |
| if (test_case.m_stage == stage) |
| { |
| GLchar buffer[16]; |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| GLint max_n_xfb_comp = 0; |
| GLint max_n_xfb_bytes = 0; |
| size_t position = 0; |
| const GLchar* var_definition = 0; |
| const GLchar* var_use = 0; |
| |
| gl.getIntegerv(GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS, &max_n_xfb_comp); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv"); |
| |
| max_n_xfb_bytes = max_n_xfb_comp * 4; |
| |
| sprintf(buffer, "%d", max_n_xfb_bytes); |
| |
| switch (test_case.m_case) |
| { |
| case BLOCK: |
| var_definition = block_var_definition; |
| var_use = block_use; |
| break; |
| case GLOBAL: |
| var_definition = global_var_definition; |
| var_use = global_use; |
| break; |
| case VECTOR: |
| var_definition = vector_var_definition; |
| var_use = vector_use; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| switch (stage) |
| { |
| case Utils::Shader::GEOMETRY: |
| source = gs_tested; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| source = tes_tested; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs_tested; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| Utils::replaceToken("VAR_DEFINITION", position, var_definition, source); |
| position = 0; |
| Utils::replaceToken("MAX_SIZE", position, buffer, source); |
| Utils::replaceToken("VARIABLE_USE", position, var_use, source); |
| } |
| else |
| { |
| switch (test_case.m_stage) |
| { |
| case Utils::Shader::GEOMETRY: |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs; |
| break; |
| default: |
| source = ""; |
| } |
| break; |
| case Utils::Shader::TESS_EVAL: |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| source = tcs; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs; |
| break; |
| default: |
| source = ""; |
| } |
| break; |
| case Utils::Shader::VERTEX: |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs; |
| break; |
| default: |
| source = ""; |
| } |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| break; |
| } |
| } |
| |
| return source; |
| } |
| |
| /** Get description of test case |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return Test case description |
| **/ |
| std::string XFBExceedOffsetLimitTest::getTestCaseName(GLuint test_case_index) |
| { |
| std::stringstream stream; |
| testCase& test_case = m_test_cases[test_case_index]; |
| |
| stream << "Stage: " << Utils::Shader::GetStageName(test_case.m_stage) << ", case: "; |
| |
| switch (test_case.m_case) |
| { |
| case BLOCK: |
| stream << "BLOCK"; |
| break; |
| case GLOBAL: |
| stream << "GLOBAL"; |
| break; |
| case VECTOR: |
| stream << "VECTOR"; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| return stream.str(); |
| } |
| |
| /** Get number of test cases |
| * |
| * @return Number of test cases |
| **/ |
| GLuint XFBExceedOffsetLimitTest::getTestCaseNumber() |
| { |
| return static_cast<GLuint>(m_test_cases.size()); |
| } |
| |
| /** Selects if "compute" stage is relevant for test |
| * |
| * @param ignored |
| * |
| * @return false |
| **/ |
| bool XFBExceedOffsetLimitTest::isComputeRelevant(GLuint /* test_case_index */) |
| { |
| return false; |
| } |
| |
| /** Prepare all test cases |
| * |
| **/ |
| void XFBExceedOffsetLimitTest::testInit() |
| { |
| for (GLuint c = 0; c < CASE_MAX; ++c) |
| { |
| for (GLuint stage = 0; stage < Utils::Shader::STAGE_MAX; ++stage) |
| { |
| if ((Utils::Shader::COMPUTE == stage) || (Utils::Shader::TESS_CTRL == stage) || |
| (Utils::Shader::FRAGMENT == stage)) |
| { |
| continue; |
| } |
| |
| testCase test_case = { (CASES)c, (Utils::Shader::STAGES)stage }; |
| |
| m_test_cases.push_back(test_case); |
| } |
| } |
| } |
| |
| /** Constructor |
| * |
| * @param context Test context |
| **/ |
| XFBGlobalBufferTest::XFBGlobalBufferTest(deqp::Context& context) |
| : BufferTestBase(context, "xfb_global_buffer", "Test verifies that global xfb_buffer qualifier is respected") |
| { |
| /* Nothing to be done here */ |
| } |
| |
| /** Get descriptors of buffers necessary for test |
| * |
| * @param test_case_index Index of test case |
| * @param out_descriptors Descriptors of buffers used by test |
| **/ |
| void XFBGlobalBufferTest::getBufferDescriptors(glw::GLuint test_case_index, bufferDescriptor::Vector& out_descriptors) |
| { |
| // the function "getType(test_case_index)" can't return correct data type, so change code as following: |
| const Utils::Type& type = m_test_cases[test_case_index].m_type; |
| |
| /* Test needs single uniform and two xfbs */ |
| out_descriptors.resize(3); |
| |
| /* Get references */ |
| bufferDescriptor& uniform = out_descriptors[0]; |
| bufferDescriptor& xfb_1 = out_descriptors[1]; |
| bufferDescriptor& xfb_3 = out_descriptors[2]; |
| |
| /* Index */ |
| uniform.m_index = 0; |
| xfb_1.m_index = 1; |
| xfb_3.m_index = 3; |
| |
| /* Target */ |
| uniform.m_target = Utils::Buffer::Uniform; |
| xfb_1.m_target = Utils::Buffer::Transform_feedback; |
| xfb_3.m_target = Utils::Buffer::Transform_feedback; |
| |
| /* Data */ |
| const GLuint gen_start = Utils::s_rand; |
| const std::vector<GLubyte>& chichi_data = type.GenerateData(); |
| const std::vector<GLubyte>& bulma_data = type.GenerateData(); |
| const std::vector<GLubyte>& trunks_data = type.GenerateData(); |
| const std::vector<GLubyte>& bra_data = type.GenerateData(); |
| const std::vector<GLubyte>& gohan_data = type.GenerateData(); |
| const std::vector<GLubyte>& goten_data = type.GenerateData(); |
| |
| Utils::s_rand = gen_start; |
| const std::vector<GLubyte>& chichi_data_pck = type.GenerateDataPacked(); |
| const std::vector<GLubyte>& bulma_data_pck = type.GenerateDataPacked(); |
| const std::vector<GLubyte>& trunks_data_pck = type.GenerateDataPacked(); |
| const std::vector<GLubyte>& bra_data_pck = type.GenerateDataPacked(); |
| const std::vector<GLubyte>& gohan_data_pck = type.GenerateDataPacked(); |
| const std::vector<GLubyte>& goten_data_pck = type.GenerateDataPacked(); |
| |
| const GLuint type_size = static_cast<GLuint>(chichi_data.size()); |
| const GLuint type_size_pck = static_cast<GLuint>(chichi_data_pck.size()); |
| |
| /* Uniform data */ |
| uniform.m_initial_data.resize(6 * type_size); |
| memcpy(&uniform.m_initial_data[0] + 0, &chichi_data[0], type_size); |
| memcpy(&uniform.m_initial_data[0] + type_size, &bulma_data[0], type_size); |
| memcpy(&uniform.m_initial_data[0] + 2 * type_size, &trunks_data[0], type_size); |
| memcpy(&uniform.m_initial_data[0] + 3 * type_size, &bra_data[0], type_size); |
| memcpy(&uniform.m_initial_data[0] + 4 * type_size, &gohan_data[0], type_size); |
| memcpy(&uniform.m_initial_data[0] + 5 * type_size, &goten_data[0], type_size); |
| |
| /* XFB data */ |
| xfb_1.m_initial_data.resize(3 * type_size_pck); |
| xfb_1.m_expected_data.resize(3 * type_size_pck); |
| xfb_3.m_initial_data.resize(3 * type_size_pck); |
| xfb_3.m_expected_data.resize(3 * type_size_pck); |
| |
| for (GLuint i = 0; i < 3 * type_size_pck; ++i) |
| { |
| xfb_1.m_initial_data[i] = (glw::GLubyte)i; |
| xfb_1.m_expected_data[i] = (glw::GLubyte)i; |
| xfb_3.m_initial_data[i] = (glw::GLubyte)i; |
| xfb_3.m_expected_data[i] = (glw::GLubyte)i; |
| } |
| |
| memcpy(&xfb_3.m_expected_data[0] + 2 * type_size_pck, &chichi_data_pck[0], type_size_pck); |
| memcpy(&xfb_1.m_expected_data[0] + 0 * type_size_pck, &bulma_data_pck[0], type_size_pck); |
| memcpy(&xfb_1.m_expected_data[0] + 1 * type_size_pck, &trunks_data_pck[0], type_size_pck); |
| memcpy(&xfb_1.m_expected_data[0] + 2 * type_size_pck, &bra_data_pck[0], type_size_pck); |
| memcpy(&xfb_3.m_expected_data[0] + 0 * type_size_pck, &gohan_data_pck[0], type_size_pck); |
| memcpy(&xfb_3.m_expected_data[0] + 1 * type_size_pck, &goten_data_pck[0], type_size_pck); |
| } |
| |
| /** Source for given test case and stage |
| * |
| * @param test_case_index Index of test case |
| * @param stage Shader stage |
| * |
| * @return Shader source |
| **/ |
| std::string XFBGlobalBufferTest::getShaderSource(GLuint test_case_index, Utils::Shader::STAGES stage) |
| { |
| static const GLchar* fs = |
| "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "flat in TYPE chichi;\n" |
| "flat in TYPE bulma;\n" |
| "in Vegeta {\n" |
| " flat TYPE trunk;\n" |
| " flat TYPE bra;\n" |
| "} vegeta;\n" |
| "in Goku {\n" |
| " flat TYPE gohan;\n" |
| " flat TYPE goten;\n" |
| "} goku;\n" |
| "\n" |
| "out vec4 fs_out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " fs_out = vec4(1);\n" |
| " if (TYPE(1) != chichi + bulma + vegeta.trunk + vegeta.bra + goku.gohan + goku.goten)\n" |
| " {\n" |
| " fs_out = vec4(0);\n" |
| " }\n" |
| "}\n" |
| "\n"; |
| |
| static const GLchar* gs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(points, max_vertices = 1) out;\n" |
| "\n" |
| "INTERFACE" |
| "\n" |
| "void main()\n" |
| "{\n" |
| "ASSIGNMENTS" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| |
| static const GLchar* tcs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| |
| static const GLchar* tes = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(isolines, point_mode) in;\n" |
| "\n" |
| "INTERFACE" |
| "\n" |
| "void main()\n" |
| "{\n" |
| "ASSIGNMENTS" |
| "}\n" |
| "\n"; |
| |
| static const GLchar* vs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| "}\n" |
| "\n"; |
| |
| static const GLchar* vs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "INTERFACE" |
| "\n" |
| "void main()\n" |
| "{\n" |
| "ASSIGNMENTS" |
| "}\n" |
| "\n"; |
| |
| std::string source; |
| const _testCase& test_case = m_test_cases[test_case_index]; |
| const GLchar* type_name = test_case.m_type.GetGLSLTypeName(); |
| |
| if (test_case.m_stage == stage) |
| { |
| std::string assignments = " chichi = uni_chichi;\n" |
| " bulma = uni_bulma;\n" |
| " vegeta.trunk = uni_trunk;\n" |
| " vegeta.bra = uni_bra;\n" |
| " goku.gohan = uni_gohan;\n" |
| " goku.goten = uni_goten;\n"; |
| |
| std::string interface = "layout (xfb_buffer = 3) out;\n" |
| "\n" |
| "const uint type_size = SIZE;\n" |
| "\n" |
| "layout ( xfb_offset = 2 * type_size) flat out TYPE chichi;\n" |
| "layout (xfb_buffer = 1, xfb_offset = 0) flat out TYPE bulma;\n" |
| "layout (xfb_buffer = 1, xfb_offset = 1 * type_size) out Vegeta {\n" |
| " flat TYPE trunk;\n" |
| " flat TYPE bra;\n" |
| "} vegeta;\n" |
| "layout ( xfb_offset = 0) out Goku {\n" |
| " flat TYPE gohan;\n" |
| " flat TYPE goten;\n" |
| "} goku;\n" |
| "\n" |
| // Uniform block must be declared with std140, otherwise each block member is not packed |
| "layout(binding = 0, std140) uniform block {\n" |
| " TYPE uni_chichi;\n" |
| " TYPE uni_bulma;\n" |
| " TYPE uni_trunk;\n" |
| " TYPE uni_bra;\n" |
| " TYPE uni_gohan;\n" |
| " TYPE uni_goten;\n" |
| "};\n"; |
| |
| /* Prepare interface string */ |
| { |
| GLchar buffer[16]; |
| size_t position = 0; |
| const GLuint type_size = test_case.m_type.GetSize(); |
| |
| sprintf(buffer, "%d", type_size); |
| |
| Utils::replaceToken("SIZE", position, buffer, interface); |
| Utils::replaceAllTokens("TYPE", type_name, interface); |
| } |
| |
| switch (stage) |
| { |
| case Utils::Shader::GEOMETRY: |
| source = gs; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| source = tes; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs_tested; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| /* Replace tokens */ |
| { |
| size_t position = 0; |
| |
| Utils::replaceToken("INTERFACE", position, interface.c_str(), source); |
| Utils::replaceToken("ASSIGNMENTS", position, assignments.c_str(), source); |
| } |
| } |
| else |
| { |
| switch (test_case.m_stage) |
| { |
| case Utils::Shader::GEOMETRY: |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs; |
| Utils::replaceAllTokens("TYPE", type_name, source); |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs; |
| break; |
| default: |
| source = ""; |
| } |
| break; |
| case Utils::Shader::TESS_EVAL: |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs; |
| Utils::replaceAllTokens("TYPE", type_name, source); |
| break; |
| case Utils::Shader::TESS_CTRL: |
| source = tcs; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs; |
| break; |
| default: |
| source = ""; |
| } |
| break; |
| case Utils::Shader::VERTEX: |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs; |
| Utils::replaceAllTokens("TYPE", type_name, source); |
| break; |
| default: |
| source = ""; |
| } |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| break; |
| } |
| } |
| |
| return source; |
| } |
| |
| /** Get name of test case |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return Name of case |
| **/ |
| std::string XFBGlobalBufferTest::getTestCaseName(GLuint test_case_index) |
| { |
| std::string name; |
| const _testCase& test_case = m_test_cases[test_case_index]; |
| |
| name = "Tested stage: "; |
| name.append(Utils::Shader::GetStageName(test_case.m_stage)); |
| name.append(". Tested type: "); |
| name.append(test_case.m_type.GetGLSLTypeName()); |
| |
| return name; |
| } |
| |
| /** Get number of cases |
| * |
| * @return Number of test cases |
| **/ |
| GLuint XFBGlobalBufferTest::getTestCaseNumber() |
| { |
| return static_cast<GLuint>(m_test_cases.size()); |
| } |
| |
| /** Prepare set of test cases |
| * |
| **/ |
| void XFBGlobalBufferTest::testInit() |
| { |
| GLuint n_types = getTypesNumber(); |
| |
| for (GLuint i = 0; i < n_types; ++i) |
| { |
| const Utils::Type& type = getType(i); |
| /* |
| When the tfx varying is the following type, the number of output exceeds the gl_MaxVaryingComponents, which will |
| cause a link time error. |
| */ |
| if (strcmp(type.GetGLSLTypeName(), "dmat3") == 0 || strcmp(type.GetGLSLTypeName(), "dmat4") == 0 || |
| strcmp(type.GetGLSLTypeName(), "dmat3x4") == 0 || strcmp(type.GetGLSLTypeName(), "dmat4x3") == 0) |
| { |
| continue; |
| } |
| const _testCase test_cases[] = { { Utils::Shader::VERTEX, type }, |
| { Utils::Shader::GEOMETRY, type }, |
| { Utils::Shader::TESS_EVAL, type } }; |
| |
| m_test_cases.push_back(test_cases[0]); |
| m_test_cases.push_back(test_cases[1]); |
| m_test_cases.push_back(test_cases[2]); |
| } |
| } |
| |
| /** Constructor |
| * |
| * @param context Test context |
| **/ |
| XFBStrideTest::XFBStrideTest(deqp::Context& context) |
| : BufferTestBase(context, "xfb_stride", "Test verifies that correct stride is used for all types") |
| { |
| /* Nothing to be done here */ |
| } |
| |
| /** Execute drawArrays for single vertex |
| * |
| * @param test_case_index |
| * |
| * @return true |
| **/ |
| bool XFBStrideTest::executeDrawCall(bool /* tesEnabled */, GLuint test_case_index) |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| GLenum primitive_type = GL_PATCHES; |
| const testCase& test_case = m_test_cases[test_case_index]; |
| |
| if (Utils::Shader::VERTEX == test_case.m_stage) |
| { |
| primitive_type = GL_POINTS; |
| } |
| |
| gl.disable(GL_RASTERIZER_DISCARD); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Disable"); |
| |
| gl.beginTransformFeedback(GL_POINTS); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "BeginTransformFeedback"); |
| |
| gl.drawArrays(primitive_type, 0 /* first */, 2 /* count */); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays"); |
| |
| gl.endTransformFeedback(); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "EndTransformFeedback"); |
| |
| return true; |
| } |
| |
| /** Get descriptors of buffers necessary for test |
| * |
| * @param test_case_index Index of test case |
| * @param out_descriptors Descriptors of buffers used by test |
| **/ |
| void XFBStrideTest::getBufferDescriptors(GLuint test_case_index, bufferDescriptor::Vector& out_descriptors) |
| { |
| const testCase& test_case = m_test_cases[test_case_index]; |
| const Utils::Type& type = test_case.m_type; |
| |
| /* Test needs single uniform and xfb */ |
| out_descriptors.resize(2); |
| |
| /* Get references */ |
| bufferDescriptor& uniform = out_descriptors[0]; |
| bufferDescriptor& xfb = out_descriptors[1]; |
| |
| /* Index */ |
| uniform.m_index = 0; |
| xfb.m_index = 0; |
| |
| /* Target */ |
| uniform.m_target = Utils::Buffer::Uniform; |
| xfb.m_target = Utils::Buffer::Transform_feedback; |
| |
| /* Data */ |
| const GLuint rand_start = Utils::s_rand; |
| const std::vector<GLubyte>& uniform_data = type.GenerateData(); |
| |
| Utils::s_rand = rand_start; |
| const std::vector<GLubyte>& xfb_data = type.GenerateDataPacked(); |
| |
| const GLuint uni_type_size = static_cast<GLuint>(uniform_data.size()); |
| const GLuint xfb_type_size = static_cast<GLuint>(xfb_data.size()); |
| /* |
| Note: If xfb varying output from vertex shader, the variable "goku" will only output once to transform feedback buffer, |
| if xfb varying output from TES or GS, because the input primitive type in TES is defined as "layout(isolines, point_mode) in;", |
| the primitive type is line which make the variable "goku" will output twice to transform feedback buffer, so for vertex shader |
| only one valid data should be initialized in xfb.m_expected_data |
| */ |
| const GLuint xfb_data_size = (test_case.m_stage == Utils::Shader::VERTEX) ? xfb_type_size : xfb_type_size * 2; |
| /* Uniform data */ |
| uniform.m_initial_data.resize(uni_type_size); |
| memcpy(&uniform.m_initial_data[0] + 0 * uni_type_size, &uniform_data[0], uni_type_size); |
| |
| /* XFB data */ |
| xfb.m_initial_data.resize(xfb_data_size); |
| xfb.m_expected_data.resize(xfb_data_size); |
| |
| for (GLuint i = 0; i < xfb_data_size; ++i) |
| { |
| xfb.m_initial_data[i] = (glw::GLubyte)i; |
| xfb.m_expected_data[i] = (glw::GLubyte)i; |
| } |
| |
| if (test_case.m_stage == Utils::Shader::VERTEX) |
| { |
| memcpy(&xfb.m_expected_data[0] + 0 * xfb_type_size, &xfb_data[0], xfb_type_size); |
| } |
| else |
| { |
| memcpy(&xfb.m_expected_data[0] + 0 * xfb_type_size, &xfb_data[0], xfb_type_size); |
| memcpy(&xfb.m_expected_data[0] + 1 * xfb_type_size, &xfb_data[0], xfb_type_size); |
| } |
| } |
| |
| /** Get body of main function for given shader stage |
| * |
| * @param test_case_index Index of test case |
| * @param stage Shader stage |
| * @param out_assignments Set to empty |
| * @param out_calculations Set to empty |
| **/ |
| void XFBStrideTest::getShaderBody(GLuint test_case_index, Utils::Shader::STAGES stage, std::string& out_assignments, |
| std::string& out_calculations) |
| { |
| const testCase& test_case = m_test_cases[test_case_index]; |
| |
| out_calculations = ""; |
| |
| static const GLchar* vs_tes_gs = " goku = uni_goku;\n"; |
| static const GLchar* fs = " fs_out = vec4(1, 0.25, 0.5, 0.75);\n" |
| " if (TYPE(0) == goku)\n" |
| " {\n" |
| " fs_out = vec4(1, 0.75, 0.5, 0.5);\n" |
| " }\n"; |
| |
| const GLchar* assignments = ""; |
| |
| if (test_case.m_stage == stage) |
| { |
| switch (stage) |
| { |
| case Utils::Shader::GEOMETRY: |
| assignments = vs_tes_gs; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| assignments = vs_tes_gs; |
| break; |
| case Utils::Shader::VERTEX: |
| assignments = vs_tes_gs; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| } |
| else |
| { |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| assignments = fs; |
| break; |
| case Utils::Shader::GEOMETRY: |
| case Utils::Shader::TESS_CTRL: |
| case Utils::Shader::TESS_EVAL: |
| case Utils::Shader::VERTEX: |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| } |
| |
| out_assignments = assignments; |
| |
| if (Utils::Shader::FRAGMENT == stage) |
| { |
| Utils::replaceAllTokens("TYPE", test_case.m_type.GetGLSLTypeName(), out_assignments); |
| } |
| } |
| |
| /** Get interface of shader |
| * |
| * @param test_case_index Index of test case |
| * @param stage Shader stage |
| * @param out_interface Set to "" |
| **/ |
| void XFBStrideTest::getShaderInterface(GLuint test_case_index, Utils::Shader::STAGES stage, std::string& out_interface) |
| { |
| static const GLchar* vs_tes_gs = "layout (xfb_offset = 0) FLAT out TYPE goku;\n" |
| "\n" |
| "layout(std140, binding = 0) uniform Goku {\n" |
| " TYPE uni_goku;\n" |
| "};\n"; |
| static const GLchar* fs = "FLAT in TYPE goku;\n" |
| "\n" |
| "out vec4 fs_out;\n"; |
| |
| const testCase& test_case = m_test_cases[test_case_index]; |
| const GLchar* interface = ""; |
| const GLchar* flat = ""; |
| |
| if (test_case.m_stage == stage) |
| { |
| switch (stage) |
| { |
| case Utils::Shader::GEOMETRY: |
| interface = vs_tes_gs; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| interface = vs_tes_gs; |
| break; |
| case Utils::Shader::VERTEX: |
| interface = vs_tes_gs; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| } |
| else |
| { |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| interface = fs; |
| break; |
| case Utils::Shader::GEOMETRY: |
| case Utils::Shader::TESS_CTRL: |
| case Utils::Shader::TESS_EVAL: |
| case Utils::Shader::VERTEX: |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| } |
| |
| out_interface = interface; |
| |
| if (Utils::Type::Float != test_case.m_type.m_basic_type) |
| { |
| flat = "flat"; |
| } |
| |
| Utils::replaceAllTokens("FLAT", flat, out_interface); |
| Utils::replaceAllTokens("TYPE", test_case.m_type.GetGLSLTypeName(), out_interface); |
| } |
| |
| /** Get source code of shader |
| * |
| * @param test_case_index Index of test case |
| * @param stage Shader stage |
| * |
| * @return Source |
| **/ |
| std::string XFBStrideTest::getShaderSource(GLuint test_case_index, Utils::Shader::STAGES stage) |
| { |
| std::string source; |
| const testCase& test_case = m_test_cases[test_case_index]; |
| |
| switch (test_case.m_stage) |
| { |
| case Utils::Shader::VERTEX: |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| case Utils::Shader::VERTEX: |
| source = BufferTestBase::getShaderSource(test_case_index, stage); |
| break; |
| default: |
| break; |
| } |
| break; |
| |
| case Utils::Shader::TESS_EVAL: |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| case Utils::Shader::TESS_CTRL: |
| case Utils::Shader::TESS_EVAL: |
| case Utils::Shader::VERTEX: |
| source = BufferTestBase::getShaderSource(test_case_index, stage); |
| break; |
| default: |
| break; |
| } |
| break; |
| |
| case Utils::Shader::GEOMETRY: |
| source = BufferTestBase::getShaderSource(test_case_index, stage); |
| break; |
| |
| default: |
| TCU_FAIL("Invalid enum"); |
| break; |
| } |
| |
| /* */ |
| return source; |
| } |
| |
| /** Get name of test case |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return Name of tested stage |
| **/ |
| std::string XFBStrideTest::getTestCaseName(glw::GLuint test_case_index) |
| { |
| std::stringstream stream; |
| const testCase& test_case = m_test_cases[test_case_index]; |
| |
| stream << "Type: " << test_case.m_type.GetGLSLTypeName() |
| << ", stage: " << Utils::Shader::GetStageName(test_case.m_stage); |
| |
| return stream.str(); |
| } |
| |
| /** Returns number of test cases |
| * |
| * @return TEST_MAX |
| **/ |
| glw::GLuint XFBStrideTest::getTestCaseNumber() |
| { |
| return static_cast<GLuint>(m_test_cases.size()); |
| } |
| |
| /** Prepare all test cases |
| * |
| **/ |
| void XFBStrideTest::testInit() |
| { |
| const GLuint n_types = getTypesNumber(); |
| |
| for (GLuint i = 0; i < n_types; ++i) |
| { |
| const Utils::Type& type = getType(i); |
| |
| for (GLuint stage = 0; stage < Utils::Shader::STAGE_MAX; ++stage) |
| { |
| if ((Utils::Shader::COMPUTE == stage) || (Utils::Shader::FRAGMENT == stage) || |
| (Utils::Shader::TESS_CTRL == stage)) |
| { |
| continue; |
| } |
| |
| testCase test_case = { (Utils::Shader::STAGES)stage, type }; |
| |
| m_test_cases.push_back(test_case); |
| } |
| } |
| } |
| |
| /** Constructor |
| * |
| * @param context Test framework context |
| **/ |
| XFBBlockMemberBufferTest::XFBBlockMemberBufferTest(deqp::Context& context) |
| : NegativeTestBase( |
| context, "xfb_block_member_buffer", |
| "Test verifies that compiler reports error when block member has different xfb_buffer qualifier than buffer") |
| { |
| } |
| |
| /** Source for given test case and stage |
| * |
| * @param test_case_index Index of test case |
| * @param stage Shader stage |
| * |
| * @return Shader source |
| **/ |
| std::string XFBBlockMemberBufferTest::getShaderSource(GLuint test_case_index, Utils::Shader::STAGES stage) |
| { |
| static const GLchar* var_definition = "layout (xfb_offset = 0) out Goku {\n" |
| " vec4 gohan;\n" |
| #if DEBUG_NEG_REMOVE_ERROR |
| " /* layout (xfb_buffer = 1) */ vec4 goten;\n" |
| #else |
| " layout (xfb_buffer = 1) vec4 goten;\n" |
| #endif /* DEBUG_NEG_REMOVE_ERROR */ |
| "} goku;\n"; |
| static const GLchar* var_use = " goku.gohan = result / 2;\n" |
| " goku.goten = result / 4;\n"; |
| static const GLchar* fs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 any_fs;\n" |
| "out vec4 fs_out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " fs_out = any_fs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* gs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 vs_any[];\n" |
| "out vec4 any_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = vs_any[0];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " any_fs = result;\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " any_fs = result;\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| " any_fs = result;\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " any_fs = result;\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tcs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "in vec4 vs_any[];\n" |
| "out vec4 tcs_tes[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| "\n" |
| " tcs_tes[gl_InvocationID] = vs_any[gl_InvocationID];\n" |
| "\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tes_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(isolines, point_mode) in;\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 tcs_tes[];\n" |
| "out vec4 any_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = tcs_tes[0];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " any_fs += result;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 vs_any;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vs_any = in_vs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 any_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = in_vs;\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " any_fs = result;\n" |
| "}\n" |
| "\n"; |
| |
| std::string source; |
| testCase& test_case = m_test_cases[test_case_index]; |
| |
| if (test_case.m_stage == stage) |
| { |
| size_t position = 0; |
| |
| switch (stage) |
| { |
| case Utils::Shader::GEOMETRY: |
| source = gs_tested; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| source = tes_tested; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs_tested; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| Utils::replaceToken("VAR_DEFINITION", position, var_definition, source); |
| position = 0; |
| Utils::replaceToken("VARIABLE_USE", position, var_use, source); |
| } |
| else |
| { |
| switch (test_case.m_stage) |
| { |
| case Utils::Shader::GEOMETRY: |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs; |
| break; |
| default: |
| source = ""; |
| } |
| break; |
| case Utils::Shader::TESS_EVAL: |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| source = tcs; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs; |
| break; |
| default: |
| source = ""; |
| } |
| break; |
| case Utils::Shader::VERTEX: |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs; |
| break; |
| default: |
| source = ""; |
| } |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| break; |
| } |
| } |
| |
| return source; |
| } |
| |
| /** Get description of test case |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return Test case description |
| **/ |
| std::string XFBBlockMemberBufferTest::getTestCaseName(GLuint test_case_index) |
| { |
| std::stringstream stream; |
| testCase& test_case = m_test_cases[test_case_index]; |
| |
| stream << "Stage: " << Utils::Shader::GetStageName(test_case.m_stage); |
| |
| return stream.str(); |
| } |
| |
| /** Get number of test cases |
| * |
| * @return Number of test cases |
| **/ |
| GLuint XFBBlockMemberBufferTest::getTestCaseNumber() |
| { |
| return static_cast<GLuint>(m_test_cases.size()); |
| } |
| |
| /** Selects if "compute" stage is relevant for test |
| * |
| * @param ignored |
| * |
| * @return false |
| **/ |
| bool XFBBlockMemberBufferTest::isComputeRelevant(GLuint /* test_case_index */) |
| { |
| return false; |
| } |
| |
| /** Prepare all test cases |
| * |
| **/ |
| void XFBBlockMemberBufferTest::testInit() |
| { |
| for (GLuint stage = 0; stage < Utils::Shader::STAGE_MAX; ++stage) |
| { |
| if ((Utils::Shader::COMPUTE == stage) || (Utils::Shader::TESS_CTRL == stage) || |
| (Utils::Shader::FRAGMENT == stage)) |
| { |
| continue; |
| } |
| |
| testCase test_case = { (Utils::Shader::STAGES)stage }; |
| |
| m_test_cases.push_back(test_case); |
| } |
| } |
| |
| /** Constructor |
| * |
| * @param context Test framework context |
| **/ |
| XFBOutputOverlappingTest::XFBOutputOverlappingTest(deqp::Context& context) |
| : NegativeTestBase(context, "xfb_output_overlapping", |
| "Test verifies that compiler reports error when two xfb qualified outputs overlap") |
| { |
| } |
| |
| /** Source for given test case and stage |
| * |
| * @param test_case_index Index of test case |
| * @param stage Shader stage |
| * |
| * @return Shader source |
| **/ |
| std::string XFBOutputOverlappingTest::getShaderSource(GLuint test_case_index, Utils::Shader::STAGES stage) |
| { |
| static const GLchar* var_definition = "layout (xfb_offset = 0) out TYPE gohan;\n" |
| #if DEBUG_NEG_REMOVE_ERROR |
| "/* layout (xfb_offset = OFFSET) */ out TYPE goten;\n"; |
| #else |
| "layout (xfb_offset = OFFSET) out TYPE goten;\n"; |
| #endif /* DEBUG_NEG_REMOVE_ERROR */ |
| static const GLchar* var_use = " gohan = TYPE(0);\n" |
| " goten = TYPE(1);\n" |
| " if (vec4(0) == result)\n" |
| " {\n" |
| " gohan = TYPE(1);\n" |
| " goten = TYPE(0);\n" |
| " }\n"; |
| static const GLchar* fs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 any_fs;\n" |
| "out vec4 fs_out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " fs_out = any_fs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* gs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 vs_any[];\n" |
| "out vec4 any_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = vs_any[0];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " any_fs = result;\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " any_fs = result;\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| " any_fs = result;\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " any_fs = result;\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tcs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "in vec4 vs_any[];\n" |
| "out vec4 tcs_tes[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| "\n" |
| " tcs_tes[gl_InvocationID] = vs_any[gl_InvocationID];\n" |
| "\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tes_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(isolines, point_mode) in;\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 tcs_tes[];\n" |
| "out vec4 any_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = tcs_tes[0];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " any_fs += result;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 vs_any;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vs_any = in_vs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 any_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = in_vs;\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " any_fs = result;\n" |
| "}\n" |
| "\n"; |
| |
| std::string source; |
| testCase& test_case = m_test_cases[test_case_index]; |
| |
| if (test_case.m_stage == stage) |
| { |
| GLchar offset[16]; |
| size_t position = 0; |
| const GLchar* type_name = test_case.m_type.GetGLSLTypeName(); |
| |
| sprintf(offset, "%d", test_case.m_offset); |
| |
| switch (stage) |
| { |
| case Utils::Shader::GEOMETRY: |
| source = gs_tested; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| source = tes_tested; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs_tested; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| Utils::replaceToken("VAR_DEFINITION", position, var_definition, source); |
| position = 0; |
| Utils::replaceToken("OFFSET", position, offset, source); |
| Utils::replaceToken("VARIABLE_USE", position, var_use, source); |
| |
| Utils::replaceAllTokens("TYPE", type_name, source); |
| } |
| else |
| { |
| switch (test_case.m_stage) |
| { |
| case Utils::Shader::GEOMETRY: |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs; |
| break; |
| default: |
| source = ""; |
| } |
| break; |
| case Utils::Shader::TESS_EVAL: |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| source = tcs; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs; |
| break; |
| default: |
| source = ""; |
| } |
| break; |
| case Utils::Shader::VERTEX: |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs; |
| break; |
| default: |
| source = ""; |
| } |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| break; |
| } |
| } |
| |
| return source; |
| } |
| |
| /** Get description of test case |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return Test case description |
| **/ |
| std::string XFBOutputOverlappingTest::getTestCaseName(GLuint test_case_index) |
| { |
| std::stringstream stream; |
| testCase& test_case = m_test_cases[test_case_index]; |
| |
| stream << "Stage: " << Utils::Shader::GetStageName(test_case.m_stage) |
| << ", type: " << test_case.m_type.GetGLSLTypeName() << ", offset: " << test_case.m_offset; |
| |
| return stream.str(); |
| } |
| |
| /** Get number of test cases |
| * |
| * @return Number of test cases |
| **/ |
| GLuint XFBOutputOverlappingTest::getTestCaseNumber() |
| { |
| return static_cast<GLuint>(m_test_cases.size()); |
| } |
| |
| /** Selects if "compute" stage is relevant for test |
| * |
| * @param ignored |
| * |
| * @return false |
| **/ |
| bool XFBOutputOverlappingTest::isComputeRelevant(GLuint /* test_case_index */) |
| { |
| return false; |
| } |
| |
| /** Prepare all test cases |
| * |
| **/ |
| void XFBOutputOverlappingTest::testInit() |
| { |
| const GLuint n_types = getTypesNumber(); |
| |
| for (GLuint i = 0; i < n_types; ++i) |
| { |
| const Utils::Type& type = getType(i); |
| const GLuint basic_type_size = Utils::Type::GetTypeSize(type.m_basic_type); |
| |
| /* Skip scalars, not applicable as: |
| * |
| * The offset must be a multiple of the size of the first component of the first |
| * qualified variable or block member, or a compile-time error results. |
| */ |
| if ((1 == type.m_n_columns) && (1 == type.m_n_rows)) |
| { |
| continue; |
| } |
| |
| for (GLuint stage = 0; stage < Utils::Shader::STAGE_MAX; ++stage) |
| { |
| if ((Utils::Shader::COMPUTE == stage) || (Utils::Shader::TESS_CTRL == stage) || |
| (Utils::Shader::FRAGMENT == stage)) |
| { |
| continue; |
| } |
| |
| testCase test_case = { basic_type_size /* offset */, (Utils::Shader::STAGES)stage, type }; |
| |
| m_test_cases.push_back(test_case); |
| } |
| } |
| } |
| |
| /** Constructor |
| * |
| * @param context Test framework context |
| **/ |
| XFBInvalidOffsetAlignmentTest::XFBInvalidOffsetAlignmentTest(deqp::Context& context) |
| : NegativeTestBase(context, "xfb_invalid_offset_alignment", |
| "Test verifies that compiler reports error when xfb_offset has invalid alignment") |
| { |
| } |
| |
| /** Source for given test case and stage |
| * |
| * @param test_case_index Index of test case |
| * @param stage Shader stage |
| * |
| * @return Shader source |
| **/ |
| std::string XFBInvalidOffsetAlignmentTest::getShaderSource(GLuint test_case_index, Utils::Shader::STAGES stage) |
| { |
| #if DEBUG_NEG_REMOVE_ERROR |
| static const GLchar* var_definition = "/* layout (xfb_offset = OFFSET) */ out TYPE gohan;\n"; |
| #else |
| static const GLchar* var_definition = "layout (xfb_offset = OFFSET) out TYPE gohan;\n"; |
| #endif /* DEBUG_NEG_REMOVE_ERROR */ |
| static const GLchar* var_use = " gohan = TYPE(0);\n" |
| " if (vec4(0) == result)\n" |
| " {\n" |
| " gohan = TYPE(1);\n" |
| " }\n"; |
| static const GLchar* fs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 any_fs;\n" |
| "out vec4 fs_out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " fs_out = any_fs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* gs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 vs_any[];\n" |
| "out vec4 any_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = vs_any[0];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " any_fs = result;\n" |
| " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " any_fs = result;\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| " any_fs = result;\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " EmitVertex();\n" |
| " any_fs = result;\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " EmitVertex();\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tcs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(vertices = 1) out;\n" |
| "\n" |
| "in vec4 vs_any[];\n" |
| "out vec4 tcs_tes[];\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| "\n" |
| " tcs_tes[gl_InvocationID] = vs_any[gl_InvocationID];\n" |
| "\n" |
| " gl_TessLevelOuter[0] = 1.0;\n" |
| " gl_TessLevelOuter[1] = 1.0;\n" |
| " gl_TessLevelOuter[2] = 1.0;\n" |
| " gl_TessLevelOuter[3] = 1.0;\n" |
| " gl_TessLevelInner[0] = 1.0;\n" |
| " gl_TessLevelInner[1] = 1.0;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* tes_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "layout(isolines, point_mode) in;\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 tcs_tes[];\n" |
| "out vec4 any_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = tcs_tes[0];\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " any_fs += result;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 vs_any;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vs_any = in_vs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 any_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = in_vs;\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " any_fs = result;\n" |
| "}\n" |
| "\n"; |
| |
| std::string source; |
| testCase& test_case = m_test_cases[test_case_index]; |
| |
| if (test_case.m_stage == stage) |
| { |
| GLchar offset[16]; |
| size_t position = 0; |
| const GLchar* type_name = test_case.m_type.GetGLSLTypeName(); |
| |
| sprintf(offset, "%d", test_case.m_offset); |
| |
| switch (stage) |
| { |
| case Utils::Shader::GEOMETRY: |
| source = gs_tested; |
| break; |
| case Utils::Shader::TESS_EVAL: |
| source = tes_tested; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs_tested; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| Utils::replaceToken("VAR_DEFINITION", position, var_definition, source); |
| position = 0; |
| Utils::replaceToken("OFFSET", position, offset, source); |
| Utils::replaceToken("VARIABLE_USE", position, var_use, source); |
| |
| Utils::replaceAllTokens("TYPE", type_name, source); |
| } |
| else |
| { |
| switch (test_case.m_stage) |
| { |
| case Utils::Shader::GEOMETRY: |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs; |
| break; |
| default: |
| source = ""; |
| } |
| break; |
| case Utils::Shader::TESS_EVAL: |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs; |
| break; |
| case Utils::Shader::TESS_CTRL: |
| source = tcs; |
| break; |
| case Utils::Shader::VERTEX: |
| source = vs; |
| break; |
| default: |
| source = ""; |
| } |
| break; |
| case Utils::Shader::VERTEX: |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs; |
| break; |
| default: |
| source = ""; |
| } |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| break; |
| } |
| } |
| |
| return source; |
| } |
| |
| /** Get description of test case |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return Test case description |
| **/ |
| std::string XFBInvalidOffsetAlignmentTest::getTestCaseName(GLuint test_case_index) |
| { |
| std::stringstream stream; |
| testCase& test_case = m_test_cases[test_case_index]; |
| |
| stream << "Stage: " << Utils::Shader::GetStageName(test_case.m_stage) |
| << ", type: " << test_case.m_type.GetGLSLTypeName() << ", offset: " << test_case.m_offset; |
| |
| return stream.str(); |
| } |
| |
| /** Get number of test cases |
| * |
| * @return Number of test cases |
| **/ |
| GLuint XFBInvalidOffsetAlignmentTest::getTestCaseNumber() |
| { |
| return static_cast<GLuint>(m_test_cases.size()); |
| } |
| |
| /** Selects if "compute" stage is relevant for test |
| * |
| * @param ignored |
| * |
| * @return false |
| **/ |
| bool XFBInvalidOffsetAlignmentTest::isComputeRelevant(GLuint /* test_case_index */) |
| { |
| return false; |
| } |
| |
| /** Prepare all test cases |
| * |
| **/ |
| void XFBInvalidOffsetAlignmentTest::testInit() |
| { |
| const GLuint n_types = getTypesNumber(); |
| |
| for (GLuint i = 0; i < n_types; ++i) |
| { |
| const Utils::Type& type = getType(i); |
| const GLuint basic_type_size = Utils::Type::GetTypeSize(type.m_basic_type); |
| |
| for (GLuint stage = 0; stage < Utils::Shader::STAGE_MAX; ++stage) |
| { |
| if ((Utils::Shader::COMPUTE == stage) || (Utils::Shader::TESS_CTRL == stage) || |
| (Utils::Shader::FRAGMENT == stage)) |
| { |
| continue; |
| } |
| |
| for (GLuint offset = basic_type_size + 1; offset < 2 * basic_type_size; ++offset) |
| { |
| testCase test_case = { offset, (Utils::Shader::STAGES)stage, type }; |
| |
| m_test_cases.push_back(test_case); |
| } |
| } |
| } |
| } |
| |
| /** Constructor |
| * |
| * @param context Test context |
| **/ |
| XFBCaptureInactiveOutputVariableTest::XFBCaptureInactiveOutputVariableTest(deqp::Context& context) |
| : BufferTestBase(context, "xfb_capture_inactive_output_variable", |
| "Test verifies that inactive variables are captured") |
| { |
| /* Nothing to be done here */ |
| } |
| |
| /** Execute drawArrays for single vertex |
| * |
| * @param test_case_index |
| * |
| * @return true |
| **/ |
| bool XFBCaptureInactiveOutputVariableTest::executeDrawCall(bool /* tesEnabled */, GLuint test_case_index) |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| GLenum primitive_type = GL_PATCHES; |
| |
| if (TEST_VS == test_case_index) |
| { |
| primitive_type = GL_POINTS; |
| } |
| |
| gl.disable(GL_RASTERIZER_DISCARD); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Disable"); |
| |
| gl.beginTransformFeedback(GL_POINTS); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "BeginTransformFeedback"); |
| |
| gl.drawArrays(primitive_type, 0 /* first */, 1 /* count */); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays"); |
| |
| gl.endTransformFeedback(); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "EndTransformFeedback"); |
| |
| return true; |
| } |
| |
| /** Get descriptors of buffers necessary for test |
| * |
| * @param ignored |
| * @param out_descriptors Descriptors of buffers used by test |
| **/ |
| void XFBCaptureInactiveOutputVariableTest::getBufferDescriptors(glw::GLuint /* test_case_index */, |
| bufferDescriptor::Vector& out_descriptors) |
| { |
| const Utils::Type& type = Utils::Type::vec4; |
| |
| /* Test needs single uniform and xfb */ |
| out_descriptors.resize(2); |
| |
| /* Get references */ |
| bufferDescriptor& uniform = out_descriptors[0]; |
| bufferDescriptor& xfb = out_descriptors[1]; |
| |
| /* Index */ |
| uniform.m_index = 0; |
| xfb.m_index = 0; |
| |
| /* Target */ |
| uniform.m_target = Utils::Buffer::Uniform; |
| xfb.m_target = Utils::Buffer::Transform_feedback; |
| |
| /* Data */ |
| const std::vector<GLubyte>& gohan_data = type.GenerateData(); |
| const std::vector<GLubyte>& goten_data = type.GenerateData(); |
| |
| const GLuint type_size = static_cast<GLuint>(gohan_data.size()); |
| |
| /* Uniform data */ |
| uniform.m_initial_data.resize(2 * type_size); |
| memcpy(&uniform.m_initial_data[0] + 0, &gohan_data[0], type_size); |
| memcpy(&uniform.m_initial_data[0] + type_size, &goten_data[0], type_size); |
| |
| /* XFB data */ |
| xfb.m_initial_data.resize(3 * type_size); |
| xfb.m_expected_data.resize(3 * type_size); |
| |
| for (GLuint i = 0; i < 3 * type_size; ++i) |
| { |
| xfb.m_initial_data[i] = (glw::GLubyte)i; |
| xfb.m_expected_data[i] = (glw::GLubyte)i; |
| } |
| |
| memcpy(&xfb.m_expected_data[0] + 2 * type_size, &gohan_data[0], type_size); |
| memcpy(&xfb.m_expected_data[0] + 0 * type_size, &goten_data[0], type_size); |
| } |
| |
| /** Get body of main function for given shader stage |
| * |
| * @param test_case_index Index of test case |
| * @param stage Shader stage |
| * @param out_assignments Set to empty |
| * @param out_calculations Set to empty |
| **/ |
| void XFBCaptureInactiveOutputVariableTest::getShaderBody(GLuint test_case_index, Utils::Shader::STAGES stage, |
| std::string& out_assignments, std::string& out_calculations) |
| { |
| out_calculations = ""; |
| |
| static const GLchar* vs_tes_gs = " goten = uni_goten;\n" |
| " gohan = uni_gohan;\n"; |
| static const GLchar* fs = " fs_out = goku + gohan + goten;\n"; |
| |
| const GLchar* assignments = ""; |
| |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| assignments = fs; |
| break; |
| |
| case Utils::Shader::GEOMETRY: |
| if (TEST_GS == test_case_index) |
| { |
| assignments = vs_tes_gs; |
| } |
| break; |
| |
| case Utils::Shader::TESS_CTRL: |
| break; |
| |
| case Utils::Shader::TESS_EVAL: |
| if (TEST_TES == test_case_index) |
| { |
| assignments = vs_tes_gs; |
| } |
| break; |
| |
| case Utils::Shader::VERTEX: |
| if (TEST_VS == test_case_index) |
| { |
| assignments = vs_tes_gs; |
| } |
| break; |
| |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| out_assignments = assignments; |
| } |
| |
| /** Get interface of shader |
| * |
| * @param test_case_index Index of test case |
| * @param stage Shader stage |
| * @param out_interface Set to "" |
| **/ |
| void XFBCaptureInactiveOutputVariableTest::getShaderInterface(GLuint test_case_index, Utils::Shader::STAGES stage, |
| std::string& out_interface) |
| { |
| static const GLchar* vs_tes_gs = "const uint sizeof_type = 16;\n" |
| "\n" |
| "layout (xfb_offset = 1 * sizeof_type) out vec4 goku;\n" |
| "layout (xfb_offset = 2 * sizeof_type) out vec4 gohan;\n" |
| "layout (xfb_offset = 0 * sizeof_type) out vec4 goten;\n" |
| "\n" |
| "layout(binding = 0) uniform block {\n" |
| " vec4 uni_gohan;\n" |
| " vec4 uni_goten;\n" |
| "};\n"; |
| static const GLchar* fs = "in vec4 goku;\n" |
| "in vec4 gohan;\n" |
| "in vec4 goten;\n" |
| "out vec4 fs_out;\n"; |
| |
| const GLchar* interface = ""; |
| |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| interface = fs; |
| break; |
| |
| case Utils::Shader::GEOMETRY: |
| if (TEST_GS == test_case_index) |
| { |
| interface = vs_tes_gs; |
| } |
| break; |
| |
| case Utils::Shader::TESS_CTRL: |
| break; |
| |
| case Utils::Shader::TESS_EVAL: |
| if (TEST_TES == test_case_index) |
| { |
| interface = vs_tes_gs; |
| } |
| break; |
| |
| case Utils::Shader::VERTEX: |
| if (TEST_VS == test_case_index) |
| { |
| interface = vs_tes_gs; |
| } |
| break; |
| |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| out_interface = interface; |
| } |
| |
| /** Get source code of shader |
| * |
| * @param test_case_index Index of test case |
| * @param stage Shader stage |
| * |
| * @return Source |
| **/ |
| std::string XFBCaptureInactiveOutputVariableTest::getShaderSource(GLuint test_case_index, Utils::Shader::STAGES stage) |
| { |
| std::string source; |
| |
| switch (test_case_index) |
| { |
| case TEST_VS: |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| case Utils::Shader::VERTEX: |
| source = BufferTestBase::getShaderSource(test_case_index, stage); |
| break; |
| default: |
| break; |
| } |
| break; |
| |
| case TEST_TES: |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| case Utils::Shader::TESS_CTRL: |
| case Utils::Shader::TESS_EVAL: |
| case Utils::Shader::VERTEX: |
| source = BufferTestBase::getShaderSource(test_case_index, stage); |
| break; |
| default: |
| break; |
| } |
| break; |
| |
| case TEST_GS: |
| source = BufferTestBase::getShaderSource(test_case_index, stage); |
| break; |
| |
| default: |
| TCU_FAIL("Invalid enum"); |
| break; |
| } |
| |
| /* */ |
| return source; |
| } |
| |
| /** Get name of test case |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return Name of tested stage |
| **/ |
| std::string XFBCaptureInactiveOutputVariableTest::getTestCaseName(glw::GLuint test_case_index) |
| { |
| const GLchar* name = 0; |
| |
| switch (test_case_index) |
| { |
| case TEST_VS: |
| name = "vertex"; |
| break; |
| case TEST_TES: |
| name = "tessellation evaluation"; |
| break; |
| case TEST_GS: |
| name = "geometry"; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| return name; |
| } |
| |
| /** Returns number of test cases |
| * |
| * @return TEST_MAX |
| **/ |
| glw::GLuint XFBCaptureInactiveOutputVariableTest::getTestCaseNumber() |
| { |
| return TEST_MAX; |
| } |
| |
| /** Inspects program to check if all resources are as expected |
| * |
| * @param ignored |
| * @param program Program instance |
| * @param out_stream Error message |
| * |
| * @return true if everything is ok, false otherwise |
| **/ |
| bool XFBCaptureInactiveOutputVariableTest::inspectProgram(GLuint /* test_case_index */, Utils::Program& program, |
| std::stringstream& out_stream) |
| { |
| GLint stride = 0; |
| const Utils::Type& type = Utils::Type::vec4; |
| const GLuint type_size = type.GetSize(); |
| |
| program.GetResource(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, GL_TRANSFORM_FEEDBACK_BUFFER_STRIDE, |
| 1 /* buf_size */, &stride); |
| |
| if ((GLint)(3 * type_size) != stride) |
| { |
| out_stream << "Stride is: " << stride << " expected: " << (3 * type_size); |
| |
| return false; |
| } |
| |
| return true; |
| } |
| |
| /** Verify contents of buffers |
| * |
| * @param buffers Collection of buffers to be verified |
| * |
| * @return true if everything is as expected, false otherwise |
| **/ |
| bool XFBCaptureInactiveOutputVariableTest::verifyBuffers(bufferCollection& buffers) |
| { |
| bool result = true; |
| |
| bufferCollection::pair& pair = buffers.m_vector[1] /* xfb */; |
| Utils::Buffer* buffer = pair.m_buffer; |
| bufferDescriptor* descriptor = pair.m_descriptor; |
| |
| /* Get pointer to contents of buffer */ |
| buffer->Bind(); |
| GLubyte* buffer_data = (GLubyte*)buffer->Map(Utils::Buffer::ReadOnly); |
| |
| /* Get pointer to expected data */ |
| GLubyte* expected_data = (GLubyte*)&descriptor->m_expected_data[0]; |
| |
| /* Compare */ |
| static const GLuint vec4_size = 16; |
| |
| int res_gohan = memcmp(buffer_data + 2 * vec4_size, expected_data + 2 * vec4_size, vec4_size); |
| int res_goten = memcmp(buffer_data + 0 * vec4_size, expected_data + 0 * vec4_size, vec4_size); |
| |
| if ((0 != res_gohan) || (0 != res_goten)) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Invalid result. Buffer: " << Utils::Buffer::GetBufferName(descriptor->m_target) |
| << ". Index: " << descriptor->m_index << tcu::TestLog::EndMessage; |
| |
| result = false; |
| } |
| |
| /* Release buffer mapping */ |
| buffer->UnMap(); |
| |
| return result; |
| } |
| |
| /** Constructor |
| * |
| * @param context Test context |
| **/ |
| XFBCaptureInactiveOutputComponentTest::XFBCaptureInactiveOutputComponentTest(deqp::Context& context) |
| : BufferTestBase(context, "xfb_capture_inactive_output_component", |
| "Test verifies that inactive components are not modified") |
| { |
| /* Nothing to be done here */ |
| } |
| |
| /** Execute drawArrays for single vertex |
| * |
| * @param test_case_index |
| * |
| * @return true |
| **/ |
| bool XFBCaptureInactiveOutputComponentTest::executeDrawCall(bool /* tesEnabled */, GLuint test_case_index) |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| GLenum primitive_type = GL_PATCHES; |
| |
| if (TEST_VS == test_case_index) |
| { |
| primitive_type = GL_POINTS; |
| } |
| |
| gl.disable(GL_RASTERIZER_DISCARD); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Disable"); |
| |
| gl.beginTransformFeedback(GL_POINTS); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "BeginTransformFeedback"); |
| |
| gl.drawArrays(primitive_type, 0 /* first */, 1 /* count */); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays"); |
| |
| gl.endTransformFeedback(); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "EndTransformFeedback"); |
| |
| return true; |
| } |
| |
| /** Get descriptors of buffers necessary for test |
| * |
| * @param ignored |
| * @param out_descriptors Descriptors of buffers used by test |
| **/ |
| void XFBCaptureInactiveOutputComponentTest::getBufferDescriptors(glw::GLuint /* test_case_index */, |
| bufferDescriptor::Vector& out_descriptors) |
| { |
| const Utils::Type& type = Utils::Type::vec4; |
| |
| /* Test needs single uniform and xfb */ |
| out_descriptors.resize(2); |
| |
| /* Get references */ |
| bufferDescriptor& uniform = out_descriptors[0]; |
| bufferDescriptor& xfb = out_descriptors[1]; |
| |
| /* Index */ |
| uniform.m_index = 0; |
| xfb.m_index = 0; |
| |
| /* Target */ |
| uniform.m_target = Utils::Buffer::Uniform; |
| xfb.m_target = Utils::Buffer::Transform_feedback; |
| |
| /* Data */ |
| const std::vector<GLubyte>& goku_data = type.GenerateData(); |
| const std::vector<GLubyte>& gohan_data = type.GenerateData(); |
| const std::vector<GLubyte>& goten_data = type.GenerateData(); |
| const std::vector<GLubyte>& chichi_data = type.GenerateData(); |
| const std::vector<GLubyte>& vegeta_data = type.GenerateData(); |
| const std::vector<GLubyte>& trunks_data = type.GenerateData(); |
| const std::vector<GLubyte>& bra_data = type.GenerateData(); |
| const std::vector<GLubyte>& bulma_data = type.GenerateData(); |
| |
| const GLuint comp_size = Utils::Type::GetTypeSize(type.m_basic_type); |
| const GLuint type_size = static_cast<GLuint>(gohan_data.size()); |
| |
| /* Uniform data */ |
| uniform.m_initial_data.resize(8 * type_size); |
| memcpy(&uniform.m_initial_data[0] + 0 * type_size, &goku_data[0], type_size); |
| memcpy(&uniform.m_initial_data[0] + 1 * type_size, &gohan_data[0], type_size); |
| memcpy(&uniform.m_initial_data[0] + 2 * type_size, &goten_data[0], type_size); |
| memcpy(&uniform.m_initial_data[0] + 3 * type_size, &chichi_data[0], type_size); |
| memcpy(&uniform.m_initial_data[0] + 4 * type_size, &vegeta_data[0], type_size); |
| memcpy(&uniform.m_initial_data[0] + 5 * type_size, &trunks_data[0], type_size); |
| memcpy(&uniform.m_initial_data[0] + 6 * type_size, &bra_data[0], type_size); |
| memcpy(&uniform.m_initial_data[0] + 7 * type_size, &bulma_data[0], type_size); |
| |
| /* XFB data */ |
| xfb.m_initial_data.resize(8 * type_size); |
| xfb.m_expected_data.resize(8 * type_size); |
| |
| for (GLuint i = 0; i < 8 * type_size; ++i) |
| { |
| xfb.m_initial_data[i] = (glw::GLubyte)i; |
| xfb.m_expected_data[i] = (glw::GLubyte)i; |
| } |
| |
| /* goku - x, z - 32 */ |
| memcpy(&xfb.m_expected_data[0] + 2 * type_size + 0 * comp_size, &goku_data[0] + 0 * comp_size, comp_size); |
| memcpy(&xfb.m_expected_data[0] + 2 * type_size + 2 * comp_size, &goku_data[0] + 2 * comp_size, comp_size); |
| |
| /* gohan - y, w - 0 */ |
| memcpy(&xfb.m_expected_data[0] + 0 * type_size + 1 * comp_size, &gohan_data[0] + 1 * comp_size, comp_size); |
| memcpy(&xfb.m_expected_data[0] + 0 * type_size + 3 * comp_size, &gohan_data[0] + 3 * comp_size, comp_size); |
| |
| /* goten - x, y - 16 */ |
| memcpy(&xfb.m_expected_data[0] + 1 * type_size + 0 * comp_size, &goten_data[0] + 0 * comp_size, comp_size); |
| memcpy(&xfb.m_expected_data[0] + 1 * type_size + 1 * comp_size, &goten_data[0] + 1 * comp_size, comp_size); |
| |
| /* chichi - z, w - 48 */ |
| memcpy(&xfb.m_expected_data[0] + 3 * type_size + 2 * comp_size, &chichi_data[0] + 2 * comp_size, comp_size); |
| memcpy(&xfb.m_expected_data[0] + 3 * type_size + 3 * comp_size, &chichi_data[0] + 3 * comp_size, comp_size); |
| |
| /* vegeta - x - 112 */ |
| memcpy(&xfb.m_expected_data[0] + 7 * type_size + 0 * comp_size, &vegeta_data[0] + 0 * comp_size, comp_size); |
| |
| /* trunks - y - 96 */ |
| memcpy(&xfb.m_expected_data[0] + 6 * type_size + 1 * comp_size, &trunks_data[0] + 1 * comp_size, comp_size); |
| |
| /* bra - z - 80 */ |
| memcpy(&xfb.m_expected_data[0] + 5 * type_size + 2 * comp_size, &bra_data[0] + 2 * comp_size, comp_size); |
| |
| /* bulma - w - 64 */ |
| memcpy(&xfb.m_expected_data[0] + 4 * type_size + 3 * comp_size, &bulma_data[0] + 3 * comp_size, comp_size); |
| } |
| |
| /** Get body of main function for given shader stage |
| * |
| * @param test_case_index Index of test case |
| * @param stage Shader stage |
| * @param out_assignments Set to empty |
| * @param out_calculations Set to empty |
| **/ |
| void XFBCaptureInactiveOutputComponentTest::getShaderBody(GLuint test_case_index, Utils::Shader::STAGES stage, |
| std::string& out_assignments, std::string& out_calculations) |
| { |
| out_calculations = ""; |
| |
| static const GLchar* vs_tes_gs = " goku.x = uni_goku.x ;\n" |
| " goku.z = uni_goku.z ;\n" |
| " gohan.y = uni_gohan.y ;\n" |
| " gohan.w = uni_gohan.w ;\n" |
| " goten.x = uni_goten.x ;\n" |
| " goten.y = uni_goten.y ;\n" |
| " chichi.z = uni_chichi.z ;\n" |
| " chichi.w = uni_chichi.w ;\n" |
| " vegeta.x = uni_vegeta.x ;\n" |
| " trunks.y = uni_trunks.y ;\n" |
| " bra.z = uni_bra.z ;\n" |
| " bulma.w = uni_bulma.w ;\n"; |
| static const GLchar* fs = " fs_out = goku + gohan + goten + chichi + vegeta + trunks + bra + bulma;\n"; |
| |
| const GLchar* assignments = ""; |
| |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| assignments = fs; |
| break; |
| |
| case Utils::Shader::GEOMETRY: |
| if (TEST_GS == test_case_index) |
| { |
| assignments = vs_tes_gs; |
| } |
| break; |
| |
| case Utils::Shader::TESS_CTRL: |
| break; |
| |
| case Utils::Shader::TESS_EVAL: |
| if (TEST_TES == test_case_index) |
| { |
| assignments = vs_tes_gs; |
| } |
| break; |
| |
| case Utils::Shader::VERTEX: |
| if (TEST_VS == test_case_index) |
| { |
| assignments = vs_tes_gs; |
| } |
| break; |
| |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| out_assignments = assignments; |
| } |
| |
| /** Get interface of shader |
| * |
| * @param test_case_index Index of test case |
| * @param stage Shader stage |
| * @param out_interface Set to "" |
| **/ |
| void XFBCaptureInactiveOutputComponentTest::getShaderInterface(GLuint test_case_index, Utils::Shader::STAGES stage, |
| std::string& out_interface) |
| { |
| static const GLchar* vs_tes_gs = "const uint sizeof_type = 16;\n" |
| "\n" |
| "layout (xfb_offset = 2 * sizeof_type) out vec4 goku;\n" |
| "layout (xfb_offset = 0 * sizeof_type) out vec4 gohan;\n" |
| "layout (xfb_offset = 1 * sizeof_type) out vec4 goten;\n" |
| "layout (xfb_offset = 3 * sizeof_type) out vec4 chichi;\n" |
| "layout (xfb_offset = 7 * sizeof_type) out vec4 vegeta;\n" |
| "layout (xfb_offset = 6 * sizeof_type) out vec4 trunks;\n" |
| "layout (xfb_offset = 5 * sizeof_type) out vec4 bra;\n" |
| "layout (xfb_offset = 4 * sizeof_type) out vec4 bulma;\n" |
| "\n" |
| "layout(binding = 0) uniform block {\n" |
| " vec4 uni_goku;\n" |
| " vec4 uni_gohan;\n" |
| " vec4 uni_goten;\n" |
| " vec4 uni_chichi;\n" |
| " vec4 uni_vegeta;\n" |
| " vec4 uni_trunks;\n" |
| " vec4 uni_bra;\n" |
| " vec4 uni_bulma;\n" |
| "};\n"; |
| static const GLchar* fs = "in vec4 vegeta;\n" |
| "in vec4 trunks;\n" |
| "in vec4 bra;\n" |
| "in vec4 bulma;\n" |
| "in vec4 goku;\n" |
| "in vec4 gohan;\n" |
| "in vec4 goten;\n" |
| "in vec4 chichi;\n" |
| "\n" |
| "out vec4 fs_out;\n"; |
| |
| const GLchar* interface = ""; |
| |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| interface = fs; |
| break; |
| |
| case Utils::Shader::GEOMETRY: |
| if (TEST_GS == test_case_index) |
| { |
| interface = vs_tes_gs; |
| } |
| break; |
| |
| case Utils::Shader::TESS_CTRL: |
| break; |
| |
| case Utils::Shader::TESS_EVAL: |
| if (TEST_TES == test_case_index) |
| { |
| interface = vs_tes_gs; |
| } |
| break; |
| |
| case Utils::Shader::VERTEX: |
| if (TEST_VS == test_case_index) |
| { |
| interface = vs_tes_gs; |
| } |
| break; |
| |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| out_interface = interface; |
| } |
| |
| /** Get source code of shader |
| * |
| * @param test_case_index Index of test case |
| * @param stage Shader stage |
| * |
| * @return Source |
| **/ |
| std::string XFBCaptureInactiveOutputComponentTest::getShaderSource(GLuint test_case_index, Utils::Shader::STAGES stage) |
| { |
| std::string source; |
| |
| switch (test_case_index) |
| { |
| case TEST_VS: |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| case Utils::Shader::VERTEX: |
| source = BufferTestBase::getShaderSource(test_case_index, stage); |
| break; |
| default: |
| break; |
| } |
| break; |
| |
| case TEST_TES: |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| case Utils::Shader::TESS_CTRL: |
| case Utils::Shader::TESS_EVAL: |
| case Utils::Shader::VERTEX: |
| source = BufferTestBase::getShaderSource(test_case_index, stage); |
| break; |
| default: |
| break; |
| } |
| break; |
| |
| case TEST_GS: |
| source = BufferTestBase::getShaderSource(test_case_index, stage); |
| break; |
| |
| default: |
| TCU_FAIL("Invalid enum"); |
| break; |
| } |
| |
| /* */ |
| return source; |
| } |
| |
| /** Get name of test case |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return Name of tested stage |
| **/ |
| std::string XFBCaptureInactiveOutputComponentTest::getTestCaseName(glw::GLuint test_case_index) |
| { |
| const GLchar* name = 0; |
| |
| switch (test_case_index) |
| { |
| case TEST_VS: |
| name = "vertex"; |
| break; |
| case TEST_TES: |
| name = "tessellation evaluation"; |
| break; |
| case TEST_GS: |
| name = "geometry"; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| return name; |
| } |
| |
| /** Returns number of test cases |
| * |
| * @return TEST_MAX |
| **/ |
| glw::GLuint XFBCaptureInactiveOutputComponentTest::getTestCaseNumber() |
| { |
| return TEST_MAX; |
| } |
| |
| /** Verify contents of buffers |
| * |
| * @param buffers Collection of buffers to be verified |
| * |
| * @return true if everything is as expected, false otherwise |
| **/ |
| bool XFBCaptureInactiveOutputComponentTest::verifyBuffers(bufferCollection& buffers) |
| { |
| bool result = true; |
| |
| bufferCollection::pair& pair = buffers.m_vector[1] /* xfb */; |
| Utils::Buffer* buffer = pair.m_buffer; |
| bufferDescriptor* descriptor = pair.m_descriptor; |
| |
| /* Get pointer to contents of buffer */ |
| buffer->Bind(); |
| GLubyte* buffer_data = (GLubyte*)buffer->Map(Utils::Buffer::ReadOnly); |
| |
| /* Get pointer to expected data */ |
| GLubyte* expected_data = (GLubyte*)&descriptor->m_expected_data[0]; |
| |
| /* Compare */ |
| static const GLuint comp_size = 4; |
| static const GLuint vec4_size = 16; |
| |
| int res_goku_x = |
| memcmp(buffer_data + 2 * vec4_size + 0 * comp_size, expected_data + 2 * vec4_size + 0 * comp_size, comp_size); |
| int res_goku_z = |
| memcmp(buffer_data + 2 * vec4_size + 2 * comp_size, expected_data + 2 * vec4_size + 2 * comp_size, comp_size); |
| |
| int res_gohan_y = |
| memcmp(buffer_data + 0 * vec4_size + 1 * comp_size, expected_data + 0 * vec4_size + 1 * comp_size, comp_size); |
| int res_gohan_w = |
| memcmp(buffer_data + 0 * vec4_size + 3 * comp_size, expected_data + 0 * vec4_size + 3 * comp_size, comp_size); |
| |
| int res_goten_x = |
| memcmp(buffer_data + 1 * vec4_size + 0 * comp_size, expected_data + 1 * vec4_size + 0 * comp_size, comp_size); |
| int res_goten_y = |
| memcmp(buffer_data + 1 * vec4_size + 1 * comp_size, expected_data + 1 * vec4_size + 1 * comp_size, comp_size); |
| |
| int res_chichi_z = |
| memcmp(buffer_data + 3 * vec4_size + 2 * comp_size, expected_data + 3 * vec4_size + 2 * comp_size, comp_size); |
| int res_chichi_w = |
| memcmp(buffer_data + 3 * vec4_size + 3 * comp_size, expected_data + 3 * vec4_size + 3 * comp_size, comp_size); |
| |
| int res_vegeta_x = |
| memcmp(buffer_data + 7 * vec4_size + 0 * comp_size, expected_data + 7 * vec4_size + 0 * comp_size, comp_size); |
| |
| int res_trunks_y = |
| memcmp(buffer_data + 6 * vec4_size + 1 * comp_size, expected_data + 6 * vec4_size + 1 * comp_size, comp_size); |
| |
| int res_bra_z = |
| memcmp(buffer_data + 5 * vec4_size + 2 * comp_size, expected_data + 5 * vec4_size + 2 * comp_size, comp_size); |
| |
| int res_bulma_w = |
| memcmp(buffer_data + 4 * vec4_size + 3 * comp_size, expected_data + 4 * vec4_size + 3 * comp_size, comp_size); |
| |
| if ((0 != res_goku_x) || (0 != res_goku_z) || (0 != res_gohan_y) || (0 != res_gohan_w) || (0 != res_goten_x) || |
| (0 != res_goten_y) || (0 != res_chichi_z) || (0 != res_chichi_w) || (0 != res_vegeta_x) || |
| (0 != res_trunks_y) || (0 != res_bra_z) || (0 != res_bulma_w)) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Invalid result. Buffer: " << Utils::Buffer::GetBufferName(descriptor->m_target) |
| << ". Index: " << descriptor->m_index << tcu::TestLog::EndMessage; |
| |
| result = false; |
| } |
| |
| /* Release buffer mapping */ |
| buffer->UnMap(); |
| |
| return result; |
| } |
| |
| /** Constructor |
| * |
| * @param context Test context |
| **/ |
| XFBCaptureInactiveOutputBlockMemberTest::XFBCaptureInactiveOutputBlockMemberTest(deqp::Context& context) |
| : BufferTestBase(context, "xfb_capture_inactive_output_block_member", |
| "Test verifies that inactive block members are captured") |
| { |
| /* Nothing to be done here */ |
| } |
| |
| /** Execute drawArrays for single vertex |
| * |
| * @param test_case_index |
| * |
| * @return true |
| **/ |
| bool XFBCaptureInactiveOutputBlockMemberTest::executeDrawCall(bool /* tesEnabled */, GLuint test_case_index) |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| GLenum primitive_type = GL_PATCHES; |
| |
| if (TEST_VS == test_case_index) |
| { |
| primitive_type = GL_POINTS; |
| } |
| |
| gl.disable(GL_RASTERIZER_DISCARD); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Disable"); |
| |
| gl.beginTransformFeedback(GL_POINTS); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "BeginTransformFeedback"); |
| |
| gl.drawArrays(primitive_type, 0 /* first */, 1 /* count */); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays"); |
| |
| gl.endTransformFeedback(); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "EndTransformFeedback"); |
| |
| return true; |
| } |
| |
| /** Get descriptors of buffers necessary for test |
| * |
| * @param ignored |
| * @param out_descriptors Descriptors of buffers used by test |
| **/ |
| void XFBCaptureInactiveOutputBlockMemberTest::getBufferDescriptors(glw::GLuint /* test_case_index */, |
| bufferDescriptor::Vector& out_descriptors) |
| { |
| const Utils::Type& type = Utils::Type::vec4; |
| |
| /* Test needs single uniform and xfb */ |
| out_descriptors.resize(2); |
| |
| /* Get references */ |
| bufferDescriptor& uniform = out_descriptors[0]; |
| bufferDescriptor& xfb = out_descriptors[1]; |
| |
| /* Index */ |
| uniform.m_index = 0; |
| xfb.m_index = 0; |
| |
| /* Target */ |
| uniform.m_target = Utils::Buffer::Uniform; |
| xfb.m_target = Utils::Buffer::Transform_feedback; |
| |
| /* Data */ |
| const std::vector<GLubyte>& gohan_data = type.GenerateData(); |
| const std::vector<GLubyte>& chichi_data = type.GenerateData(); |
| |
| const GLuint type_size = static_cast<GLuint>(gohan_data.size()); |
| |
| /* Uniform data */ |
| uniform.m_initial_data.resize(2 * type_size); |
| memcpy(&uniform.m_initial_data[0] + 0, &gohan_data[0], type_size); |
| memcpy(&uniform.m_initial_data[0] + type_size, &chichi_data[0], type_size); |
| |
| /* XFB data */ |
| xfb.m_initial_data.resize(4 * type_size); |
| xfb.m_expected_data.resize(4 * type_size); |
| |
| for (GLuint i = 0; i < 4 * type_size; ++i) |
| { |
| xfb.m_initial_data[i] = (glw::GLubyte)i; |
| xfb.m_expected_data[i] = (glw::GLubyte)i; |
| } |
| |
| memcpy(&xfb.m_expected_data[0] + 1 * type_size, &gohan_data[0], type_size); |
| memcpy(&xfb.m_expected_data[0] + 3 * type_size, &chichi_data[0], type_size); |
| } |
| |
| /** Get body of main function for given shader stage |
| * |
| * @param test_case_index Index of test case |
| * @param stage Shader stage |
| * @param out_assignments Set to empty |
| * @param out_calculations Set to empty |
| **/ |
| void XFBCaptureInactiveOutputBlockMemberTest::getShaderBody(GLuint test_case_index, Utils::Shader::STAGES stage, |
| std::string& out_assignments, std::string& out_calculations) |
| { |
| out_calculations = ""; |
| |
| static const GLchar* vs_tes_gs = " chichi = uni_chichi;\n" |
| " gohan = uni_gohan;\n"; |
| static const GLchar* fs = " fs_out = goten + gohan + chichi;\n"; |
| |
| const GLchar* assignments = ""; |
| |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| assignments = fs; |
| break; |
| |
| case Utils::Shader::GEOMETRY: |
| if (TEST_GS == test_case_index) |
| { |
| assignments = vs_tes_gs; |
| } |
| break; |
| |
| case Utils::Shader::TESS_CTRL: |
| break; |
| |
| case Utils::Shader::TESS_EVAL: |
| if (TEST_TES == test_case_index) |
| { |
| assignments = vs_tes_gs; |
| } |
| break; |
| |
| case Utils::Shader::VERTEX: |
| if (TEST_VS == test_case_index) |
| { |
| assignments = vs_tes_gs; |
| } |
| break; |
| |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| out_assignments = assignments; |
| } |
| |
| /** Get interface of shader |
| * |
| * @param test_case_index Index of test case |
| * @param stage Shader stage |
| * @param out_interface Set to "" |
| **/ |
| void XFBCaptureInactiveOutputBlockMemberTest::getShaderInterface(GLuint test_case_index, Utils::Shader::STAGES stage, |
| std::string& out_interface) |
| { |
| static const GLchar* vs_tes_gs = "const uint sizeof_type = 16;\n" |
| "\n" |
| "layout (xfb_offset = 1 * sizeof_type) out Goku {\n" |
| " vec4 gohan;\n" |
| " vec4 goten;\n" |
| " vec4 chichi;\n" |
| "};\n" |
| "\n" |
| "layout(binding = 0) uniform block {\n" |
| " vec4 uni_gohan;\n" |
| " vec4 uni_chichi;\n" |
| "};\n"; |
| static const GLchar* fs = "in Goku {\n" |
| " vec4 gohan;\n" |
| " vec4 goten;\n" |
| " vec4 chichi;\n" |
| "};\n" |
| "out vec4 fs_out;\n"; |
| |
| const GLchar* interface = ""; |
| |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| interface = fs; |
| break; |
| |
| case Utils::Shader::GEOMETRY: |
| if (TEST_GS == test_case_index) |
| { |
| interface = vs_tes_gs; |
| } |
| break; |
| |
| case Utils::Shader::TESS_CTRL: |
| break; |
| |
| case Utils::Shader::TESS_EVAL: |
| if (TEST_TES == test_case_index) |
| { |
| interface = vs_tes_gs; |
| } |
| break; |
| |
| case Utils::Shader::VERTEX: |
| if (TEST_VS == test_case_index) |
| { |
| interface = vs_tes_gs; |
| } |
| break; |
| |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| out_interface = interface; |
| } |
| |
| /** Get source code of shader |
| * |
| * @param test_case_index Index of test case |
| * @param stage Shader stage |
| * |
| * @return Source |
| **/ |
| std::string XFBCaptureInactiveOutputBlockMemberTest::getShaderSource(GLuint test_case_index, |
| Utils::Shader::STAGES stage) |
| { |
| std::string source; |
| |
| switch (test_case_index) |
| { |
| case TEST_VS: |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| case Utils::Shader::VERTEX: |
| source = BufferTestBase::getShaderSource(test_case_index, stage); |
| break; |
| default: |
| break; |
| } |
| break; |
| |
| case TEST_TES: |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| case Utils::Shader::TESS_CTRL: |
| case Utils::Shader::TESS_EVAL: |
| case Utils::Shader::VERTEX: |
| source = BufferTestBase::getShaderSource(test_case_index, stage); |
| break; |
| default: |
| break; |
| } |
| break; |
| |
| case TEST_GS: |
| source = BufferTestBase::getShaderSource(test_case_index, stage); |
| break; |
| |
| default: |
| TCU_FAIL("Invalid enum"); |
| break; |
| } |
| |
| /* */ |
| return source; |
| } |
| |
| /** Get name of test case |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return Name of tested stage |
| **/ |
| std::string XFBCaptureInactiveOutputBlockMemberTest::getTestCaseName(glw::GLuint test_case_index) |
| { |
| const GLchar* name = 0; |
| |
| switch (test_case_index) |
| { |
| case TEST_VS: |
| name = "vertex"; |
| break; |
| case TEST_TES: |
| name = "tessellation evaluation"; |
| break; |
| case TEST_GS: |
| name = "geometry"; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| return name; |
| } |
| |
| /** Returns number of test cases |
| * |
| * @return TEST_MAX |
| **/ |
| glw::GLuint XFBCaptureInactiveOutputBlockMemberTest::getTestCaseNumber() |
| { |
| return TEST_MAX; |
| } |
| |
| /** Verify contents of buffers |
| * |
| * @param buffers Collection of buffers to be verified |
| * |
| * @return true if everything is as expected, false otherwise |
| **/ |
| bool XFBCaptureInactiveOutputBlockMemberTest::verifyBuffers(bufferCollection& buffers) |
| { |
| bool result = true; |
| |
| bufferCollection::pair& pair = buffers.m_vector[1] /* xfb */; |
| Utils::Buffer* buffer = pair.m_buffer; |
| bufferDescriptor* descriptor = pair.m_descriptor; |
| |
| /* Get pointer to contents of buffer */ |
| buffer->Bind(); |
| GLubyte* buffer_data = (GLubyte*)buffer->Map(Utils::Buffer::ReadOnly); |
| |
| /* Get pointer to expected data */ |
| GLubyte* expected_data = (GLubyte*)&descriptor->m_expected_data[0]; |
| |
| /* Compare */ |
| static const GLuint vec4_size = 16; |
| |
| int res_before = memcmp(buffer_data, expected_data, vec4_size); |
| int res_gohan = memcmp(buffer_data + 1 * vec4_size, expected_data + 1 * vec4_size, vec4_size); |
| int res_chichi = memcmp(buffer_data + 3 * vec4_size, expected_data + 3 * vec4_size, vec4_size); |
| |
| if ((0 != res_before) || (0 != res_gohan) || (0 != res_chichi)) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Invalid result. Buffer: " << Utils::Buffer::GetBufferName(descriptor->m_target) |
| << ". Index: " << descriptor->m_index << tcu::TestLog::EndMessage; |
| |
| result = false; |
| } |
| |
| /* Release buffer mapping */ |
| buffer->UnMap(); |
| |
| return result; |
| } |
| |
| /** Constructor |
| * |
| * @param context Test context |
| **/ |
| XFBCaptureStructTest::XFBCaptureStructTest(deqp::Context& context) |
| : BufferTestBase(context, "xfb_capture_struct", "Test verifies that inactive structure members are captured") |
| { |
| /* Nothing to be done here */ |
| } |
| |
| /** Execute drawArrays for single vertex |
| * |
| * @param test_case_index |
| * |
| * @return true |
| **/ |
| bool XFBCaptureStructTest::executeDrawCall(bool /* tesEnabled */, GLuint test_case_index) |
| { |
| const Functions& gl = m_context.getRenderContext().getFunctions(); |
| GLenum primitive_type = GL_PATCHES; |
| |
| if (TEST_VS == test_case_index) |
| { |
| primitive_type = GL_POINTS; |
| } |
| |
| gl.disable(GL_RASTERIZER_DISCARD); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Disable"); |
| |
| gl.beginTransformFeedback(GL_POINTS); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "BeginTransformFeedback"); |
| |
| gl.drawArrays(primitive_type, 0 /* first */, 1 /* count */); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays"); |
| |
| gl.endTransformFeedback(); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "EndTransformFeedback"); |
| |
| return true; |
| } |
| |
| /** Get descriptors of buffers necessary for test |
| * |
| * @param ignored |
| * @param out_descriptors Descriptors of buffers used by test |
| **/ |
| void XFBCaptureStructTest::getBufferDescriptors(glw::GLuint /* test_case_index */, |
| bufferDescriptor::Vector& out_descriptors) |
| { |
| const Utils::Type& type = Utils::Type::vec4; |
| |
| /* Test needs single uniform and xfb */ |
| out_descriptors.resize(2); |
| |
| /* Get references */ |
| bufferDescriptor& uniform = out_descriptors[0]; |
| bufferDescriptor& xfb = out_descriptors[1]; |
| |
| /* Index */ |
| uniform.m_index = 0; |
| xfb.m_index = 0; |
| |
| /* Target */ |
| uniform.m_target = Utils::Buffer::Uniform; |
| xfb.m_target = Utils::Buffer::Transform_feedback; |
| |
| /* Data */ |
| const std::vector<GLubyte>& gohan_data = type.GenerateData(); |
| const std::vector<GLubyte>& chichi_data = type.GenerateData(); |
| |
| const GLuint type_size = static_cast<GLuint>(gohan_data.size()); |
| |
| /* Uniform data */ |
| uniform.m_initial_data.resize(2 * type_size); |
| memcpy(&uniform.m_initial_data[0] + 0, &gohan_data[0], type_size); |
| memcpy(&uniform.m_initial_data[0] + type_size, &chichi_data[0], type_size); |
| |
| /* XFB data */ |
| xfb.m_initial_data.resize(4 * type_size); |
| xfb.m_expected_data.resize(4 * type_size); |
| |
| for (GLuint i = 0; i < 4 * type_size; ++i) |
| { |
| xfb.m_initial_data[i] = (glw::GLubyte)i; |
| xfb.m_expected_data[i] = (glw::GLubyte)i; |
| } |
| |
| memcpy(&xfb.m_expected_data[0] + 1 * type_size, &gohan_data[0], type_size); |
| memcpy(&xfb.m_expected_data[0] + 3 * type_size, &chichi_data[0], type_size); |
| } |
| |
| /** Get body of main function for given shader stage |
| * |
| * @param test_case_index Index of test case |
| * @param stage Shader stage |
| * @param out_assignments Set to empty |
| * @param out_calculations Set to empty |
| **/ |
| void XFBCaptureStructTest::getShaderBody(GLuint test_case_index, Utils::Shader::STAGES stage, |
| std::string& out_assignments, std::string& out_calculations) |
| { |
| out_calculations = ""; |
| |
| static const GLchar* vs_tes_gs = " goku.chichi = uni_chichi;\n" |
| " goku.gohan = uni_gohan;\n"; |
| static const GLchar* fs = " fs_out = goku.goten + goku.gohan + goku.chichi;\n"; |
| |
| const GLchar* assignments = ""; |
| |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| assignments = fs; |
| break; |
| |
| case Utils::Shader::GEOMETRY: |
| if (TEST_GS == test_case_index) |
| { |
| assignments = vs_tes_gs; |
| } |
| break; |
| |
| case Utils::Shader::TESS_CTRL: |
| break; |
| |
| case Utils::Shader::TESS_EVAL: |
| if (TEST_TES == test_case_index) |
| { |
| assignments = vs_tes_gs; |
| } |
| break; |
| |
| case Utils::Shader::VERTEX: |
| if (TEST_VS == test_case_index) |
| { |
| assignments = vs_tes_gs; |
| } |
| break; |
| |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| out_assignments = assignments; |
| } |
| |
| /** Get interface of shader |
| * |
| * @param test_case_index Index of test case |
| * @param stage Shader stage |
| * @param out_interface Set to "" |
| **/ |
| void XFBCaptureStructTest::getShaderInterface(GLuint test_case_index, Utils::Shader::STAGES stage, |
| std::string& out_interface) |
| { |
| static const GLchar* vs_tes_gs = "const uint sizeof_type = 16;\n" |
| "\n" |
| "struct Goku {\n" |
| " vec4 gohan;\n" |
| " vec4 goten;\n" |
| " vec4 chichi;\n" |
| "};\n" |
| "\n" |
| "layout (xfb_offset = sizeof_type) out Goku goku;\n" |
| "\n" |
| "layout(binding = 0, std140) uniform block {\n" |
| " vec4 uni_gohan;\n" |
| " vec4 uni_chichi;\n" |
| "};\n"; |
| static const GLchar* fs = "struct Goku {\n" |
| " vec4 gohan;\n" |
| " vec4 goten;\n" |
| " vec4 chichi;\n" |
| "};\n" |
| "\n" |
| "in Goku goku;\n" |
| "\n" |
| "out vec4 fs_out;\n"; |
| |
| const GLchar* interface = ""; |
| |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| interface = fs; |
| break; |
| |
| case Utils::Shader::GEOMETRY: |
| if (TEST_GS == test_case_index) |
| { |
| interface = vs_tes_gs; |
| } |
| break; |
| |
| case Utils::Shader::TESS_CTRL: |
| break; |
| |
| case Utils::Shader::TESS_EVAL: |
| if (TEST_TES == test_case_index) |
| { |
| interface = vs_tes_gs; |
| } |
| break; |
| |
| case Utils::Shader::VERTEX: |
| if (TEST_VS == test_case_index) |
| { |
| interface = vs_tes_gs; |
| } |
| break; |
| |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| out_interface = interface; |
| } |
| |
| /** Get source code of shader |
| * |
| * @param test_case_index Index of test case |
| * @param stage Shader stage |
| * |
| * @return Source |
| **/ |
| std::string XFBCaptureStructTest::getShaderSource(GLuint test_case_index, Utils::Shader::STAGES stage) |
| { |
| std::string source; |
| |
| switch (test_case_index) |
| { |
| case TEST_VS: |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| case Utils::Shader::VERTEX: |
| source = BufferTestBase::getShaderSource(test_case_index, stage); |
| break; |
| default: |
| break; |
| } |
| break; |
| |
| case TEST_TES: |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| case Utils::Shader::TESS_CTRL: |
| case Utils::Shader::TESS_EVAL: |
| case Utils::Shader::VERTEX: |
| source = BufferTestBase::getShaderSource(test_case_index, stage); |
| break; |
| default: |
| break; |
| } |
| break; |
| |
| case TEST_GS: |
| source = BufferTestBase::getShaderSource(test_case_index, stage); |
| break; |
| |
| default: |
| TCU_FAIL("Invalid enum"); |
| break; |
| } |
| |
| /* */ |
| return source; |
| } |
| |
| /** Get name of test case |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return Name of tested stage |
| **/ |
| std::string XFBCaptureStructTest::getTestCaseName(glw::GLuint test_case_index) |
| { |
| const GLchar* name = 0; |
| |
| switch (test_case_index) |
| { |
| case TEST_VS: |
| name = "vertex"; |
| break; |
| case TEST_TES: |
| name = "tessellation evaluation"; |
| break; |
| case TEST_GS: |
| name = "geometry"; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| return name; |
| } |
| |
| /** Returns number of test cases |
| * |
| * @return TEST_MAX |
| **/ |
| glw::GLuint XFBCaptureStructTest::getTestCaseNumber() |
| { |
| return TEST_MAX; |
| } |
| |
| /** Verify contents of buffers |
| * |
| * @param buffers Collection of buffers to be verified |
| * |
| * @return true if everything is as expected, false otherwise |
| **/ |
| bool XFBCaptureStructTest::verifyBuffers(bufferCollection& buffers) |
| { |
| bool result = true; |
| |
| bufferCollection::pair& pair = buffers.m_vector[1] /* xfb */; |
| Utils::Buffer* buffer = pair.m_buffer; |
| bufferDescriptor* descriptor = pair.m_descriptor; |
| |
| /* Get pointer to contents of buffer */ |
| buffer->Bind(); |
| GLubyte* buffer_data = (GLubyte*)buffer->Map(Utils::Buffer::ReadOnly); |
| |
| /* Get pointer to expected data */ |
| GLubyte* expected_data = (GLubyte*)&descriptor->m_expected_data[0]; |
| |
| /* Compare */ |
| static const GLuint vec4_size = 16; |
| |
| int res_before = memcmp(buffer_data, expected_data, vec4_size); |
| int res_gohan = memcmp(buffer_data + 1 * vec4_size, expected_data + 1 * vec4_size, vec4_size); |
| int res_chichi = memcmp(buffer_data + 3 * vec4_size, expected_data + 3 * vec4_size, vec4_size); |
| |
| if ((0 != res_before) || (0 != res_gohan) || (0 != res_chichi)) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Invalid result. Buffer: " << Utils::Buffer::GetBufferName(descriptor->m_target) |
| << ". Index: " << descriptor->m_index << tcu::TestLog::EndMessage; |
| |
| result = false; |
| } |
| |
| /* Release buffer mapping */ |
| buffer->UnMap(); |
| |
| return result; |
| } |
| |
| /** Constructor |
| * |
| * @param context Test framework context |
| **/ |
| XFBCaptureUnsizedArrayTest::XFBCaptureUnsizedArrayTest(deqp::Context& context) |
| : NegativeTestBase(context, "xfb_capture_unsized_array", |
| "Test verifies that compiler reports error when unsized array is qualified with xfb_offset") |
| { |
| } |
| |
| /** Source for given test case and stage |
| * |
| * @param test_case_index Index of test case |
| * @param stage Shader stage |
| * |
| * @return Shader source |
| **/ |
| std::string XFBCaptureUnsizedArrayTest::getShaderSource(GLuint test_case_index, Utils::Shader::STAGES stage) |
| { |
| #if DEBUG_NEG_REMOVE_ERROR |
| static const GLchar* var_definition = "/* layout (xfb_offset = 0) */ out vec4 goku[];\n"; |
| #else |
| static const GLchar* var_definition = "layout (xfb_offset = 0) out vec4 goku[];\n"; |
| #endif /* DEBUG_NEG_REMOVE_ERROR */ |
| static const GLchar* var_use = " goku[0] = result / 2;\n"; |
| static const GLchar* fs = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "in vec4 any_fs;\n" |
| "out vec4 fs_out;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " fs_out = any_fs;\n" |
| "}\n" |
| "\n"; |
| static const GLchar* vs_tested = "#version 430 core\n" |
| "#extension GL_ARB_enhanced_layouts : require\n" |
| "\n" |
| "VAR_DEFINITION" |
| "\n" |
| "in vec4 in_vs;\n" |
| "out vec4 any_fs;\n" |
| "\n" |
| "void main()\n" |
| "{\n" |
| " vec4 result = in_vs;\n" |
| "\n" |
| "VARIABLE_USE" |
| "\n" |
| " any_fs = result;\n" |
| "}\n" |
| "\n"; |
| |
| std::string source; |
| testCase& test_case = m_test_cases[test_case_index]; |
| |
| if (test_case.m_stage == stage) |
| { |
| size_t position = 0; |
| |
| switch (stage) |
| { |
| case Utils::Shader::VERTEX: |
| source = vs_tested; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| Utils::replaceToken("VAR_DEFINITION", position, var_definition, source); |
| position = 0; |
| Utils::replaceToken("VARIABLE_USE", position, var_use, source); |
| } |
| else |
| { |
| switch (test_case.m_stage) |
| { |
| case Utils::Shader::VERTEX: |
| switch (stage) |
| { |
| case Utils::Shader::FRAGMENT: |
| source = fs; |
| break; |
| default: |
| source = ""; |
| } |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| break; |
| } |
| } |
| |
| return source; |
| } |
| |
| /** Get description of test case |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return Test case description |
| **/ |
| std::string XFBCaptureUnsizedArrayTest::getTestCaseName(GLuint test_case_index) |
| { |
| std::stringstream stream; |
| testCase& test_case = m_test_cases[test_case_index]; |
| |
| stream << "Stage: " << Utils::Shader::GetStageName(test_case.m_stage); |
| |
| return stream.str(); |
| } |
| |
| /** Get number of test cases |
| * |
| * @return Number of test cases |
| **/ |
| GLuint XFBCaptureUnsizedArrayTest::getTestCaseNumber() |
| { |
| return static_cast<GLuint>(m_test_cases.size()); |
| } |
| |
| /** Selects if "compute" stage is relevant for test |
| * |
| * @param ignored |
| * |
| * @return false |
| **/ |
| bool XFBCaptureUnsizedArrayTest::isComputeRelevant(GLuint /* test_case_index */) |
| { |
| return false; |
| } |
| |
| /** Prepare all test cases |
| * |
| **/ |
| void XFBCaptureUnsizedArrayTest::testInit() |
| { |
| for (GLuint stage = 0; stage < Utils::Shader::STAGE_MAX; ++stage) |
| { |
| /* Not aplicable for */ |
| if ((Utils::Shader::COMPUTE == stage) || (Utils::Shader::TESS_CTRL == stage) || |
| (Utils::Shader::FRAGMENT == stage) || (Utils::Shader::GEOMETRY == stage) || |
| (Utils::Shader::TESS_EVAL == stage)) |
| { |
| continue; |
| } |
| |
| testCase test_case = { (Utils::Shader::STAGES)stage }; |
| |
| m_test_cases.push_back(test_case); |
| } |
| } |
| } /* EnhancedLayouts namespace */ |
| |
| /** Constructor. |
| * |
| * @param context Rendering context. |
| **/ |
| EnhancedLayoutsTests::EnhancedLayoutsTests(deqp::Context& context) |
| : TestCaseGroup(context, "enhanced_layouts", "Verifies \"enhanced layouts\" functionality") |
| { |
| /* Left blank on purpose */ |
| } |
| |
| /** Initializes a texture_storage_multisample test group. |
| * |
| **/ |
| void EnhancedLayoutsTests::init(void) |
| { |
| addChild(new EnhancedLayouts::APIConstantValuesTest(m_context)); |
| addChild(new EnhancedLayouts::APIErrorsTest(m_context)); |
| addChild(new EnhancedLayouts::GLSLContantValuesTest(m_context)); |
| addChild(new EnhancedLayouts::GLSLContantImmutablityTest(m_context)); |
| addChild(new EnhancedLayouts::GLSLConstantIntegralExpressionTest(m_context)); |
| addChild(new EnhancedLayouts::UniformBlockLayoutQualifierConflictTest(m_context)); |
| addChild(new EnhancedLayouts::SSBMemberInvalidOffsetAlignmentTest(m_context)); |
| addChild(new EnhancedLayouts::SSBMemberOverlappingOffsetsTest(m_context)); |
| addChild(new EnhancedLayouts::VaryingInvalidValueComponentTest(m_context)); |
| addChild(new EnhancedLayouts::VaryingExceedingComponentsTest(m_context)); |
| addChild(new EnhancedLayouts::VaryingComponentOfInvalidTypeTest(m_context)); |
| addChild(new EnhancedLayouts::OutputComponentAliasingTest(m_context)); |
| addChild(new EnhancedLayouts::VertexAttribLocationAPITest(m_context)); |
| addChild(new EnhancedLayouts::XFBInputTest(m_context)); |
| addChild(new EnhancedLayouts::XFBAllStagesTest(m_context)); |
| addChild(new EnhancedLayouts::XFBCaptureInactiveOutputVariableTest(m_context)); |
| addChild(new EnhancedLayouts::XFBCaptureInactiveOutputComponentTest(m_context)); |
| addChild(new EnhancedLayouts::XFBCaptureInactiveOutputBlockMemberTest(m_context)); |
| addChild(new EnhancedLayouts::XFBStrideTest(m_context)); |
| |
| addChild(new EnhancedLayouts::UniformBlockMemberOffsetAndAlignTest(m_context)); |
| addChild(new EnhancedLayouts::UniformBlockMemberInvalidOffsetAlignmentTest(m_context)); |
| addChild(new EnhancedLayouts::UniformBlockMemberOverlappingOffsetsTest(m_context)); |
| addChild(new EnhancedLayouts::UniformBlockMemberAlignNonPowerOf2Test(m_context)); |
| addChild(new EnhancedLayouts::SSBLayoutQualifierConflictTest(m_context)); |
| addChild(new EnhancedLayouts::SSBMemberAlignNonPowerOf2Test(m_context)); |
| addChild(new EnhancedLayouts::SSBAlignmentTest(m_context)); |
| addChild(new EnhancedLayouts::VaryingStructureMemberLocationTest(m_context)); |
| addChild(new EnhancedLayouts::VaryingBlockAutomaticMemberLocationsTest(m_context)); |
| addChild(new EnhancedLayouts::VaryingComponentWithoutLocationTest(m_context)); |
| addChild(new EnhancedLayouts::InputComponentAliasingTest(m_context)); |
| addChild(new EnhancedLayouts::VaryingLocationAliasingWithMixedTypesTest(m_context)); |
| addChild(new EnhancedLayouts::VaryingLocationAliasingWithMixedInterpolationTest(m_context)); |
| addChild(new EnhancedLayouts::VaryingLocationAliasingWithMixedAuxiliaryStorageTest(m_context)); |
| addChild(new EnhancedLayouts::XFBStrideOfEmptyListTest(m_context)); |
| addChild(new EnhancedLayouts::XFBStrideOfEmptyListAndAPITest(m_context)); |
| addChild(new EnhancedLayouts::XFBTooSmallStrideTest(m_context)); |
| addChild(new EnhancedLayouts::XFBBlockMemberStrideTest(m_context)); |
| addChild(new EnhancedLayouts::XFBDuplicatedStrideTest(m_context)); |
| addChild(new EnhancedLayouts::XFBGetProgramResourceAPITest(m_context)); |
| addChild(new EnhancedLayouts::XFBMultipleVertexStreamsTest(m_context)); |
| addChild(new EnhancedLayouts::XFBExceedBufferLimitTest(m_context)); |
| addChild(new EnhancedLayouts::XFBExceedOffsetLimitTest(m_context)); |
| addChild(new EnhancedLayouts::XFBBlockMemberBufferTest(m_context)); |
| addChild(new EnhancedLayouts::XFBOutputOverlappingTest(m_context)); |
| addChild(new EnhancedLayouts::XFBInvalidOffsetAlignmentTest(m_context)); |
| addChild(new EnhancedLayouts::XFBCaptureStructTest(m_context)); |
| addChild(new EnhancedLayouts::XFBCaptureUnsizedArrayTest(m_context)); |
| addChild(new EnhancedLayouts::UniformBlockAlignmentTest(m_context)); |
| addChild(new EnhancedLayouts::SSBMemberOffsetAndAlignTest(m_context)); |
| addChild(new EnhancedLayouts::VertexAttribLocationsTest(m_context)); |
| addChild(new EnhancedLayouts::VaryingLocationsTest(m_context)); |
| addChild(new EnhancedLayouts::VaryingArrayLocationsTest(m_context)); |
| addChild(new EnhancedLayouts::VaryingStructureLocationsTest(m_context)); |
| addChild(new EnhancedLayouts::VaryingBlockLocationsTest(m_context)); |
| addChild(new EnhancedLayouts::VaryingBlockMemberLocationsTest(m_context)); |
| addChild(new EnhancedLayouts::XFBVariableStrideTest(m_context)); |
| addChild(new EnhancedLayouts::XFBBlockStrideTest(m_context)); |
| addChild(new EnhancedLayouts::XFBOverrideQualifiersWithAPITest(m_context)); |
| addChild(new EnhancedLayouts::XFBVertexStreamsTest(m_context)); |
| addChild(new EnhancedLayouts::XFBGlobalBufferTest(m_context)); |
| addChild(new EnhancedLayouts::FragmentDataLocationAPITest(m_context)); |
| addChild(new EnhancedLayouts::VaryingLocationLimitTest(m_context)); |
| addChild(new EnhancedLayouts::VaryingComponentsTest(m_context)); |
| addChild(new EnhancedLayouts::VaryingArrayComponentsTest(m_context)); |
| } |
| |
| } /* gl4cts namespace */ |