Fix VK-GL-CTS build error
... temporarily by overriding the offending file until the upstream fix
lands.
Bug: angleproject:432337091
Change-Id: I878561e0856e43b657bcaf08a7563ac639794098
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/6775382
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
diff --git a/src/tests/BUILD.gn b/src/tests/BUILD.gn
index c0dc92a..c31bc41 100644
--- a/src/tests/BUILD.gn
+++ b/src/tests/BUILD.gn
@@ -1886,7 +1886,10 @@
deqp_khr_gl_sources + deqp_khr_gles2_sources +
deqp_khr_gles3_sources + deqp_khr_gles31_sources +
deqp_khr_gles32_sources + deqp_khr_glesext_sources +
- [ "deqp_support/glcTestPackageEntry_override.cpp" ]
+ [
+ "deqp_support/gl4cEnhancedLayoutsTests_override.cpp",
+ "deqp_support/glcTestPackageEntry_override.cpp",
+ ]
public_deps = [
":angle_deqp_framework_platform",
":angle_deqp_glshared",
diff --git a/src/tests/deqp_support/deqp.gni b/src/tests/deqp_support/deqp.gni
index de9e9db..9c84957 100644
--- a/src/tests/deqp_support/deqp.gni
+++ b/src/tests/deqp_support/deqp.gni
@@ -1135,7 +1135,10 @@
"$deqp_path/external/openglcts/modules/gl/gl4cDirectStateAccessXFBTests.cpp",
"$deqp_path/external/openglcts/modules/gl/gl4cES31CompatibilityTests.cpp",
"$deqp_path/external/openglcts/modules/gl/gl4cES31CompatibilityTests.hpp",
- "$deqp_path/external/openglcts/modules/gl/gl4cEnhancedLayoutsTests.cpp",
+
+ # Overriden with an include fix until fix
+ # (https://gerrit.khronos.org/c/vk-gl-cts/+/17729) lands upstream.
+ # "$deqp_path/external/openglcts/modules/gl/gl4cEnhancedLayoutsTests.cpp",
"$deqp_path/external/openglcts/modules/gl/gl4cEnhancedLayoutsTests.hpp",
"$deqp_path/external/openglcts/modules/gl/gl4cGPUShaderFP64Tests.cpp",
"$deqp_path/external/openglcts/modules/gl/gl4cGPUShaderFP64Tests.hpp",
diff --git a/src/tests/deqp_support/gl4cEnhancedLayoutsTests_override.cpp b/src/tests/deqp_support/gl4cEnhancedLayoutsTests_override.cpp
new file mode 100644
index 0000000..fe3d91a
--- /dev/null
+++ b/src/tests/deqp_support/gl4cEnhancedLayoutsTests_override.cpp
@@ -0,0 +1,30682 @@
+/*-------------------------------------------------------------------------
+ * 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 <iterator>
+#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);
+ const GLuint padding = alignment - GetTypeSize(m_basic_type) * m_n_rows;
+ const GLuint data_size = alignment * m_n_columns - padding;
+
+ std::vector<GLubyte> data;
+ data.resize(data_size);
+
+ 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)
+{
+ /* Quick 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");
+ }
+}
+
+/** 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");
+ }
+}
+
+/** 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");
+ }
+
+ 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");
+ }
+
+ 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");
+ }
+}
+
+/** 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");
+ }
+
+ 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);
+}
+} // namespace Utils
+
+/** 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;
+}
+
+const glw::GLuint TYPES_NUMBER = 34;
+
+/** 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");
+ }
+
+ /* 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");
+ }
+
+ /* 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;
+ return TYPES_NUMBER;
+}
+
+/** 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 (tcu::NotSupportedError &exc)
+ {
+ // Write message to log and return true to continue with rest of test cases
+ m_context.getTestContext().getLog().writeMessage(exc.what());
+ return true;
+ }
+ 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,
+ GLuint constant,
+ GLuint stage)
+ : NegativeTestBase(context,
+ "glsl_contant_immutablity",
+ "Test verifies that glsl constants cannot be modified"),
+ m_constant(constant),
+ m_stage(stage)
+{
+ std::string name = ("glsl_contant_immutablity_");
+ name.append(EnhancedLayouts::GLSLContantImmutablityTest::getConstantName(
+ (EnhancedLayouts::GLSLContantImmutablityTest::CONSTANTS)constant));
+ name.append("_");
+ name.append(EnhancedLayouts::Utils::Shader::GetStageName(
+ (EnhancedLayouts::Utils::Shader::STAGES)stage));
+
+ NegativeTestBase::m_name = name.c_str();
+}
+
+/** 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()
+{
+ testCase test_case = {(CONSTANTS)m_constant, (Utils::Shader::STAGES)m_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,
+ glw::GLuint qualifier,
+ glw::GLuint stage)
+ : NegativeTestBase(context,
+ "uniform_block_layout_qualifier_conflict",
+ "Test verifies that std140 is required when offset and/or align qualifiers "
+ "are used with uniform block"),
+ m_qualifier(qualifier),
+ m_stage(stage)
+{
+ std::string name = ("uniform_block_layout_qualifier_conflict_");
+ name.append(EnhancedLayouts::UniformBlockLayoutQualifierConflictTest::getQualifierName(
+ (EnhancedLayouts::UniformBlockLayoutQualifierConflictTest::QUALIFIERS)qualifier));
+ name.append("_");
+ name.append(EnhancedLayouts::Utils::Shader::GetStageName(
+ (EnhancedLayouts::Utils::Shader::STAGES)stage));
+
+ NegativeTestBase::m_name = name.c_str();
+}
+
+/** 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 b;\n"
+ " layout(align = 64) vec4 a;\n"
+ "} uni_block;\n"
+ "\n"
+ "writeonly uniform image2D uni_image;\n"
+ "\n"
+ "void main()\n"
+ "{\n"
+ " vec4 result = uni_block.b + uni_block.a;\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 b;\n"
+ " layout(align = 64) vec4 a;\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.b + uni_block.a;\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 b;\n"
+ " layout(align = 64) vec4 a;\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.b + uni_block.a;\n"
+ " gl_Position = vec4(-1, -1, 0, 1);\n"
+ " EmitVertex();\n"
+ " gs_fs = tes_gs[0] + uni_block.b + uni_block.a;\n"
+ " gl_Position = vec4(-1, 1, 0, 1);\n"
+ " EmitVertex();\n"
+ " gs_fs = tes_gs[0] + uni_block.b + uni_block.a;\n"
+ " gl_Position = vec4(1, -1, 0, 1);\n"
+ " EmitVertex();\n"
+ " gs_fs = tes_gs[0] + uni_block.b + uni_block.a;\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 b;\n"
+ " layout(align = 64) vec4 a;\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.b + uni_block.a;\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 b;\n"
+ " layout(align = 64) vec4 a;\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.b + uni_block.a;\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 b;\n"
+ " layout(align = 64) vec4 a;\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.b + uni_block.a;\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()
+{
+ testCase test_case = {(QUALIFIERS)m_qualifier, (Utils::Shader::STAGES)m_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 = "default";
+ 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,
+ GLuint type,
+ GLuint stage)
+ : NegativeTestBase(
+ context,
+ "uniform_block_member_invalid_offset_alignment",
+ "Test verifies that invalid alignment of offset qualifiers cause compilation failure"),
+ m_type(type),
+ m_stage(stage)
+{
+ std::string name = ("uniform_block_member_invalid_offset_alignment_");
+ name.append(getTypeName(type));
+ name.append("_");
+ name.append(EnhancedLayouts::Utils::Shader::GetStageName(
+ (EnhancedLayouts::Utils::Shader::STAGES)stage));
+
+ NegativeTestBase::m_name = name.c_str();
+}
+
+/** 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,
+ GLuint type,
+ GLuint stage)
+ : NegativeTestBase(context, name, description), m_type(type), m_stage(stage)
+{
+ /* 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 Utils::Type &type = getType(m_type);
+ const GLuint alignment = type.GetBaseAlignment(false);
+ const GLuint type_size = type.GetSize(true);
+ const GLuint sec_to_end = getMaxBlockSize() - 2 * type_size;
+
+ 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)m_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)m_stage, type};
+
+ m_test_cases.push_back(test_case);
+ }
+}
+
+/** Constructor
+ *
+ * @param context Test framework context
+ **/
+UniformBlockMemberOverlappingOffsetsTest::UniformBlockMemberOverlappingOffsetsTest(
+ deqp::Context &context,
+ GLuint type_i,
+ GLuint type_j)
+ : NegativeTestBase(
+ context,
+ "uniform_block_member_overlapping_offsets",
+ "Test verifies that overlapping offsets qualifiers cause compilation failure"),
+ m_type_i(type_i),
+ m_type_j(type_j)
+{
+ std::string name = ("uniform_block_member_overlapping_offsets_");
+ name.append(getTypeName(type_i));
+ name.append("_");
+ name.append(getTypeName(type_j));
+
+ NegativeTestBase::m_name = name.c_str();
+}
+
+/** 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,
+ GLuint type_i,
+ GLuint type_j)
+ : NegativeTestBase(context, name, description), m_type_i(type_i), m_type_j(type_j)
+{
+ /* 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 = B_OFFSET) B_TYPE b;\n"
+ " layout (offset = A_OFFSET) A_TYPE a;\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 ((B_TYPE(1) == block.b) ||\n"
+ " (A_TYPE(0) == block.a) )\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 = B_OFFSET) B_TYPE b;\n"
+ " layout (offset = A_OFFSET) A_TYPE a;\n"
+ "} block;\n"
+ "\n"
+ "in vec4 gs_fs;\n"
+ "out vec4 fs_out;\n"
+ "\n"
+ "void main()\n"
+ "{\n"
+ " if ((B_TYPE(1) == block.b) ||\n"
+ " (A_TYPE(0) == block.a) )\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 = B_OFFSET) B_TYPE b;\n"
+ " layout (offset = A_OFFSET) A_TYPE a;\n"
+ "} block;\n"
+ "\n"
+ "in vec4 tes_gs[];\n"
+ "out vec4 gs_fs;\n"
+ "\n"
+ "void main()\n"
+ "{\n"
+ " if ((B_TYPE(1) == block.b) ||\n"
+ " (A_TYPE(0) == block.a) )\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 = B_OFFSET) B_TYPE b;\n"
+ " layout (offset = A_OFFSET) A_TYPE a;\n"
+ "} block;\n"
+ "\n"
+ "in vec4 vs_tcs[];\n"
+ "out vec4 tcs_tes[];\n"
+ "\n"
+ "void main()\n"
+ "{\n"
+ " if ((B_TYPE(1) == block.b) ||\n"
+ " (A_TYPE(0) == block.a) )\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 = B_OFFSET) B_TYPE b;\n"
+ " layout (offset = A_OFFSET) A_TYPE a;\n"
+ "} block;\n"
+ "\n"
+ "in vec4 tcs_tes[];\n"
+ "out vec4 tes_gs;\n"
+ "\n"
+ "void main()\n"
+ "{\n"
+ " if ((B_TYPE(1) == block.b) ||\n"
+ " (A_TYPE(0) == block.a) )\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 = B_OFFSET) B_TYPE b;\n"
+ " layout (offset = A_OFFSET) A_TYPE a;\n"
+ "} block;\n"
+ "\n"
+ "in vec4 in_vs;\n"
+ "out vec4 vs_tcs;\n"
+ "\n"
+ "void main()\n"
+ "{\n"
+ " if ((B_TYPE(1) == block.b) ||\n"
+ " (A_TYPE(0) == block.a) )\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 b_offset = test_case.m_b_offset;
+ const Utils::Type &b_type = test_case.m_b_type;
+ const GLchar *b_type_name = b_type.GetGLSLTypeName();
+ const GLuint a_offset = test_case.m_a_offset;
+ const Utils::Type &a_type = test_case.m_a_type;
+ const GLchar *a_type_name = a_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", b_offset);
+ Utils::replaceToken("B_OFFSET", position, buffer, source);
+ Utils::replaceToken("B_TYPE", position, b_type_name, source);
+ sprintf(buffer, "%d", a_offset);
+ Utils::replaceToken("A_OFFSET", position, buffer, source);
+ Utils::replaceToken("A_TYPE", position, a_type_name, source);
+ Utils::replaceToken("B_TYPE", position, b_type_name, source);
+ Utils::replaceToken("A_TYPE", position, a_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_b_type.GetGLSLTypeName()
+ << ", offset: " << test_case.m_b_offset
+ << ". Type: " << test_case.m_a_type.GetGLSLTypeName()
+ << ", offset: " << test_case.m_a_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()
+{
+ 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);
+ }
+
+ const Utils::Type &b_type = getType(m_type_i);
+ const GLuint b_size = b_type.GetActualAlignment(1 /* align */, false /* is_array*/);
+
+ const Utils::Type &a_type = getType(m_type_j);
+ const GLuint a_align = a_type.GetBaseAlignment(false);
+ const GLuint a_size = a_type.GetActualAlignment(1 /* align */, false /* is_array*/);
+
+ const GLuint b_offset = lcm(b_size, a_size);
+ const GLuint a_after_start = b_offset + 1;
+ const GLuint a_after_off = a_type.GetActualOffset(a_after_start, a_size);
+ const GLuint a_before_start = b_offset - a_align;
+ const GLuint a_before_off = a_type.GetActualOffset(a_before_start, a_size);
+
+ for (GLuint stage = 0; stage < Utils::Shader::STAGE_MAX; ++stage)
+ {
+ if (false == stage_support[stage])
+ {
+ continue;
+ }
+
+ if ((b_offset > a_before_off) && (b_offset < a_before_off + a_size))
+ {
+ testCase test_case = {b_offset, b_type, a_before_off, a_type,
+ (Utils::Shader::STAGES)stage};
+
+ m_test_cases.push_back(test_case);
+ }
+
+ if ((b_offset < a_after_off) && (b_offset + b_size > a_after_off))
+ {
+ testCase test_case = {b_offset, b_type, a_after_off, a_type,
+ (Utils::Shader::STAGES)stage};
+
+ m_test_cases.push_back(test_case);
+ }
+
+ /* b offset, should be fine for both types */
+ testCase test_case = {b_offset, b_type, b_offset, a_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,
+ glw::GLuint type)
+ : NegativeTestBase(context,
+ "uniform_block_member_align_non_power_of_2",
+ "Test verifies that align qualifier requires value that is a power of 2"),
+ m_type(type)
+{
+ std::string name = ("uniform_block_member_align_non_power_of_2_");
+ name.append(getTypeName(type));
+
+ NegativeTestBase::m_name = name.c_str();
+}
+
+/** 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,
+ glw::GLuint type)
+ : NegativeTestBase(context, name, description), m_type(type)
+{
+ /* 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 b;\n"
+ " layout (align = ALIGN) TYPE a;\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.a)\n"
+ " {\n"
+ " result = vec4(1, 1, 1, 1) - block.b;\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 b;\n"
+ " layout (align = ALIGN) TYPE a;\n"
+ "} block;\n"
+ "\n"
+ "in vec4 gs_fs;\n"
+ "out vec4 fs_out;\n"
+ "\n"
+ "void main()\n"
+ "{\n"
+ " if (TYPE(0) == block.a)\n"
+ " {\n"
+ " fs_out = block.b;\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 b;\n"
+ " layout (align = ALIGN) TYPE a;\n"
+ "} block;\n"
+ "\n"
+ "in vec4 tes_gs[];\n"
+ "out vec4 gs_fs;\n"
+ "\n"
+ "void main()\n"
+ "{\n"
+ " if (TYPE(0) == block.a)\n"
+ " {\n"
+ " gs_fs = block.b;\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 b;\n"
+ " layout (align = ALIGN) TYPE a;\n"
+ "} block;\n"
+ "\n"
+ "in vec4 vs_tcs[];\n"
+ "out vec4 tcs_tes[];\n"
+ "\n"
+ "void main()\n"
+ "{\n"
+ " if (TYPE(0) == block.a)\n"
+ " {\n"
+ " tcs_tes[gl_InvocationID] = block.b;\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 b;\n"
+ " layout (align = ALIGN) TYPE a;\n"
+ "} block;\n"
+ "\n"
+ "in vec4 tcs_tes[];\n"
+ "out vec4 tes_gs;\n"
+ "\n"
+ "void main()\n"
+ "{\n"
+ " if (TYPE(0) == block.a)\n"
+ " {\n"
+ " tes_gs = block.b;\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 b;\n"
+ " layout (align = ALIGN) TYPE a;\n"
+ "} block;\n"
+ "\n"
+ "in vec4 in_vs;\n"
+ "out vec4 vs_tcs;\n"
+ "\n"
+ "void main()\n"
+ "{\n"
+ " if (TYPE(0) == block.a)\n"
+ " {\n"
+ " vs_tcs = block.b;\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;
+ 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);
+ }
+
+ const Utils::Type &type = getType(m_type);
+
+ 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,
+ GLuint qualifier,
+ GLuint stage)
+ : 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"),
+ m_qualifier(qualifier),
+ m_stage(stage)
+{
+ std::string name = ("ssb_layout_qualifier_conflict_");
+ name.append(EnhancedLayouts::SSBLayoutQualifierConflictTest::getQualifierName(
+ (EnhancedLayouts::SSBLayoutQualifierConflictTest::QUALIFIERS)qualifier));
+ name.append("_");
+ name.append(EnhancedLayouts::Utils::Shader::GetStageName(
+ (EnhancedLayouts::Utils::Shader::STAGES)stage));
+
+ NegativeTestBase::m_name = name.c_str();
+}
+
+/** 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 b;\n"
+ " layout(align = 64) vec4 a;\n"
+ "} uni_block;\n"
+ "\n"
+ "writeonly uniform image2D uni_image;\n"
+ "\n"
+ "void main()\n"
+ "{\n"
+ " vec4 result = uni_block.b + uni_block.a;\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 b;\n"
+ " layout(align = 64) vec4 a;\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.b + uni_block.a;\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 b;\n"
+ " layout(align = 64) vec4 a;\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.b + uni_block.a;\n"
+ " gl_Position = vec4(-1, -1, 0, 1);\n"
+ " EmitVertex();\n"
+ " gs_fs = tes_gs[0] + uni_block.b + uni_block.a;\n"
+ " gl_Position = vec4(-1, 1, 0, 1);\n"
+ " EmitVertex();\n"
+ " gs_fs = tes_gs[0] + uni_block.b + uni_block.a;\n"
+ " gl_Position = vec4(1, -1, 0, 1);\n"
+ " EmitVertex();\n"
+ " gs_fs = tes_gs[0] + uni_block.b + uni_block.a;\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 b;\n"
+ " layout(align = 64) vec4 a;\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.b + uni_block.a;\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 b;\n"
+ " layout(align = 64) vec4 a;\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.b + uni_block.a;\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 b;\n"
+ " layout(align = 64) vec4 a;\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.b + uni_block.a;\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()
+{
+ testCase test_case = {(QUALIFIERS)m_qualifier, (Utils::Shader::STAGES)m_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,
+ GLuint type,
+ GLuint stage)
+ : UniformBlockMemberInvalidOffsetAlignmentTest(
+ context,
+ "ssb_member_invalid_offset_alignment",
+ "Test verifies that invalid alignment of offset qualifiers cause compilation failure",
+ type,
+ stage)
+{
+ std::string name = ("ssb_member_invalid_offset_alignment_");
+ name.append(getTypeName(type));
+ name.append("_");
+ name.append(EnhancedLayouts::Utils::Shader::GetStageName(
+ (EnhancedLayouts::Utils::Shader::STAGES)stage));
+
+ NegativeTestBase::m_name = name.c_str();
+}
+
+/** 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,
+ GLuint type_i,
+ GLuint type_j)
+ : UniformBlockMemberOverlappingOffsetsTest(
+ context,
+ "ssb_member_overlapping_offsets",
+ "Test verifies that overlapping offsets qualifiers cause compilation failure",
+ type_i,
+ type_j)
+{
+ std::string name = ("ssb_member_overlapping_offsets_");
+ name.append(getTypeName(type_i));
+ name.append("_");
+ name.append(getTypeName(type_j));
+
+ NegativeTestBase::m_name = name.c_str();
+}
+
+/** 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 = B_OFFSET) B_TYPE b;\n"
+ " layout (offset = A_OFFSET) A_TYPE a;\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 ((B_TYPE(1) == block.b) ||\n"
+ " (A_TYPE(0) == block.a) )\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 = B_OFFSET) B_TYPE b;\n"
+ " layout (offset = A_OFFSET) A_TYPE a;\n"
+ "} block;\n"
+ "\n"
+ "in vec4 gs_fs;\n"
+ "out vec4 fs_out;\n"
+ "\n"
+ "void main()\n"
+ "{\n"
+ " if ((B_TYPE(1) == block.b) ||\n"
+ " (A_TYPE(0) == block.a) )\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 = B_OFFSET) B_TYPE b;\n"
+ " layout (offset = A_OFFSET) A_TYPE a;\n"
+ "} block;\n"
+ "\n"
+ "in vec4 tes_gs[];\n"
+ "out vec4 gs_fs;\n"
+ "\n"
+ "void main()\n"
+ "{\n"
+ " if ((B_TYPE(1) == block.b) ||\n"
+ " (A_TYPE(0) == block.a) )\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 = B_OFFSET) B_TYPE b;\n"
+ " layout (offset = A_OFFSET) A_TYPE a;\n"
+ "} block;\n"
+ "\n"
+ "in vec4 vs_tcs[];\n"
+ "out vec4 tcs_tes[];\n"
+ "\n"
+ "void main()\n"
+ "{\n"
+ " if ((B_TYPE(1) == block.b) ||\n"
+ " (A_TYPE(0) == block.a) )\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 = B_OFFSET) B_TYPE b;\n"
+ " layout (offset = A_OFFSET) A_TYPE a;\n"
+ "} block;\n"
+ "\n"
+ "in vec4 tcs_tes[];\n"
+ "out vec4 tes_gs;\n"
+ "\n"
+ "void main()\n"
+ "{\n"
+ " if ((B_TYPE(1) == block.b) ||\n"
+ " (A_TYPE(0) == block.a) )\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 = B_OFFSET) B_TYPE b;\n"
+ " layout (offset = A_OFFSET) A_TYPE a;\n"
+ "} block;\n"
+ "\n"
+ "in vec4 in_vs;\n"
+ "out vec4 vs_tcs;\n"
+ "\n"
+ "void main()\n"
+ "{\n"
+ " if ((B_TYPE(1) == block.b) ||\n"
+ " (A_TYPE(0) == block.a) )\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 b_offset = test_case.m_b_offset;
+ const Utils::Type &b_type = test_case.m_b_type;
+ const GLchar *b_type_name = b_type.GetGLSLTypeName();
+ const GLuint a_offset = test_case.m_a_offset;
+ const Utils::Type &a_type = test_case.m_a_type;
+ const GLchar *a_type_name = a_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", b_offset);
+ Utils::replaceToken("B_OFFSET", position, buffer, source);
+ Utils::replaceToken("B_TYPE", position, b_type_name, source);
+ sprintf(buffer, "%d", a_offset);
+ Utils::replaceToken("A_OFFSET", position, buffer, source);
+ Utils::replaceToken("A_TYPE", position, a_type_name, source);
+ Utils::replaceToken("B_TYPE", position, b_type_name, source);
+ Utils::replaceToken("A_TYPE", position, a_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, GLuint type)
+ : UniformBlockMemberAlignNonPowerOf2Test(
+ context,
+ "ssb_member_align_non_power_of_2",
+ "Test verifies that align qualifier requires value that is a power of 2",
+ type)
+{
+ std::string name = ("ssb_member_align_non_power_of_2_");
+ name.append(getTypeName(type));
+
+ NegativeTestBase::m_name = name.c_str();
+}
+
+/** 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 b;\n"
+ " layout (align = ALIGN) TYPE a;\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.a)\n"
+ " {\n"
+ " result = vec4(1, 1, 1, 1) - block.b;\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 b;\n"
+ " layout (align = ALIGN) TYPE a;\n"
+ "} block;\n"
+ "\n"
+ "in vec4 gs_fs;\n"
+ "out vec4 fs_out;\n"
+ "\n"
+ "void main()\n"
+ "{\n"
+ " if (TYPE(0) == block.a)\n"
+ " {\n"
+ " fs_out = block.b;\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 b;\n"
+ " layout (align = ALIGN) TYPE a;\n"
+ "} block;\n"
+ "\n"
+ "in vec4 tes_gs[];\n"
+ "out vec4 gs_fs;\n"
+ "\n"
+ "void main()\n"
+ "{\n"
+ " if (TYPE(0) == block.a)\n"
+ " {\n"
+ " gs_fs = block.b;\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 b;\n"
+ " layout (align = ALIGN) TYPE a;\n"
+ "} block;\n"
+ "\n"
+ "in vec4 vs_tcs[];\n"
+ "out vec4 tcs_tes[];\n"
+ "\n"
+ "void main()\n"
+ "{\n"
+ " if (TYPE(0) == block.a)\n"
+ " {\n"
+ " tcs_tes[gl_InvocationID] = block.b;\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 b;\n"
+ " layout (align = ALIGN) TYPE a;\n"
+ "} block;\n"
+ "\n"
+ "in vec4 tcs_tes[];\n"
+ "out vec4 tes_gs;\n"
+ "\n"
+ "void main()\n"
+ "{\n"
+ " if (TYPE(0) == block.a)\n"
+ " {\n"
+ " tes_gs = block.b;\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 b;\n"
+ " layout (align = ALIGN) TYPE a;\n"
+ "} block;\n"
+ "\n"
+ "in vec4 in_vs;\n"
+ "out vec4 vs_tcs;\n"
+ "\n"
+ "void main()\n"
+ "{\n"
+ " if (TYPE(0) == block.a)\n"
+ " {\n"
+ " vs_tcs = block.b;\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"),
+ m_gl_max_geometry_input_components(0)
+{
+ const Functions &gl = m_context.getRenderContext().getFunctions();
+ gl.getIntegerv(GL_MAX_GEOMETRY_INPUT_COMPONENTS, &m_gl_max_geometry_input_components);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
+}
+
+/** 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);
+
+ GLint totalComponents = 2 * type.m_n_columns * type.m_n_rows;
+ if (type.m_basic_type == Utils::Type::Double)
+ {
+ totalComponents = totalComponents * 2;
+ }
+ if (totalComponents >= m_gl_max_geometry_input_components)
+ {
+ throw tcu::NotSupportedError("Test case index " + std::to_string(test_case_index) +
+ " for type " + type.GetGLSLTypeName() + " not supported");
+ }
+ 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, nullptr);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "DrawElements");
+ break;
+ case DRAWELEMENTSBASEVERTEX:
+ gl.drawElementsBaseVertex(GL_PATCHES, 1 /* count */, GL_UNSIGNED_BYTE, nullptr,
+ m_base_vertex);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "DrawElementsBaseVertex");
+ break;
+ case DRAWELEMENTSINSTANCED:
+ gl.drawElementsInstanced(GL_PATCHES, 1 /* count */, GL_UNSIGNED_BYTE, nullptr,
+ m_n_instances);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "DrawElementsInstanced");
+ break;
+ case DRAWELEMENTSINSTANCEDBASEINSTANCE:
+ gl.drawElementsInstancedBaseInstance(GL_PATCHES, 1 /* count */, GL_UNSIGNED_BYTE,
+ nullptr, 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, nullptr,
+ 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, nullptr, 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,
+ GLuint stage)
+ : NegativeTestBase(
+ context,
+ "varying_structure_member_location",
+ "Test verifies that compiler does not allow location qualifier on member of structure"),
+ m_stage(stage)
+{
+ std::string name = ("varying_structure_member_location_");
+ name.append(EnhancedLayouts::Utils::Shader::GetStageName(
+ (EnhancedLayouts::Utils::Shader::STAGES)stage));
+
+ NegativeTestBase::m_name = name.c_str();
+}
+
+/** 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()
+{
+ testCase test_case_in = {true, (Utils::Shader::STAGES)m_stage};
+ testCase test_case_out = {false, (Utils::Shader::STAGES)m_stage};
+
+ /* It is a compile-time error to declare a struct as a VS input */
+ if (Utils::Shader::VERTEX != m_stage)
+ {
+ m_test_cases.push_back(test_case_in);
+ }
+
+ if (Utils::Shader::FRAGMENT != m_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,
+ GLuint stage)
+ : NegativeTestBase(context,
+ "varying_block_member_locations",
+ "Test verifies that compilation error is reported when not all members of "
+ "block are qualified with location"),
+ m_stage(stage)
+{
+ std::string name = ("varying_block_member_locations_");
+ name.append(EnhancedLayouts::Utils::Shader::GetStageName(
+ (EnhancedLayouts::Utils::Shader::STAGES)stage));
+
+ NegativeTestBase::m_name = name.c_str();
+}
+
+/** 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()
+{
+ testCase test_case_in_all = {true, true, (Utils::Shader::STAGES)m_stage};
+ testCase test_case_in_one = {true, false, (Utils::Shader::STAGES)m_stage};
+ testCase test_case_out_all = {false, true, (Utils::Shader::STAGES)m_stage};
+ testCase test_case_out_one = {false, false, (Utils::Shader::STAGES)m_stage};
+
+ if (Utils::Shader::VERTEX != m_stage)
+ {
+ m_test_cases.push_back(test_case_in_all);
+ m_test_cases.push_back(test_case_in_one);
+ }
+
+ if (Utils::Shader::FRAGMENT != m_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,
+ GLuint stage)
+ : NegativeTestBase(context,
+ "varying_block_automatic_member_locations",
+ "Test verifies that compiler assigns subsequent locations to block members, "
+ "even if this causes errors"),
+ m_stage(stage)
+{
+ std::string name = ("varying_block_automatic_member_locations_");
+ name.append(EnhancedLayouts::Utils::Shader::GetStageName(
+ (EnhancedLayouts::Utils::Shader::STAGES)stage));
+
+ NegativeTestBase::m_name = name.c_str();
+}
+
+/** 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;
+ }
+
+ bool needs_vertex_output = stage == Utils::Shader::VERTEX && true == test_case.m_is_input &&
+ test_case.m_stage != Utils::Shader::VERTEX;
+ bool needs_fragment_input = stage == Utils::Shader::FRAGMENT && false == test_case.m_is_input &&
+ test_case.m_stage != Utils::Shader::FRAGMENT;
+
+ if (test_case.m_stage == stage || needs_vertex_output || needs_fragment_input)
+ {
+ size_t position = 0;
+
+ switch (stage)
+ {
+ case Utils::Shader::FRAGMENT:
+ direction = "in";
+ var_use = input_use;
+ 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:
+ direction = "out";
+ var_use = output_use;
+ 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()
+{
+ testCase test_case_in = {true, (Utils::Shader::STAGES)m_stage};
+ testCase test_case_out = {false, (Utils::Shader::STAGES)m_stage};
+
+ if (Utils::Shader::VERTEX != m_stage)
+ {
+ m_test_cases.push_back(test_case_in);
+ }
+
+ if (Utils::Shader::FRAGMENT != m_stage)
+ {
+ m_test_cases.push_back(test_case_out);
+ }
+}
+
+/** Constructor
+ *
+ * @param context Test framework context
+ **/
+VaryingLocationLimitTest::VaryingLocationLimitTest(deqp::Context &context,
+ GLuint type,
+ GLuint stage)
+ : NegativeTestBase(
+ context,
+ "varying_location_limit",
+ "Test verifies that compiler reports error when location qualifier exceeds limits"),
+ m_type(type),
+ m_stage(stage)
+{
+ std::string name = ("varying_location_limit_");
+ name.append(getTypeName(m_type));
+ name.append("_");
+ name.append(EnhancedLayouts::Utils::Shader::GetStageName(
+ (EnhancedLayouts::Utils::Shader::STAGES)stage));
+
+ NegativeTestBase::m_name = name.c_str();
+}
+
+/** 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";
+
+ bool needs_vertex_output = stage == Utils::Shader::VERTEX && true == test_case.m_is_input &&
+ test_case.m_stage != Utils::Shader::VERTEX;
+ bool needs_fragment_input = stage == Utils::Shader::FRAGMENT && false == test_case.m_is_input &&
+ test_case.m_stage != Utils::Shader::FRAGMENT;
+
+ if (test_case.m_stage == stage || needs_fragment_input || needs_vertex_output)
+ {
+ 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 && !needs_fragment_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:
+ direction = "in ";
+ last = getLastInputLocation(stage, test_case.m_type, 0, true);
+ storage = Utils::Variable::VARYING_INPUT;
+ var_use = input_use;
+
+ 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:
+ direction = "out";
+ last = getLastOutputLocation(stage, test_case.m_type, 0, true);
+ storage = Utils::Variable::VARYING_OUTPUT;
+ var_use = output_use;
+
+ 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 Utils::Type &type = getType(m_type);
+
+ testCase test_case_in = {true, type, (Utils::Shader::STAGES)m_stage};
+ testCase test_case_out = {false, type, (Utils::Shader::STAGES)m_stage};
+
+ if (Utils::Shader::VERTEX != m_stage)
+ {
+ m_test_cases.push_back(test_case_in);
+ }
+
+ if (Utils::Shader::FRAGMENT != m_stage)
+ {
+ m_test_cases.push_back(test_case_out);
+ }
+}
+
+/** Constructor
+ *
+ * @param context Test framework context
+ **/
+VaryingComponentsTest::VaryingComponentsTest(deqp::Context &context,
+ COMPONENTS_LAYOUT layout,
+ Utils::Type::TYPES type)
+ : VaryingLocationsTest(context,
+ "varying_components",
+ "Test verifies that input and output components are respected"),
+ m_layout(layout),
+ m_type(type)
+{
+ std::string name = ("varying_components_");
+ name.append(getComponentsLayoutName(m_layout));
+ name.append("_");
+ name.append(getTypesName(type));
+
+ VaryingLocationsTest::m_name = name.c_str();
+}
+
+/** 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,
+ COMPONENTS_LAYOUT layout,
+ Utils::Type::TYPES type)
+ : VaryingLocationsTest(context, test_name, test_description), m_layout(layout), m_type(type)
+{
+ std::string name = ("varying_components_");
+ name.append(getComponentsLayoutName(m_layout));
+ name.append("_");
+ name.append(getTypesName(type));
+
+ VaryingLocationsTest::m_name = name.c_str();
+}
+
+/** 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(m_layout, m_type));
+}
+
+std::string VaryingComponentsTest::getComponentsLayoutName(COMPONENTS_LAYOUT layout)
+{
+ switch (layout)
+ {
+ case G64VEC2:
+ return "g64vec2";
+ case G64SCALAR_G64SCALAR:
+ return "g64scalar_g64scalar";
+ case GVEC4:
+ return "gvec4";
+ case SCALAR_GVEC3:
+ return "scalar_gvec3";
+ case GVEC3_SCALAR:
+ return "gvec3_scalar";
+ case GVEC2_GVEC2:
+ return "gvec2_gvec2";
+ case GVEC2_SCALAR_SCALAR:
+ return "gvec2_scalar_scalar";
+ case SCALAR_GVEC2_SCALAR:
+ return "scalar_gvec2_scalar";
+ case SCALAR_SCALAR_GVEC2:
+ return "scalar_scalar_gvec2";
+ case SCALAR_SCALAR_SCALAR_SCALAR:
+ return "scalar_scalar_scalar_scalar";
+ default:
+ return "default";
+ }
+}
+
+std::string VaryingComponentsTest::getTypesName(Utils::Type::TYPES type)
+{
+ switch (type)
+ {
+ case Utils::Type::Double:
+ return "double";
+ case Utils::Type::Float:
+ return "float";
+ case Utils::Type::Int:
+ return "int";
+ case Utils::Type::Uint:
+ return "uint";
+ default:
+ return "default";
+ }
+}
+
+/** 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,
+ COMPONENTS_LAYOUT layout,
+ Utils::Type::TYPES type)
+ : VaryingComponentsTest(
+ context,
+ "varying_array_components",
+ "Test verifies that input and output components are respected for arrays",
+ layout,
+ type)
+{
+ std::string name = ("varying_array_components_");
+ name.append(getComponentsLayoutName(m_layout));
+ name.append("_");
+ name.append(getTypesName(type));
+
+ VaryingLocationsTest::m_name = name.c_str();
+}
+
+/** 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,
+ GLuint type)
+ : 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"),
+ m_type(type)
+{
+ std::string name = ("varying_invalid_value_component_");
+ name.append(getTypeName(type));
+
+ NegativeTestBase::m_name = name.c_str();
+}
+
+/** 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 Utils::Type &type = getType(m_type);
+ const std::vector<GLuint> &valid_components = type.GetValidComponents();
+
+ 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(),
+ std::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, GLuint type)
+ : NegativeTestBase(
+ context,
+ "varying_exceeding_components",
+ "Test verifies that compiler reports error when component qualifier exceeds limits"),
+ m_type(type)
+{
+ std::string name = ("varying_exceeding_components_");
+ name.append(getTypeName(type));
+
+ NegativeTestBase::m_name = name.c_str();
+}
+
+/** 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 Utils::Type &type = getType(m_type);
+
+ 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,
+ GLuint type)
+ : NegativeTestBase(context,
+ "varying_component_without_location",
+ "Test verifies that compiler reports error when component qualifier is used "
+ "without location"),
+ m_type(type)
+{
+ std::string name = ("varying_component_without_location_");
+ name.append(getTypeName(type));
+
+ NegativeTestBase::m_name = name.c_str();
+}
+
+/** 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 Utils::Type &type = getType(m_type);
+ const std::vector<GLuint> &valid_components = type.GetValidComponents();
+
+ 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,
+ GLuint type,
+ GLuint stage)
+ : NegativeTestBase(context,
+ "varying_component_of_invalid_type",
+ "Test verifies that compiler reports error when component qualifier is used "
+ "for invalid type"),
+ m_type(type),
+ m_stage(stage)
+{
+ std::string name = ("varying_component_of_invalid_type_");
+ name.append(getTypeName(type));
+ name.append("_");
+ name.append(EnhancedLayouts::Utils::Shader::GetStageName(
+ (EnhancedLayouts::Utils::Shader::STAGES)stage));
+
+ NegativeTestBase::m_name = name.c_str();
+}
+
+/** 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 Utils::Type &type = getType(m_type);
+ const std::vector<GLuint> &valid_components = type.GetValidComponents();
+
+ /* matrices */
+ if (1 != type.m_n_columns)
+ {
+ testCase test_case_in_arr = {MATRIX, 0, true, true, (Utils::Shader::STAGES)m_stage, type};
+ testCase test_case_in_one = {MATRIX, 0, false, true, (Utils::Shader::STAGES)m_stage, type};
+ testCase test_case_out_arr = {MATRIX, 0, true, false, (Utils::Shader::STAGES)m_stage, type};
+ testCase test_case_out_one = {MATRIX, 0, false, false, (Utils::Shader::STAGES)m_stage,
+ type};
+
+ m_test_cases.push_back(test_case_in_arr);
+ m_test_cases.push_back(test_case_in_one);
+
+ if (Utils::Shader::FRAGMENT != m_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)m_stage,
+ type};
+ testCase test_case_in_one = {DVEC3_DVEC4, 0, false, true, (Utils::Shader::STAGES)m_stage,
+ type};
+ testCase test_case_out_arr = {DVEC3_DVEC4, 0, true, false, (Utils::Shader::STAGES)m_stage,
+ type};
+ testCase test_case_out_one = {DVEC3_DVEC4, 0, false, false, (Utils::Shader::STAGES)m_stage,
+ type};
+
+ m_test_cases.push_back(test_case_in_arr);
+ m_test_cases.push_back(test_case_in_one);
+
+ if (Utils::Shader::FRAGMENT != m_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)m_stage, type};
+ testCase test_case_in_one = {(CASES)c, valid_components.back(), false,
+ true, (Utils::Shader::STAGES)m_stage, type};
+ testCase test_case_out_arr = {(CASES)c, valid_components.back(), true,
+ false, (Utils::Shader::STAGES)m_stage, type};
+ testCase test_case_out_one = {(CASES)c, valid_components.back(), false,
+ false, (Utils::Shader::STAGES)m_stage, type};
+
+ if (Utils::Shader::VERTEX != m_stage)
+ {
+ m_test_cases.push_back(test_case_in_arr);
+ m_test_cases.push_back(test_case_in_one);
+ }
+
+ if (Utils::Shader::FRAGMENT != m_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, GLuint type)
+ : NegativeTestBase(context,
+ "input_component_aliasing",
+ "Test verifies that compiler reports component aliasing as error"),
+ m_type(type)
+{
+ std::string name = ("input_component_aliasing");
+ name.append(getTypeName(type));
+
+ NegativeTestBase::m_name = name.c_str();
+}
+
+/** 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 Utils::Type &type = getType(m_type);
+ const std::vector<GLuint> &valid_components = type.GetValidComponents();
+
+ 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, GLuint type)
+ : NegativeTestBase(context,
+ "output_component_aliasing",
+ "Test verifies that compiler reports component aliasing as error"),
+ m_type(type)
+{
+ std::string name = ("output_component_aliasing_");
+ name.append(getTypeName(type));
+
+ NegativeTestBase::m_name = name.c_str();
+}
+
+/** 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 Utils::Type &type = getType(m_type);
+ const std::vector<GLuint> &valid_components = type.GetValidComponents();
+
+ 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,
+ GLuint type_gohan,
+ GLuint type_goten)
+ : NegativeTestBase(context,
+ "varying_location_aliasing_with_mixed_types",
+ "Test verifies that compiler reports error when float/int types are mixed "
+ "at one location"),
+ m_type_gohan(type_gohan),
+ m_type_goten(type_goten)
+{
+ std::string name = ("varying_location_aliasing_with_mixed_types_");
+ name.append(getTypeName(type_gohan));
+ name.append("_");
+ name.append(getTypeName(type_goten));
+
+ NegativeTestBase::m_name = name.c_str();
+}
+
+/** 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 Utils::Type &type_gohan = getType(m_type_gohan);
+ const std::vector<GLuint> &valid_components_gohan = type_gohan.GetValidComponents();
+
+ const Utils::Type &type_goten = getType(m_type_goten);
+ const std::vector<GLuint> &valid_components_goten = type_goten.GetValidComponents();
+
+ 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,
+ GLuint type_gohan,
+ GLuint type_goten)
+ : NegativeTestBase(context,
+ "varying_location_aliasing_with_mixed_interpolation",
+ "Test verifies that compiler reports error when interpolation qualifiers "
+ "are mixed at one location"),
+ m_type_gohan(type_gohan),
+ m_type_goten(type_goten)
+{
+ std::string name = ("varying_location_aliasing_with_mixed_interpolation_");
+ name.append(getTypeName(m_type_gohan));
+ name.append("_");
+ name.append(getTypeName(m_type_goten));
+
+ NegativeTestBase::m_name = name.c_str();
+}
+
+/** 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 Utils::Type &type_gohan = getType(m_type_gohan);
+ const std::vector<GLuint> &valid_components_gohan = type_gohan.GetValidComponents();
+
+ const GLuint gohan = valid_components_gohan.front();
+
+ const Utils::Type &type_goten = getType(m_type_goten);
+ const std::vector<GLuint> &valid_components_goten = type_goten.GetValidComponents();
+
+ const GLuint goten = valid_components_goten.back();
+
+ 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,
+ GLuint type_gohan,
+ GLuint type_goten)
+ : NegativeTestBase(context,
+ "varying_location_aliasing_with_mixed_auxiliary_storage",
+ "Test verifies that compiler reports error when auxiliary storage "
+ "qualifiers are mixed at one location"),
+ m_type_gohan(type_gohan),
+ m_type_goten(type_goten)
+{
+ std::string name = ("varying_location_aliasing_with_mixed_auxiliary_storage_");
+ name.append(getTypeName(m_type_gohan));
+ name.append("_");
+ name.append(getTypeName(m_type_goten));
+
+ NegativeTestBase::m_name = name.c_str();
+}
+
+/** 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 Utils::Type &type_gohan = getType(m_type_gohan);
+ const std::vector<GLuint> &valid_components_gohan = type_gohan.GetValidComponents();
+
+ const GLuint gohan = valid_components_gohan.front();
+
+ const Utils::Type &type_goten = getType(m_type_goten);
+ const std::vector<GLuint> &valid_components_goten = type_goten.GetValidComponents();
+
+ const GLuint goten = valid_components_goten.back();
+
+ 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),
+ m_goku_location(0),
+ m_gohan_location(0),
+ m_chichi_location(0)
+{}
+
+/** 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, GLuint qualifier, GLuint stage)
+ : NegativeTestBase(
+ context,
+ "xfb_input",
+ "Test verifies that compiler reports error when xfb qualifiers are used with input"),
+ m_qualifier(qualifier),
+ m_stage(stage)
+{
+ std::string name = ("xfb_input_");
+ name.append(EnhancedLayouts::XFBInputTest::getQualifierName(
+ (EnhancedLayouts::XFBInputTest::QUALIFIERS)qualifier));
+ name.append("_");
+ name.append(EnhancedLayouts::Utils::Shader::GetStageName(
+ (EnhancedLayouts::Utils::Shader::STAGES)stage));
+
+ NegativeTestBase::m_name = name.c_str();
+}
+
+/** 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()
+{
+ testCase test_case = {(QUALIFIERS)m_qualifier, (Utils::Shader::STAGES)m_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 *XFBInputTest::getQualifierName(QUALIFIERS qualifier)
+{
+ const GLchar *name = "";
+
+ switch (qualifier)
+ {
+ case BUFFER:
+ name = "xtb_buffer";
+ break;
+ case STRIDE:
+ name = "xtb_stride";
+ break;
+ case OFFSET:
+ name = "xtb_offset";
+ break;
+ default:
+ TCU_FAIL("Invalid enum");
+ }
+
+ return name;
+}
+
+/* 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, GLuint constant, GLuint stage)
+ : NegativeTestBase(
+ context,
+ "xfb_too_small_stride",
+ "Test verifies that compiler reports error when xfb_stride sets not enough space"),
+ m_constant(constant),
+ m_stage(stage)
+{
+ std::string name = ("xfb_too_small_stride_");
+ name.append(getCaseEnumName(m_constant));
+ name.append("_");
+ name.append(EnhancedLayouts::Utils::Shader::GetStageName(
+ (EnhancedLayouts::Utils::Shader::STAGES)stage));
+
+ NegativeTestBase::m_name = name.c_str();
+}
+
+/** 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");
+ }
+ }
+
+ 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();
+}
+
+std::string XFBTooSmallStrideTest::getCaseEnumName(glw::GLuint case_index)
+{
+ std::string case_name("case_max");
+ switch (case_index)
+ {
+ case 0:
+ case_name = "offset";
+ break;
+ case 1:
+ case_name = "stride";
+ break;
+ case 2:
+ case_name = "block";
+ break;
+ case 3:
+ case_name = "array";
+ break;
+ default:
+ case_name = "case_max";
+ break;
+ }
+ return case_name;
+}
+
+/** 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()
+{
+ testCase test_case = {(CASES)m_constant, (Utils::Shader::STAGES)m_stage};
+
+ m_test_cases.push_back(test_case);
+}
+
+/** Constructor
+ *
+ * @param context Test framework context
+ **/
+XFBVariableStrideTest::XFBVariableStrideTest(deqp::Context &context,
+ glw::GLuint type,
+ glw::GLuint stage,
+ glw::GLuint constant)
+ : NegativeTestBase(context,
+ "xfb_variable_stride",
+ "Test verifies that stride qualifier is respected"),
+ m_type(type),
+ m_stage(stage),
+ m_constant(constant)
+{
+ std::string name = ("xfb_variable_stride_");
+ name.append(getTypeName(m_type));
+ name.append("_");
+ name.append(EnhancedLayouts::Utils::Shader::GetStageName(
+ (EnhancedLayouts::Utils::Shader::STAGES)m_stage));
+ name.append("_");
+ name.append(getCaseEnumName(m_constant));
+
+ NegativeTestBase::m_name = name.c_str();
+}
+
+/** 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");
+ }
+ }
+
+ 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();
+}
+
+std::string XFBVariableStrideTest::getCaseEnumName(glw::GLuint case_index)
+{
+ std::string case_name("case_max");
+ switch (case_index)
+ {
+ case 0:
+ case_name = "valid";
+ break;
+ case 1:
+ case_name = "invalid";
+ break;
+ default:
+ case_name = "case_max";
+ break;
+ }
+ return case_name;
+}
+
+/** 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 Utils::Type &type = getType(m_type);
+
+ testCase test_case = {static_cast<CASES>(m_constant),
+ static_cast<Utils::Shader::STAGES>(m_stage), type};
+
+ m_test_cases.push_back(test_case);
+}
+
+/** Constructor
+ *
+ * @param context Test framework context
+ **/
+XFBBlockStrideTest::XFBBlockStrideTest(deqp::Context &context, GLuint stage)
+ : TestBase(context,
+ "xfb_block_stride",
+ "Test verifies that stride qualifier is respected for blocks"),
+ m_stage(stage)
+{
+ std::string name = ("xfb_block_stride_");
+ name.append(EnhancedLayouts::Utils::Shader::GetStageName(
+ (EnhancedLayouts::Utils::Shader::STAGES)m_stage));
+
+ TestBase::m_name = name.c_str();
+}
+
+/** 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");
+ }
+ }
+
+ 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()
+{
+ m_test_cases.push_back((Utils::Shader::STAGES)m_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,
+ GLuint constant,
+ GLuint stage)
+ : NegativeTestBase(
+ context,
+ "xfb_duplicated_stride",
+ "Test verifies that compiler reports error when conflicting stride qualifiers are used"),
+ m_constant(constant),
+ m_stage(stage)
+{
+ std::string name = ("xfb_duplicated_stride_");
+ name.append(getCaseEnumName(m_constant));
+ name.append("_");
+ name.append(EnhancedLayouts::Utils::Shader::GetStageName(
+ (EnhancedLayouts::Utils::Shader::STAGES)stage));
+
+ NegativeTestBase::m_name = name.c_str();
+}
+
+/** 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");
+ }
+ }
+
+ 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();
+}
+
+std::string XFBDuplicatedStrideTest::getCaseEnumName(GLuint test_case_index)
+{
+ std::string name = "case_max";
+
+ switch (test_case_index)
+ {
+ case 0:
+ name = "valid";
+ break;
+ case 1:
+ name = "invalid";
+ break;
+ default:
+ name = "case_max";
+ break;
+ }
+
+ return name;
+}
+
+/** 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()
+{
+ testCase test_case = {(CASES)m_constant, (Utils::Shader::STAGES)m_stage};
+
+ m_test_cases.push_back(test_case);
+}
+
+/** Constructor
+ *
+ * @param context Test framework context
+ **/
+XFBGetProgramResourceAPITest::XFBGetProgramResourceAPITest(deqp::Context &context, GLuint type)
+ : TestBase(context,
+ "xfb_get_program_resource_api",
+ "Test verifies that get program resource reports correct results for XFB"),
+ m_type(type)
+{
+ std::string name = ("xfb_get_program_resource_api_");
+ name.append(getTypeName(type));
+
+ TestBase::m_name = name.c_str();
+}
+
+/** 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();
+ 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);
+
+ const Utils::Type &type = getType(m_type);
+ bool requirment = 4 * type.GetNumComponents() + 4 > (GLuint)max_varyings;
+
+ // 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;
+ */
+ for (GLuint stage = 0; stage < Utils::Shader::STAGE_MAX; ++stage)
+ {
+ if (requirment)
+ {
+ continue;
+ }
+ /*
+ 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 padded_type_size = type.GetBaseAlignment(false) * type.m_n_columns;
+ const GLuint type_size_pck = static_cast<GLuint>(vegeta_data_pck.size());
+
+ /* Uniform data */
+ uniform.m_initial_data.resize(3 * padded_type_size);
+ memcpy(&uniform.m_initial_data[0] + 0, &vegeta_data[0], type_size);
+ memcpy(&uniform.m_initial_data[0] + padded_type_size, &trunks_data[0], type_size);
+ memcpy(&uniform.m_initial_data[0] + 2 * padded_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,
+ GLuint constant,
+ GLuint stage)
+ : NegativeTestBase(
+ context,
+ "xfb_exceed_buffer_limit",
+ "Test verifies that compiler reports error when xfb_buffer qualifier exceeds limit"),
+ m_constant(constant),
+ m_stage(stage)
+{
+ std::string name = ("xfb_exceed_buffer_limit_");
+ name.append(getCaseEnumName(m_constant));
+ name.append("_");
+ name.append(EnhancedLayouts::Utils::Shader::GetStageName(
+ (EnhancedLayouts::Utils::Shader::STAGES)stage));
+
+ NegativeTestBase::m_name = name.c_str();
+}
+
+/** 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");
+ }
+ }
+
+ 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();
+}
+
+std::string XFBExceedBufferLimitTest::getCaseEnumName(glw::GLuint test_case_index)
+{
+ std::string name = "case_max";
+
+ switch (test_case_index)
+ {
+ case 0:
+ name = "block";
+ break;
+ case 1:
+ name = "global";
+ break;
+ case 2:
+ name = "vector";
+ break;
+ default:
+ name = "case_max";
+ break;
+ }
+
+ return name;
+}
+
+/** 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()
+{
+ testCase test_case = {(CASES)m_constant, (Utils::Shader::STAGES)m_stage};
+
+ m_test_cases.push_back(test_case);
+}
+
+/** Constructor
+ *
+ * @param context Test framework context
+ **/
+XFBExceedOffsetLimitTest::XFBExceedOffsetLimitTest(deqp::Context &context,
+ GLuint constant,
+ GLuint stage)
+ : NegativeTestBase(
+ context,
+ "xfb_exceed_offset_limit",
+ "Test verifies that compiler reports error when xfb_offset qualifier exceeds limit"),
+ m_constant(constant),
+ m_stage(stage)
+{
+ std::string name = ("xfb_exceed_offset_limit_");
+ name.append(getCaseEnumName(m_constant));
+ name.append("_");
+ name.append(EnhancedLayouts::Utils::Shader::GetStageName(
+ (EnhancedLayouts::Utils::Shader::STAGES)stage));
+
+ NegativeTestBase::m_name = name.c_str();
+}
+
+/** 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");
+ }
+ }
+
+ 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();
+}
+
+std::string XFBExceedOffsetLimitTest::getCaseEnumName(glw::GLuint test_case_index)
+{
+ std::string name = "case_max";
+
+ switch (test_case_index)
+ {
+ case 0:
+ name = "block";
+ break;
+ case 1:
+ name = "global";
+ break;
+ case 2:
+ name = "vector";
+ break;
+ default:
+ name = "case_max";
+ break;
+ }
+
+ return name;
+}
+
+/** 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()
+{
+ testCase test_case = {(CASES)m_constant, (Utils::Shader::STAGES)m_stage};
+
+ m_test_cases.push_back(test_case);
+}
+
+/** Constructor
+ *
+ * @param context Test context
+ **/
+XFBGlobalBufferTest::XFBGlobalBufferTest(deqp::Context &context, GLuint type)
+ : BufferTestBase(context,
+ "xfb_global_buffer",
+ "Test verifies that global xfb_buffer qualifier is respected"),
+ m_type(type)
+{
+ std::string name = ("xfb_global_buffer_");
+ name.append(getTypeName(m_type));
+
+ BufferTestBase::m_name = name.c_str();
+}
+
+/** 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 padded_type_size = type.GetBaseAlignment(false) * type.m_n_columns;
+ const GLuint type_size_pck = static_cast<GLuint>(chichi_data_pck.size());
+
+ /* Uniform data */
+ uniform.m_initial_data.resize(6 * padded_type_size);
+ memcpy(&uniform.m_initial_data[0] + 0, &chichi_data[0], type_size);
+ memcpy(&uniform.m_initial_data[0] + padded_type_size, &bulma_data[0], type_size);
+ memcpy(&uniform.m_initial_data[0] + 2 * padded_type_size, &trunks_data[0], type_size);
+ memcpy(&uniform.m_initial_data[0] + 3 * padded_type_size, &bra_data[0], type_size);
+ memcpy(&uniform.m_initial_data[0] + 4 * padded_type_size, &gohan_data[0], type_size);
+ memcpy(&uniform.m_initial_data[0] + 5 * padded_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");
+ }
+ }
+
+ 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()
+{
+ const Utils::Type &type = getType(m_type);
+ 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, glw::GLuint type, glw::GLuint stage)
+ : BufferTestBase(context,
+ "xfb_stride",
+ "Test verifies that correct stride is used for all types"),
+ m_type(type),
+ m_stage(stage)
+{
+ std::string name = ("xfb_stride_");
+ name.append(getTypeName(type));
+ name.append("_");
+ name.append(EnhancedLayouts::Utils::Shader::GetStageName(
+ (EnhancedLayouts::Utils::Shader::STAGES)stage));
+
+ BufferTestBase::m_name = name.c_str();
+}
+
+/** 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");
+ }
+
+ /* */
+ 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 Utils::Type &type = getType(m_type);
+
+ testCase test_case = {(Utils::Shader::STAGES)m_stage, type};
+
+ m_test_cases.push_back(test_case);
+}
+
+/** Constructor
+ *
+ * @param context Test framework context
+ **/
+XFBBlockMemberBufferTest::XFBBlockMemberBufferTest(deqp::Context &context, GLuint stage)
+ : NegativeTestBase(context,
+ "xfb_block_member_buffer",
+ "Test verifies that compiler reports error when block member has different "
+ "xfb_buffer qualifier than buffer"),
+ m_stage(stage)
+{
+ std::string name = ("xfb_block_member_buffer_");
+ name.append(EnhancedLayouts::Utils::Shader::GetStageName(
+ (EnhancedLayouts::Utils::Shader::STAGES)stage));
+
+ NegativeTestBase::m_name = name.c_str();
+}
+
+/** 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");
+ }
+ }
+
+ 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()
+{
+ testCase test_case = {(Utils::Shader::STAGES)m_stage};
+
+ m_test_cases.push_back(test_case);
+}
+
+/** Constructor
+ *
+ * @param context Test framework context
+ **/
+XFBOutputOverlappingTest::XFBOutputOverlappingTest(deqp::Context &context,
+ GLuint type,
+ GLuint stage)
+ : NegativeTestBase(
+ context,
+ "xfb_output_overlapping",
+ "Test verifies that compiler reports error when two xfb qualified outputs overlap"),
+ m_type(type),
+ m_stage(stage)
+{
+ std::string name = ("xfb_output_overlapping_");
+ name.append(getTypeName(type));
+ name.append("_");
+ name.append(EnhancedLayouts::Utils::Shader::GetStageName(
+ (EnhancedLayouts::Utils::Shader::STAGES)stage));
+
+ NegativeTestBase::m_name = name.c_str();
+}
+
+/** 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");
+ }
+ }
+
+ 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 Utils::Type &type = getType(m_type);
+ 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.
+ */
+
+ testCase test_case = {basic_type_size /* offset */, (Utils::Shader::STAGES)m_stage, type};
+
+ m_test_cases.push_back(test_case);
+}
+
+/** Constructor
+ *
+ * @param context Test framework context
+ **/
+XFBInvalidOffsetAlignmentTest::XFBInvalidOffsetAlignmentTest(deqp::Context &context,
+ GLuint type,
+ GLuint stage)
+ : NegativeTestBase(
+ context,
+ "xfb_invalid_offset_alignment",
+ "Test verifies that compiler reports error when xfb_offset has invalid alignment"),
+ m_type(type),
+ m_stage(stage)
+{
+ std::string name = ("xfb_invalid_offset_alignment_");
+ name.append(getTypeName(type));
+ name.append("_");
+ name.append(EnhancedLayouts::Utils::Shader::GetStageName(
+ (EnhancedLayouts::Utils::Shader::STAGES)stage));
+
+ NegativeTestBase::m_name = name.c_str();
+}
+
+/** 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");
+ }
+ }
+
+ 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 Utils::Type &type = getType(m_type);
+ const GLuint basic_type_size = Utils::Type::GetTypeSize(type.m_basic_type);
+
+ for (GLuint offset = basic_type_size + 1; offset < 2 * basic_type_size; ++offset)
+ {
+ testCase test_case = {offset, (Utils::Shader::STAGES)m_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");
+ }
+
+ /* */
+ 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");
+ }
+
+ /* */
+ 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");
+ }
+
+ /* */
+ 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");
+ }
+
+ /* */
+ 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, GLuint stage)
+ : NegativeTestBase(context,
+ "xfb_capture_unsized_array",
+ "Test verifies that compiler reports error when unsized array is qualified "
+ "with xfb_offset"),
+ m_stage(stage)
+{
+ std::string name = ("xfb_capture_unsized_array_");
+ name.append(EnhancedLayouts::Utils::Shader::GetStageName(
+ (EnhancedLayouts::Utils::Shader::STAGES)stage));
+
+ NegativeTestBase::m_name = name.c_str();
+}
+
+/** 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");
+ }
+ }
+
+ 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()
+{
+ testCase test_case = {(Utils::Shader::STAGES)m_stage};
+
+ m_test_cases.push_back(test_case);
+}
+
+/** Constructor
+ *
+ * @param context Test context
+ **/
+XFBExplicitLocationTest::XFBExplicitLocationTest(deqp::Context &context, GLuint type, GLuint stage)
+ : BufferTestBase(
+ context,
+ "xfb_explicit_location",
+ "Test verifies that explicit location on matrices and arrays does not impact xfb output"),
+ m_type(type),
+ m_stage(stage)
+{
+ std::string name = ("xfb_explicit_location_");
+ name.append(getTypeName(m_type));
+ name.append("_");
+ name.append(EnhancedLayouts::Utils::Shader::GetStageName(
+ (EnhancedLayouts::Utils::Shader::STAGES)stage));
+
+ BufferTestBase::m_name = name.c_str();
+}
+
+/** Execute drawArrays for single vertex
+ *
+ * @param test_case_index
+ *
+ * @return true
+ **/
+bool XFBExplicitLocationTest::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 XFBExplicitLocationTest::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;
+ std::vector<GLubyte> uniform_data;
+
+ for (GLuint i = 0; i < std::max(test_case.m_array_size, 1u); i++)
+ {
+ const std::vector<GLubyte> &type_uniform_data = type.GenerateData();
+ /**
+ * Rule 4 of Section 7.6.2.2:
+ *
+ * If the member is an array of scalars or vectors, the base alignment and array stride
+ * are set to match the base alignment of a single array element, according to rules (1),
+ * (2), and (3), and rounded up to the base alignment of a vec4.
+ */
+ uniform_data.resize(Utils::align((glw::GLuint)uniform_data.size(), 16));
+ uniform_data.insert(uniform_data.end(), type_uniform_data.begin(), type_uniform_data.end());
+ }
+
+ Utils::s_rand = rand_start;
+ std::vector<GLubyte> xfb_data;
+
+ for (GLuint i = 0; i < std::max(test_case.m_array_size, 1u); i++)
+ {
+ const std::vector<GLubyte> &type_xfb_data = type.GenerateDataPacked();
+ xfb_data.insert(xfb_data.end(), type_xfb_data.begin(), type_xfb_data.end());
+ }
+
+ 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, 0);
+ xfb.m_expected_data.resize(xfb_data_size);
+
+ 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 XFBExplicitLocationTest::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";
+
+ 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 = "";
+ 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 XFBExplicitLocationTest::getShaderInterface(GLuint test_case_index,
+ Utils::Shader::STAGES stage,
+ std::string &out_interface)
+{
+ static const GLchar *vs_tes_gs =
+ "layout (location = 0, xfb_offset = 0) FLAT out TYPE gokuARRAY;\n"
+ "\n"
+ "layout(std140, binding = 0) uniform Goku {\n"
+ " TYPE uni_gokuARRAY;\n"
+ "};\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 = "";
+ 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";
+ }
+
+ /* Array size */
+ if (0 == test_case.m_array_size)
+ {
+ Utils::replaceAllTokens("ARRAY", "", out_interface);
+ }
+ else
+ {
+ char buffer[16];
+ sprintf(buffer, "[%d]", test_case.m_array_size);
+
+ Utils::replaceAllTokens("ARRAY", buffer, out_interface);
+ }
+
+ 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 XFBExplicitLocationTest::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");
+ }
+
+ /* */
+ return source;
+}
+
+/** Get name of test case
+ *
+ * @param test_case_index Index of test case
+ *
+ * @return Name of tested stage
+ **/
+std::string XFBExplicitLocationTest::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 XFBExplicitLocationTest::getTestCaseNumber()
+{
+ return static_cast<GLuint>(m_test_cases.size());
+}
+
+/** Prepare all test cases
+ *
+ **/
+void XFBExplicitLocationTest::testInit()
+{
+ const Functions &gl = m_context.getRenderContext().getFunctions();
+ GLint max_xfb_int;
+
+ gl.getIntegerv(GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS, &max_xfb_int);
+ GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
+
+ const Utils::Type &type = getType(m_type);
+
+ if (type.m_n_columns > 1)
+ {
+ testCase test_case = {(Utils::Shader::STAGES)m_stage, type, 0};
+
+ m_test_cases.push_back(test_case);
+ }
+
+ for (GLuint array_size = 3; array_size > 1; array_size--)
+ {
+ if (type.GetNumComponents() * array_size <= GLuint(max_xfb_int))
+ {
+ testCase test_case = {(Utils::Shader::STAGES)m_stage, type, array_size};
+
+ m_test_cases.push_back(test_case);
+
+ break;
+ }
+ }
+}
+
+/** Constructor
+ *
+ * @param context Test context
+ **/
+XFBExplicitLocationStructTest::XFBExplicitLocationStructTest(deqp::Context &context, GLuint stage)
+ : BufferTestBase(context,
+ "xfb_struct_explicit_location",
+ "Test verifies that explicit location on structs does not impact xfb output"),
+ m_stage(stage)
+{
+ std::string name = ("xfb_struct_explicit_location_");
+ name.append(EnhancedLayouts::Utils::Shader::GetStageName(
+ (EnhancedLayouts::Utils::Shader::STAGES)m_stage));
+
+ BufferTestBase::m_name = name.c_str();
+}
+
+/** Execute drawArrays for single vertex
+ *
+ * @param test_case_index
+ *
+ * @return true
+ **/
+bool XFBExplicitLocationStructTest::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 XFBExplicitLocationStructTest::getBufferDescriptors(GLuint test_case_index,
+ bufferDescriptor::Vector &out_descriptors)
+{
+ const testCase &test_case = m_test_cases[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 rand_start = Utils::s_rand;
+ std::vector<GLubyte> uniform_data;
+ GLuint max_aligment = 1;
+
+ for (const testType &type : test_case.m_types)
+ {
+ GLuint base_aligment = type.m_type.GetBaseAlignment(false);
+ if (type.m_array_size > 0)
+ {
+ /**
+ * Rule 4 of Section 7.6.2.2:
+ *
+ * If the member is an array of scalars or vectors, the base alignment and array stride
+ * are set to match the base alignment of a single array element, according to rules
+ * (1), (2), and (3), and rounded up to the base alignment of a vec4.
+ */
+ base_aligment = Utils::align(base_aligment, Utils::Type::vec4.GetBaseAlignment(false));
+ }
+
+ max_aligment = std::max(base_aligment, max_aligment);
+
+ uniform_data.resize(Utils::align((glw::GLuint)uniform_data.size(), base_aligment), 0);
+
+ for (GLuint i = 0; i < std::max(type.m_array_size, 1u); i++)
+ {
+ const std::vector<GLubyte> &type_uniform_data = type.m_type.GenerateData();
+ uniform_data.insert(uniform_data.end(), type_uniform_data.begin(),
+ type_uniform_data.end());
+
+ if (type.m_array_size > 0)
+ {
+ uniform_data.resize(Utils::align((glw::GLuint)uniform_data.size(), base_aligment),
+ 0);
+ }
+ }
+ }
+
+ const GLuint struct_aligment =
+ Utils::align(max_aligment, Utils::Type::vec4.GetBaseAlignment(false));
+
+ if (test_case.m_nested_struct)
+ {
+ uniform_data.resize(Utils::align((glw::GLuint)uniform_data.size(), struct_aligment), 0);
+
+ const GLuint old_size = (glw::GLuint)uniform_data.size();
+ uniform_data.resize(2 * old_size);
+ std::copy_n(uniform_data.begin(), old_size, uniform_data.begin() + old_size);
+ }
+
+ uniform_data.resize(Utils::align((glw::GLuint)uniform_data.size(), struct_aligment), 0);
+
+ Utils::s_rand = rand_start;
+ std::vector<GLubyte> xfb_data;
+
+ GLuint max_type_size = 1;
+ for (const testType &type : test_case.m_types)
+ {
+ const GLuint basic_type_size = Utils::Type::GetTypeSize(type.m_type.m_basic_type);
+ max_type_size = std::max(max_type_size, basic_type_size);
+
+ /* Align per current type's aligment requirements */
+ xfb_data.resize(Utils::align((glw::GLuint)xfb_data.size(), basic_type_size), 0);
+
+ for (GLuint i = 0; i < std::max(type.m_array_size, 1u); i++)
+ {
+ const std::vector<GLubyte> &type_xfb_data = type.m_type.GenerateDataPacked();
+ xfb_data.insert(xfb_data.end(), type_xfb_data.begin(), type_xfb_data.end());
+ }
+ }
+
+ if (test_case.m_nested_struct)
+ {
+ /* Struct has aligment requirement equal to largest requirement of its members */
+ xfb_data.resize(Utils::align((glw::GLuint)xfb_data.size(), max_type_size), 0);
+
+ const GLuint old_size = (glw::GLuint)xfb_data.size();
+ xfb_data.resize(2 * old_size);
+ std::copy_n(xfb_data.begin(), old_size, xfb_data.begin() + old_size);
+ }
+
+ xfb_data.resize(Utils::align((glw::GLuint)xfb_data.size(), max_type_size), 0);
+
+ const GLuint uni_type_size = static_cast<GLuint>(uniform_data.size());
+ const GLuint xfb_type_size = static_cast<GLuint>(xfb_data.size());
+
+ /* Do not exceed the minimum value of MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS */
+ DE_ASSERT(xfb_type_size <= 64 * sizeof(GLuint));
+
+ /*
+ 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, 0);
+ xfb.m_expected_data.resize(xfb_data_size);
+
+ 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 XFBExplicitLocationStructTest::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 *vs_tes_gs_nested =
+ " goku.inner_struct_a = uni_goku;\n"
+ " goku.inner_struct_b = uni_goku;\n";
+
+ const GLchar *assignments = "";
+
+ if (test_case.m_stage == stage)
+ {
+ switch (stage)
+ {
+ case Utils::Shader::GEOMETRY:
+ case Utils::Shader::TESS_EVAL:
+ case Utils::Shader::VERTEX:
+ if (test_case.m_nested_struct)
+ {
+ assignments = vs_tes_gs_nested;
+ }
+ else
+ {
+ assignments = vs_tes_gs;
+ }
+ break;
+ default:
+ TCU_FAIL("Invalid enum");
+ }
+ }
+ else
+ {
+ switch (stage)
+ {
+ case Utils::Shader::FRAGMENT:
+ assignments = "";
+ 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;
+}
+
+/** Get interface of shader
+ *
+ * @param test_case_index Index of test case
+ * @param stage Shader stage
+ * @param out_interface Set to ""
+ **/
+void XFBExplicitLocationStructTest::getShaderInterface(GLuint test_case_index,
+ Utils::Shader::STAGES stage,
+ std::string &out_interface)
+{
+ static const GLchar *vs_tes_gs =
+ "struct TestStruct {\n"
+ "STRUCT_MEMBERS"
+ "};\n"
+ "layout (location = 0, xfb_offset = 0) flat out TestStruct goku;\n"
+ "\n"
+ "layout(std140, binding = 0) uniform Goku {\n"
+ " TestStruct uni_goku;\n"
+ "};\n";
+
+ static const GLchar *vs_tes_gs_nested =
+ "struct TestStruct {\n"
+ "STRUCT_MEMBERS"
+ "};\n"
+ "struct OuterStruct {\n"
+ " TestStruct inner_struct_a;\n"
+ " TestStruct inner_struct_b;\n"
+ "};\n"
+ "layout (location = 0, xfb_offset = 0) flat out OuterStruct goku;\n"
+ "\n"
+ "layout(std140, binding = 0) uniform Goku {\n"
+ " TestStruct uni_goku;\n"
+ "};\n";
+
+ const testCase &test_case = m_test_cases[test_case_index];
+ const GLchar *interface = "";
+
+ if (test_case.m_stage == stage)
+ {
+ switch (stage)
+ {
+ case Utils::Shader::GEOMETRY:
+ case Utils::Shader::TESS_EVAL:
+ case Utils::Shader::VERTEX:
+ if (test_case.m_nested_struct)
+ {
+ interface = vs_tes_gs_nested;
+ }
+ else
+ {
+ interface = vs_tes_gs;
+ }
+ break;
+ default:
+ TCU_FAIL("Invalid enum");
+ }
+ }
+ else
+ {
+ switch (stage)
+ {
+ case Utils::Shader::FRAGMENT:
+ interface = "";
+ 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;
+
+ std::stringstream stream;
+
+ char member_name = 'a';
+ for (const testType &type : test_case.m_types)
+ {
+ stream << " " << type.m_type.GetGLSLTypeName() << " " << member_name++;
+ if (type.m_array_size > 0)
+ {
+ stream << "[" << type.m_array_size << "]";
+ }
+ stream << ";\n";
+ }
+
+ Utils::replaceAllTokens("STRUCT_MEMBERS", stream.str().c_str(), out_interface);
+}
+
+/** Get source code of shader
+ *
+ * @param test_case_index Index of test case
+ * @param stage Shader stage
+ *
+ * @return Source
+ **/
+std::string XFBExplicitLocationStructTest::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");
+ }
+
+ /* */
+ return source;
+}
+
+/** Get name of test case
+ *
+ * @param test_case_index Index of test case
+ *
+ * @return Name of tested stage
+ **/
+std::string XFBExplicitLocationStructTest::getTestCaseName(glw::GLuint test_case_index)
+{
+ std::stringstream stream;
+ const testCase &test_case = m_test_cases[test_case_index];
+
+ stream << "Struct: { ";
+
+ for (const testType &type : test_case.m_types)
+ {
+ stream << type.m_type.GetGLSLTypeName() << "@" << type.m_array_size << ", ";
+ }
+
+ stream << "}, stage: " << Utils::Shader::GetStageName(test_case.m_stage);
+
+ return stream.str();
+}
+
+/** Returns number of test cases
+ *
+ * @return TEST_MAX
+ **/
+glw::GLuint XFBExplicitLocationStructTest::getTestCaseNumber()
+{
+ return static_cast<GLuint>(m_test_cases.size());
+}
+
+/** Prepare all test cases
+ *
+ **/
+void XFBExplicitLocationStructTest::testInit()
+{
+ const GLuint n_types = getTypesNumber();
+
+ for (GLuint i = 0; i < n_types; ++i)
+ {
+ const Utils::Type &type = getType(i);
+
+ m_test_cases.push_back(
+ testCase{(Utils::Shader::STAGES)m_stage, {{Utils::Type::_float, 0}, {type, 0}}, false});
+ }
+
+ for (bool is_nested_struct : {false, true})
+ {
+ m_test_cases.push_back(
+ testCase{(Utils::Shader::STAGES)m_stage,
+ {{Utils::Type::_double, 0}, {Utils::Type::dvec2, 0}, {Utils::Type::dmat3, 0}},
+ is_nested_struct});
+ m_test_cases.push_back(testCase{(Utils::Shader::STAGES)m_stage,
+ {{Utils::Type::_double, 0}, {Utils::Type::vec3, 0}},
+ is_nested_struct});
+ m_test_cases.push_back(testCase{(Utils::Shader::STAGES)m_stage,
+ {{Utils::Type::dvec3, 0}, {Utils::Type::mat4x3, 0}},
+ is_nested_struct});
+ m_test_cases.push_back(testCase{(Utils::Shader::STAGES)m_stage,
+ {{Utils::Type::_float, 0},
+ {Utils::Type::dvec3, 0},
+ {Utils::Type::_float, 0},
+ {Utils::Type::_double, 0}},
+ is_nested_struct});
+ m_test_cases.push_back(testCase{(Utils::Shader::STAGES)m_stage,
+ {{Utils::Type::vec2, 0},
+ {Utils::Type::dvec3, 0},
+ {Utils::Type::_float, 0},
+ {Utils::Type::_double, 0}},
+ is_nested_struct});
+ m_test_cases.push_back(testCase{(Utils::Shader::STAGES)m_stage,
+ {{Utils::Type::_double, 0},
+ {Utils::Type::_float, 0},
+ {Utils::Type::dvec2, 0},
+ {Utils::Type::vec3, 0}},
+ is_nested_struct});
+ m_test_cases.push_back(testCase{(Utils::Shader::STAGES)m_stage,
+ {{Utils::Type::dmat3x4, 0},
+ {Utils::Type::_double, 0},
+ {Utils::Type::_float, 0},
+ {Utils::Type::dvec2, 0}},
+ is_nested_struct});
+
+ m_test_cases.push_back(
+ testCase{(Utils::Shader::STAGES)m_stage,
+ {{Utils::Type::_float, 3}, {Utils::Type::dvec3, 0}, {Utils::Type::_double, 2}},
+ is_nested_struct});
+ m_test_cases.push_back(testCase{(Utils::Shader::STAGES)m_stage,
+ {{Utils::Type::_int, 1},
+ {Utils::Type::_double, 1},
+ {Utils::Type::_float, 1},
+ {Utils::Type::dmat2x4, 1}},
+ is_nested_struct});
+ m_test_cases.push_back(testCase{(Utils::Shader::STAGES)m_stage,
+ {{Utils::Type::_int, 5},
+ {Utils::Type::dvec3, 2},
+ {Utils::Type::uvec3, 0},
+ {Utils::Type::_double, 1}},
+ is_nested_struct});
+ m_test_cases.push_back(
+ testCase{(Utils::Shader::STAGES)m_stage,
+ {{Utils::Type::mat2x3, 3}, {Utils::Type::uvec4, 1}, {Utils::Type::dvec4, 0}},
+ is_nested_struct});
+ }
+
+ m_test_cases.push_back(
+ testCase{(Utils::Shader::STAGES)m_stage,
+ {{Utils::Type::dmat2x3, 2}, {Utils::Type::mat2x3, 2}, {Utils::Type::dvec2, 0}},
+ false});
+}
+} // namespace EnhancedLayouts
+
+/** 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));
+ addGLSLContantImmutablityTest();
+ addChild(new EnhancedLayouts::GLSLConstantIntegralExpressionTest(m_context));
+ addUniformBlockLayoutQualifierConflictTest();
+ addSSBMemberInvalidOffsetAlignmentTest();
+ addSSBMemberOverlappingOffsetsTest();
+ addVaryingInvalidValueComponentTest();
+ addVaryingExceedingComponentsTest();
+ addVaryingComponentOfInvalidTypeTest();
+ addOutputComponentAliasingTest();
+ addChild(new EnhancedLayouts::VertexAttribLocationAPITest(m_context));
+ addXFBInputTest();
+ addChild(new EnhancedLayouts::XFBAllStagesTest(m_context));
+ addChild(new EnhancedLayouts::XFBCaptureInactiveOutputVariableTest(m_context));
+ addChild(new EnhancedLayouts::XFBCaptureInactiveOutputComponentTest(m_context));
+ addChild(new EnhancedLayouts::XFBCaptureInactiveOutputBlockMemberTest(m_context));
+ addXFBStrideTest();
+ addChild(new EnhancedLayouts::UniformBlockMemberOffsetAndAlignTest(m_context));
+ addUniformBlockMemberInvalidOffsetAlignmentTest();
+ addUniformBlockMemberOverlappingOffsetsTest();
+ addUniformBlockMemberAlignNonPowerOf2Test();
+ addSSBLayoutQualifierConflictTest();
+ addSSBMemberAlignNonPowerOf2Test();
+ addChild(new EnhancedLayouts::SSBAlignmentTest(m_context));
+ addVaryingStructureMemberLocationTest();
+ addVaryingBlockAutomaticMemberLocationsTest();
+ addVaryingComponentWithoutLocationTest();
+ addInputComponentAliasingTest();
+ addVaryingLocationAliasingWithMixedTypesTest();
+ addVaryingLocationAliasingWithMixedInterpolationTest();
+ addVaryingLocationAliasingWithMixedAuxiliaryStorageTest();
+ addChild(new EnhancedLayouts::XFBStrideOfEmptyListTest(m_context));
+ addChild(new EnhancedLayouts::XFBStrideOfEmptyListAndAPITest(m_context));
+ addXFBTooSmallStrideTest();
+ addChild(new EnhancedLayouts::XFBBlockMemberStrideTest(m_context));
+ addXFBDuplicatedStrideTest();
+ addXFBGetProgramResourceAPITest();
+ addChild(new EnhancedLayouts::XFBMultipleVertexStreamsTest(m_context));
+ addXFBExceedBufferLimitTest();
+ addXFBExceedOffsetLimitTest();
+ addXFBBlockMemberBufferTest();
+ addXFBOutputOverlappingTest();
+ addXFBInvalidOffsetAlignmentTest();
+ addChild(new EnhancedLayouts::XFBCaptureStructTest(m_context));
+ addXFBCaptureUnsizedArrayTest();
+ 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));
+ addVaryingBlockMemberLocationsTest();
+ addXFBVariableStrideTest();
+ addXFBBlockStrideTest();
+ addChild(new EnhancedLayouts::XFBOverrideQualifiersWithAPITest(m_context));
+ addChild(new EnhancedLayouts::XFBVertexStreamsTest(m_context));
+ addXFBGlobalBufferTest();
+ addXFBExplicitLocationTest();
+ addXFBExplicitLocationStructTest();
+ addChild(new EnhancedLayouts::FragmentDataLocationAPITest(m_context));
+ addVaryingLocationLimitTest();
+ addVaryingComponentsTest();
+ addVaryingArrayComponentsTest();
+}
+
+void EnhancedLayoutsTests::addGLSLContantImmutablityTest()
+{
+ for (GLuint constant = 0; constant < EnhancedLayouts::GLSLContantImmutablityTest::CONSTANTS_MAX;
+ ++constant)
+ {
+ for (GLuint stage = 0; stage < EnhancedLayouts::Utils::Shader::STAGE_MAX; ++stage)
+ {
+ addChild(new EnhancedLayouts::GLSLContantImmutablityTest(m_context, constant, stage));
+ }
+ }
+}
+
+void EnhancedLayoutsTests::addUniformBlockLayoutQualifierConflictTest()
+{
+ for (GLuint qualifier = 0;
+ qualifier < EnhancedLayouts::UniformBlockLayoutQualifierConflictTest::QUALIFIERS_MAX;
+ ++qualifier)
+ {
+ for (GLuint stage = 0; stage < EnhancedLayouts::Utils::Shader::STAGE_MAX; ++stage)
+ {
+ addChild(new EnhancedLayouts::UniformBlockLayoutQualifierConflictTest(
+ m_context, qualifier, stage));
+ }
+ }
+}
+
+void EnhancedLayoutsTests::addSSBMemberInvalidOffsetAlignmentTest()
+{
+ for (GLuint type = 0; type < EnhancedLayouts::TYPES_NUMBER; ++type)
+ {
+ for (GLuint stage = 0; stage < EnhancedLayouts::Utils::Shader::STAGE_MAX; ++stage)
+ {
+ EnhancedLayouts::SSBMemberInvalidOffsetAlignmentTest *test =
+ new EnhancedLayouts::SSBMemberInvalidOffsetAlignmentTest(m_context, type, stage);
+ if (test->stageAllowed(stage))
+ {
+ addChild(test);
+ }
+ else
+ {
+ delete test;
+ }
+ }
+ }
+}
+
+void EnhancedLayoutsTests::addSSBMemberOverlappingOffsetsTest()
+{
+ for (GLuint type_i = 0; type_i < EnhancedLayouts::TYPES_NUMBER; ++type_i)
+ {
+ for (GLuint type_j = 0; type_j < EnhancedLayouts::TYPES_NUMBER; ++type_j)
+ {
+ addChild(
+ new EnhancedLayouts::SSBMemberOverlappingOffsetsTest(m_context, type_i, type_j));
+ }
+ }
+}
+
+void EnhancedLayoutsTests::addVaryingInvalidValueComponentTest()
+{
+ for (GLuint type_num = 0; type_num < EnhancedLayouts::TYPES_NUMBER; ++type_num)
+ {
+ EnhancedLayouts::VaryingInvalidValueComponentTest *test =
+ new EnhancedLayouts::VaryingInvalidValueComponentTest(m_context, type_num);
+
+ const EnhancedLayouts::Utils::Type &type = test->getTypeHelper(type_num);
+ const std::vector<GLuint> &valid_components = type.GetValidComponents();
+
+ if (valid_components.empty())
+ {
+ delete test;
+ }
+ else
+ {
+ addChild(test);
+ }
+ }
+}
+
+void EnhancedLayoutsTests::addVaryingExceedingComponentsTest()
+{
+ for (GLuint type_num = 0; type_num < EnhancedLayouts::TYPES_NUMBER; ++type_num)
+ {
+ EnhancedLayouts::VaryingExceedingComponentsTest *test =
+ new EnhancedLayouts::VaryingExceedingComponentsTest(m_context, type_num);
+
+ const EnhancedLayouts::Utils::Type &type = test->getTypeHelper(type_num);
+ const std::vector<GLuint> &valid_components = type.GetValidComponents();
+
+ if (valid_components.empty())
+ {
+ delete test;
+ }
+ else
+ {
+ addChild(test);
+ }
+ }
+}
+
+void EnhancedLayoutsTests::addVaryingComponentOfInvalidTypeTest()
+{
+ for (GLuint type = 0; type < EnhancedLayouts::TYPES_NUMBER; ++type)
+ {
+ for (GLuint stage = 0; stage < EnhancedLayouts::Utils::Shader::STAGE_MAX; ++stage)
+ {
+ if (EnhancedLayouts::Utils::Shader::COMPUTE == stage)
+ {
+ continue;
+ }
+ addChild(
+ new EnhancedLayouts::VaryingComponentOfInvalidTypeTest(m_context, type, stage));
+ }
+ }
+}
+
+void EnhancedLayoutsTests::addOutputComponentAliasingTest()
+{
+ for (GLuint type_num = 0; type_num < EnhancedLayouts::TYPES_NUMBER; ++type_num)
+ {
+ EnhancedLayouts::OutputComponentAliasingTest *test =
+ new EnhancedLayouts::OutputComponentAliasingTest(m_context, type_num);
+
+ const EnhancedLayouts::Utils::Type &type = test->getTypeHelper(type_num);
+ const std::vector<GLuint> &valid_components = type.GetValidComponents();
+
+ if (valid_components.empty())
+ {
+ delete test;
+ }
+ else
+ {
+ addChild(test);
+ }
+ }
+}
+
+void EnhancedLayoutsTests::addXFBInputTest()
+{
+ for (GLuint qualifier = 0; qualifier < EnhancedLayouts::XFBInputTest::QUALIFIERS_MAX;
+ ++qualifier)
+ {
+ for (GLuint stage = 0; stage < EnhancedLayouts::Utils::Shader::STAGE_MAX; ++stage)
+ {
+ if (EnhancedLayouts::Utils::Shader::COMPUTE == stage)
+ {
+ continue;
+ }
+ addChild(new EnhancedLayouts::XFBInputTest(m_context, qualifier, stage));
+ }
+ }
+}
+
+void EnhancedLayoutsTests::addXFBStrideTest()
+{
+ for (GLuint type = 0; type < EnhancedLayouts::TYPES_NUMBER; ++type)
+ {
+ for (GLuint stage = 0; stage < EnhancedLayouts::Utils::Shader::STAGE_MAX; ++stage)
+ {
+ if ((EnhancedLayouts::Utils::Shader::COMPUTE == stage) ||
+ (EnhancedLayouts::Utils::Shader::FRAGMENT == stage) ||
+ (EnhancedLayouts::Utils::Shader::TESS_CTRL == stage))
+ {
+ continue;
+ }
+ addChild(new EnhancedLayouts::XFBStrideTest(m_context, type, stage));
+ }
+ }
+}
+
+void EnhancedLayoutsTests::addUniformBlockMemberInvalidOffsetAlignmentTest()
+{
+ for (GLuint type = 0; type < EnhancedLayouts::TYPES_NUMBER; ++type)
+ {
+ for (GLuint stage = 0; stage < EnhancedLayouts::Utils::Shader::STAGE_MAX; ++stage)
+ {
+ EnhancedLayouts::UniformBlockMemberInvalidOffsetAlignmentTest *test =
+ new EnhancedLayouts::UniformBlockMemberInvalidOffsetAlignmentTest(m_context, type,
+ stage);
+ if (test->stageAllowed(stage))
+ {
+ addChild(test);
+ }
+ else
+ {
+ delete test;
+ }
+ }
+ }
+}
+
+void EnhancedLayoutsTests::addUniformBlockMemberOverlappingOffsetsTest()
+{
+ for (GLuint type_i = 0; type_i < EnhancedLayouts::TYPES_NUMBER; ++type_i)
+ {
+ for (GLuint type_j = 0; type_j < EnhancedLayouts::TYPES_NUMBER; ++type_j)
+ {
+ addChild(new EnhancedLayouts::UniformBlockMemberOverlappingOffsetsTest(m_context,
+ type_i, type_j));
+ }
+ }
+}
+
+void EnhancedLayoutsTests::addUniformBlockMemberAlignNonPowerOf2Test()
+{
+ for (GLuint type = 0; type < EnhancedLayouts::TYPES_NUMBER; ++type)
+ {
+ addChild(new EnhancedLayouts::UniformBlockMemberAlignNonPowerOf2Test(m_context, type));
+ }
+}
+
+void EnhancedLayoutsTests::addSSBMemberAlignNonPowerOf2Test()
+{
+ for (GLuint type = 0; type < EnhancedLayouts::TYPES_NUMBER; ++type)
+ {
+ addChild(new EnhancedLayouts::SSBMemberAlignNonPowerOf2Test(m_context, type));
+ }
+}
+
+void EnhancedLayoutsTests::addSSBLayoutQualifierConflictTest()
+{
+ for (GLuint qualifier = 0;
+ qualifier < EnhancedLayouts::SSBLayoutQualifierConflictTest::QUALIFIERS_MAX; ++qualifier)
+ {
+ for (GLuint stage = 0; stage < EnhancedLayouts::Utils::Shader::STAGE_MAX; ++stage)
+ {
+ EnhancedLayouts::SSBLayoutQualifierConflictTest *test =
+ new EnhancedLayouts::SSBLayoutQualifierConflictTest(m_context, qualifier, stage);
+ if (test->stageAllowed(stage))
+ {
+ addChild(test);
+ }
+ else
+ {
+ delete test;
+ }
+ }
+ }
+}
+
+void EnhancedLayoutsTests::addVaryingStructureMemberLocationTest()
+{
+
+ for (GLuint stage = 0; stage < EnhancedLayouts::Utils::Shader::STAGE_MAX; ++stage)
+ {
+ if (EnhancedLayouts::Utils::Shader::COMPUTE == stage)
+ {
+ continue;
+ }
+ addChild(new EnhancedLayouts::VaryingStructureMemberLocationTest(m_context, stage));
+ }
+}
+
+void EnhancedLayoutsTests::addVaryingBlockAutomaticMemberLocationsTest()
+{
+
+ for (GLuint stage = 0; stage < EnhancedLayouts::Utils::Shader::STAGE_MAX; ++stage)
+ {
+ if (EnhancedLayouts::Utils::Shader::COMPUTE == stage)
+ {
+ continue;
+ }
+ addChild(new EnhancedLayouts::VaryingBlockAutomaticMemberLocationsTest(m_context, stage));
+ }
+}
+
+void EnhancedLayoutsTests::addVaryingComponentWithoutLocationTest()
+{
+ for (GLuint type_num = 0; type_num < EnhancedLayouts::TYPES_NUMBER; ++type_num)
+ {
+ EnhancedLayouts::VaryingComponentWithoutLocationTest *test =
+ new EnhancedLayouts::VaryingComponentWithoutLocationTest(m_context, type_num);
+
+ const EnhancedLayouts::Utils::Type &type = test->getTypeHelper(type_num);
+ const std::vector<GLuint> &valid_components = type.GetValidComponents();
+
+ if (valid_components.empty())
+ {
+ delete test;
+ }
+ else
+ {
+ addChild(test);
+ }
+ }
+}
+
+void EnhancedLayoutsTests::addInputComponentAliasingTest()
+{
+ for (GLuint type_num = 0; type_num < EnhancedLayouts::TYPES_NUMBER; ++type_num)
+ {
+ EnhancedLayouts::InputComponentAliasingTest *test =
+ new EnhancedLayouts::InputComponentAliasingTest(m_context, type_num);
+
+ const EnhancedLayouts::Utils::Type &type = test->getTypeHelper(type_num);
+ const std::vector<GLuint> &valid_components = type.GetValidComponents();
+
+ if (valid_components.empty())
+ {
+ delete test;
+ }
+ else
+ {
+ addChild(test);
+ }
+ }
+}
+
+void EnhancedLayoutsTests::addVaryingLocationAliasingWithMixedTypesTest()
+{
+ for (GLuint type_gohan = 0; type_gohan < EnhancedLayouts::TYPES_NUMBER; ++type_gohan)
+ {
+ for (GLuint type_goten = 0; type_goten < EnhancedLayouts::TYPES_NUMBER; ++type_goten)
+ {
+ EnhancedLayouts::VaryingLocationAliasingWithMixedTypesTest *test =
+ new EnhancedLayouts::VaryingLocationAliasingWithMixedTypesTest(
+ m_context, type_gohan, type_goten);
+
+ const EnhancedLayouts::Utils::Type &tp_gohan = test->getTypeHelper(type_gohan);
+ const std::vector<GLuint> &valid_components_gohan = tp_gohan.GetValidComponents();
+ const EnhancedLayouts::Utils::Type &tp_goten = test->getTypeHelper(type_goten);
+ const std::vector<GLuint> &valid_components_goten = tp_goten.GetValidComponents();
+
+ if (valid_components_gohan.empty() || valid_components_goten.empty() ||
+ EnhancedLayouts::Utils::Type::CanTypesShareLocation(tp_gohan.m_basic_type,
+ tp_goten.m_basic_type))
+ {
+ delete test;
+ }
+ else
+ {
+ addChild(test);
+ }
+ }
+ }
+}
+
+void EnhancedLayoutsTests::addVaryingLocationAliasingWithMixedInterpolationTest()
+{
+ for (GLuint type_gohan = 0; type_gohan < EnhancedLayouts::TYPES_NUMBER; ++type_gohan)
+ {
+ for (GLuint type_goten = 0; type_goten < EnhancedLayouts::TYPES_NUMBER; ++type_goten)
+ {
+ EnhancedLayouts::VaryingLocationAliasingWithMixedInterpolationTest *test =
+ new EnhancedLayouts::VaryingLocationAliasingWithMixedInterpolationTest(
+ m_context, type_gohan, type_goten);
+
+ const EnhancedLayouts::Utils::Type &tp_gohan = test->getTypeHelper(type_gohan);
+ const std::vector<GLuint> &valid_components_gohan = tp_gohan.GetValidComponents();
+ const EnhancedLayouts::Utils::Type &tp_goten = test->getTypeHelper(type_goten);
+ const std::vector<GLuint> &valid_components_goten = tp_goten.GetValidComponents();
+
+ if (valid_components_gohan.empty() || valid_components_goten.empty())
+ {
+ delete test;
+ }
+ else
+ {
+ const GLuint gohan = valid_components_gohan.front();
+ const GLuint min_component = gohan + tp_gohan.GetNumComponents();
+ const GLuint goten = valid_components_goten.back();
+ if ((min_component > goten) ||
+ (!EnhancedLayouts::Utils::Type::CanTypesShareLocation(tp_gohan.m_basic_type,
+ tp_goten.m_basic_type)))
+ {
+ delete test;
+ }
+ else
+ {
+ addChild(test);
+ }
+ }
+ }
+ }
+}
+
+void EnhancedLayoutsTests::addVaryingLocationAliasingWithMixedAuxiliaryStorageTest()
+{
+ for (GLuint type_gohan = 0; type_gohan < EnhancedLayouts::TYPES_NUMBER; ++type_gohan)
+ {
+ for (GLuint type_goten = 0; type_goten < EnhancedLayouts::TYPES_NUMBER; ++type_goten)
+ {
+ EnhancedLayouts::VaryingLocationAliasingWithMixedAuxiliaryStorageTest *test =
+ new EnhancedLayouts::VaryingLocationAliasingWithMixedAuxiliaryStorageTest(
+ m_context, type_gohan, type_goten);
+
+ const EnhancedLayouts::Utils::Type &tp_gohan = test->getTypeHelper(type_gohan);
+ const std::vector<GLuint> &valid_components_gohan = tp_gohan.GetValidComponents();
+ const EnhancedLayouts::Utils::Type &tp_goten = test->getTypeHelper(type_goten);
+ const std::vector<GLuint> &valid_components_goten = tp_goten.GetValidComponents();
+
+ if (valid_components_gohan.empty() || valid_components_goten.empty())
+ {
+ delete test;
+ }
+ else
+ {
+ const GLuint gohan = valid_components_gohan.front();
+ const GLuint min_component = gohan + tp_gohan.GetNumComponents();
+ const GLuint goten = valid_components_goten.back();
+ if ((min_component > goten) ||
+ (!EnhancedLayouts::Utils::Type::CanTypesShareLocation(tp_gohan.m_basic_type,
+ tp_goten.m_basic_type)))
+ {
+ delete test;
+ }
+ else
+ {
+ addChild(test);
+ }
+ }
+ }
+ }
+}
+
+void EnhancedLayoutsTests::addXFBTooSmallStrideTest()
+{
+ for (GLuint constant = 0; constant < EnhancedLayouts::XFBTooSmallStrideTest::CASES::CASE_MAX;
+ ++constant)
+ {
+ for (GLuint stage = 0; stage < EnhancedLayouts::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 ((EnhancedLayouts::Utils::Shader::COMPUTE == stage) ||
+ (EnhancedLayouts::Utils::Shader::TESS_CTRL == stage) ||
+ (EnhancedLayouts::Utils::Shader::FRAGMENT == stage))
+ {
+ continue;
+ }
+ addChild(new EnhancedLayouts::XFBTooSmallStrideTest(m_context, constant, stage));
+ }
+ }
+}
+
+void EnhancedLayoutsTests::addXFBDuplicatedStrideTest()
+{
+ for (GLuint constant = 0; constant < EnhancedLayouts::XFBDuplicatedStrideTest::CASES::CASE_MAX;
+ ++constant)
+ {
+ for (GLuint stage = 0; stage < EnhancedLayouts::Utils::Shader::STAGE_MAX; ++stage)
+ {
+ if ((EnhancedLayouts::Utils::Shader::COMPUTE == stage) ||
+ (EnhancedLayouts::Utils::Shader::TESS_CTRL == stage) ||
+ (EnhancedLayouts::Utils::Shader::FRAGMENT == stage))
+ {
+ continue;
+ }
+ addChild(new EnhancedLayouts::XFBDuplicatedStrideTest(m_context, constant, stage));
+ }
+ }
+}
+
+void EnhancedLayoutsTests::addXFBGetProgramResourceAPITest()
+{
+ for (GLuint type = 0; type < EnhancedLayouts::TYPES_NUMBER; ++type)
+ {
+ // 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
+ if ((type == 7 || type == 9))
+ {
+ continue;
+ }
+ addChild(new EnhancedLayouts::XFBGetProgramResourceAPITest(m_context, type));
+ }
+}
+
+void EnhancedLayoutsTests::addXFBExceedBufferLimitTest()
+{
+ for (GLuint constant = 0; constant < EnhancedLayouts::XFBExceedBufferLimitTest::CASES::CASE_MAX;
+ ++constant)
+ {
+ for (GLuint stage = 0; stage < EnhancedLayouts::Utils::Shader::STAGE_MAX; ++stage)
+ {
+ if ((EnhancedLayouts::Utils::Shader::COMPUTE == stage) ||
+ (EnhancedLayouts::Utils::Shader::TESS_CTRL == stage) ||
+ (EnhancedLayouts::Utils::Shader::FRAGMENT == stage))
+ {
+ continue;
+ }
+ addChild(new EnhancedLayouts::XFBExceedBufferLimitTest(m_context, constant, stage));
+ }
+ }
+}
+
+void EnhancedLayoutsTests::addXFBExceedOffsetLimitTest()
+{
+ for (GLuint constant = 0; constant < EnhancedLayouts::XFBExceedOffsetLimitTest::CASES::CASE_MAX;
+ ++constant)
+ {
+ for (GLuint stage = 0; stage < EnhancedLayouts::Utils::Shader::STAGE_MAX; ++stage)
+ {
+ if ((EnhancedLayouts::Utils::Shader::COMPUTE == stage) ||
+ (EnhancedLayouts::Utils::Shader::TESS_CTRL == stage) ||
+ (EnhancedLayouts::Utils::Shader::FRAGMENT == stage))
+ {
+ continue;
+ }
+ addChild(new EnhancedLayouts::XFBExceedOffsetLimitTest(m_context, constant, stage));
+ }
+ }
+}
+
+void EnhancedLayoutsTests::addXFBBlockMemberBufferTest()
+{
+ for (GLuint stage = 0; stage < EnhancedLayouts::Utils::Shader::STAGE_MAX; ++stage)
+ {
+ if ((EnhancedLayouts::Utils::Shader::COMPUTE == stage) ||
+ (EnhancedLayouts::Utils::Shader::TESS_CTRL == stage) ||
+ (EnhancedLayouts::Utils::Shader::FRAGMENT == stage))
+ {
+ continue;
+ }
+ addChild(new EnhancedLayouts::XFBBlockMemberBufferTest(m_context, stage));
+ }
+}
+
+void EnhancedLayoutsTests::addXFBOutputOverlappingTest()
+{
+ for (GLuint type = 0; type < EnhancedLayouts::TYPES_NUMBER; ++type)
+ {
+ for (GLuint stage = 0; stage < EnhancedLayouts::Utils::Shader::STAGE_MAX; ++stage)
+ {
+ EnhancedLayouts::XFBOutputOverlappingTest *test =
+ new EnhancedLayouts::XFBOutputOverlappingTest(m_context, type, stage);
+
+ const EnhancedLayouts::Utils::Type &utils_type = test->getTypeHelper(type);
+
+ if (((1 == utils_type.m_n_columns) && (1 == utils_type.m_n_rows)) ||
+ ((EnhancedLayouts::Utils::Shader::COMPUTE == stage) ||
+ (EnhancedLayouts::Utils::Shader::TESS_CTRL == stage) ||
+ (EnhancedLayouts::Utils::Shader::FRAGMENT == stage)))
+ {
+ delete test;
+ }
+ else
+ {
+ addChild(test);
+ }
+ }
+ }
+}
+
+void EnhancedLayoutsTests::addXFBInvalidOffsetAlignmentTest()
+{
+ for (GLuint type = 0; type < EnhancedLayouts::TYPES_NUMBER; ++type)
+ {
+ for (GLuint stage = 0; stage < EnhancedLayouts::Utils::Shader::STAGE_MAX; ++stage)
+ {
+ if (((EnhancedLayouts::Utils::Shader::COMPUTE == stage) ||
+ (EnhancedLayouts::Utils::Shader::TESS_CTRL == stage) ||
+ (EnhancedLayouts::Utils::Shader::FRAGMENT == stage)))
+ {
+ continue;
+ }
+ else
+ {
+ addChild(
+ new EnhancedLayouts::XFBInvalidOffsetAlignmentTest(m_context, type, stage));
+ }
+ }
+ }
+}
+
+void EnhancedLayoutsTests::addXFBCaptureUnsizedArrayTest()
+{
+ for (GLuint stage = 0; stage < EnhancedLayouts::Utils::Shader::STAGE_MAX; ++stage)
+ {
+ if ((EnhancedLayouts::Utils::Shader::COMPUTE == stage) ||
+ (EnhancedLayouts::Utils::Shader::TESS_CTRL == stage) ||
+ (EnhancedLayouts::Utils::Shader::FRAGMENT == stage) ||
+ (EnhancedLayouts::Utils::Shader::GEOMETRY == stage) ||
+ (EnhancedLayouts::Utils::Shader::TESS_EVAL == stage))
+ {
+ continue;
+ }
+ addChild(new EnhancedLayouts::XFBCaptureUnsizedArrayTest(m_context, stage));
+ }
+}
+
+void EnhancedLayoutsTests::addVaryingBlockMemberLocationsTest()
+{
+ for (GLuint stage = 0; stage < EnhancedLayouts::Utils::Shader::STAGE_MAX; ++stage)
+ {
+ if (EnhancedLayouts::Utils::Shader::COMPUTE == stage)
+ {
+ continue;
+ }
+ addChild(new EnhancedLayouts::VaryingBlockMemberLocationsTest(m_context, stage));
+ }
+}
+
+void EnhancedLayoutsTests::addXFBVariableStrideTest()
+{
+ for (GLuint type = 0; type < EnhancedLayouts::TYPES_NUMBER; ++type)
+ {
+ for (GLuint stage = 0; stage < EnhancedLayouts::Utils::Shader::STAGE_MAX; ++stage)
+ {
+ if ((EnhancedLayouts::Utils::Shader::COMPUTE == stage) ||
+ (EnhancedLayouts::Utils::Shader::TESS_CTRL == stage) ||
+ (EnhancedLayouts::Utils::Shader::FRAGMENT == stage))
+ {
+ continue;
+ }
+ for (GLuint constant = 0;
+ constant < EnhancedLayouts::XFBVariableStrideTest::CASES::CASE_MAX; ++constant)
+ {
+ addChild(
+ new EnhancedLayouts::XFBVariableStrideTest(m_context, type, stage, constant));
+ }
+ }
+ }
+}
+
+void EnhancedLayoutsTests::addXFBBlockStrideTest()
+{
+ for (GLuint stage = 0; stage < EnhancedLayouts::Utils::Shader::STAGE_MAX; ++stage)
+ {
+ if ((EnhancedLayouts::Utils::Shader::COMPUTE == stage) ||
+ (EnhancedLayouts::Utils::Shader::TESS_CTRL == stage) ||
+ (EnhancedLayouts::Utils::Shader::FRAGMENT == stage))
+ {
+ continue;
+ }
+ addChild(new EnhancedLayouts::XFBBlockStrideTest(m_context, stage));
+ }
+}
+
+void EnhancedLayoutsTests::addXFBGlobalBufferTest()
+{
+ for (GLuint type = 0; type < EnhancedLayouts::TYPES_NUMBER; ++type)
+ {
+ EnhancedLayouts::XFBGlobalBufferTest *test =
+ new EnhancedLayouts::XFBGlobalBufferTest(m_context, type);
+ const EnhancedLayouts::Utils::Type &utils_type = test->getTypeHelper(type);
+ /*
+ 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(utils_type.GetGLSLTypeName(), "dmat3") == 0 ||
+ strcmp(utils_type.GetGLSLTypeName(), "dmat4") == 0 ||
+ strcmp(utils_type.GetGLSLTypeName(), "dmat3x4") == 0 ||
+ strcmp(utils_type.GetGLSLTypeName(), "dmat4x3") == 0)
+ {
+ delete test;
+ }
+ else
+ {
+ addChild(test);
+ }
+ }
+}
+
+void EnhancedLayoutsTests::addXFBExplicitLocationTest()
+{
+ for (GLuint type = 0; type < EnhancedLayouts::TYPES_NUMBER; ++type)
+ {
+ for (GLuint stage = 0; stage < EnhancedLayouts::Utils::Shader::STAGE_MAX; ++stage)
+ {
+ if ((EnhancedLayouts::Utils::Shader::COMPUTE == stage) ||
+ (EnhancedLayouts::Utils::Shader::FRAGMENT == stage) ||
+ (EnhancedLayouts::Utils::Shader::TESS_CTRL == stage))
+ {
+ continue;
+ }
+ else
+ {
+ addChild(new EnhancedLayouts::XFBExplicitLocationTest(m_context, type, stage));
+ }
+ }
+ }
+}
+
+void EnhancedLayoutsTests::addXFBExplicitLocationStructTest()
+{
+ for (GLuint stage = 0; stage < EnhancedLayouts::Utils::Shader::STAGE_MAX; ++stage)
+ {
+ if ((EnhancedLayouts::Utils::Shader::COMPUTE == stage) ||
+ (EnhancedLayouts::Utils::Shader::FRAGMENT == stage) ||
+ (EnhancedLayouts::Utils::Shader::TESS_CTRL == stage))
+ {
+ continue;
+ }
+ else
+ {
+ addChild(new EnhancedLayouts::XFBExplicitLocationStructTest(m_context, stage));
+ }
+ }
+}
+
+void EnhancedLayoutsTests::addVaryingLocationLimitTest()
+{
+ for (GLuint type = 0; type < EnhancedLayouts::TYPES_NUMBER; ++type)
+ {
+ for (GLuint stage = 0; stage < EnhancedLayouts::Utils::Shader::STAGE_MAX; ++stage)
+ {
+ if (EnhancedLayouts::Utils::Shader::COMPUTE == stage)
+ {
+ continue;
+ }
+ else
+ {
+ addChild(new EnhancedLayouts::VaryingLocationLimitTest(m_context, type, stage));
+ }
+ }
+ }
+}
+
+template <class varyingClass>
+void EnhancedLayoutsTests::addVaryingTest()
+{
+ addChild(new varyingClass(m_context, varyingClass::COMPONENTS_LAYOUT::G64VEC2,
+ EnhancedLayouts::Utils::Type::Double));
+ addChild(new varyingClass(m_context, varyingClass::COMPONENTS_LAYOUT::G64SCALAR_G64SCALAR,
+ EnhancedLayouts::Utils::Type::Double));
+ addChild(new varyingClass(m_context, varyingClass::COMPONENTS_LAYOUT::GVEC4,
+ EnhancedLayouts::Utils::Type::Float));
+ addChild(new varyingClass(m_context, varyingClass::COMPONENTS_LAYOUT::SCALAR_GVEC3,
+ EnhancedLayouts::Utils::Type::Float));
+ addChild(new varyingClass(m_context, varyingClass::COMPONENTS_LAYOUT::GVEC3_SCALAR,
+ EnhancedLayouts::Utils::Type::Float));
+ addChild(new varyingClass(m_context, varyingClass::COMPONENTS_LAYOUT::GVEC2_GVEC2,
+ EnhancedLayouts::Utils::Type::Float));
+ addChild(new varyingClass(m_context, varyingClass::COMPONENTS_LAYOUT::GVEC2_SCALAR_SCALAR,
+ EnhancedLayouts::Utils::Type::Float));
+ addChild(new varyingClass(m_context, varyingClass::COMPONENTS_LAYOUT::SCALAR_GVEC2_SCALAR,
+ EnhancedLayouts::Utils::Type::Float));
+ addChild(new varyingClass(m_context, varyingClass::COMPONENTS_LAYOUT::SCALAR_SCALAR_GVEC2,
+ EnhancedLayouts::Utils::Type::Float));
+ addChild(new varyingClass(m_context,
+ varyingClass::COMPONENTS_LAYOUT::SCALAR_SCALAR_SCALAR_SCALAR,
+ EnhancedLayouts::Utils::Type::Float));
+ addChild(new varyingClass(m_context, varyingClass::COMPONENTS_LAYOUT::GVEC4,
+ EnhancedLayouts::Utils::Type::Int));
+ addChild(new varyingClass(m_context, varyingClass::COMPONENTS_LAYOUT::SCALAR_GVEC3,
+ EnhancedLayouts::Utils::Type::Int));
+ addChild(new varyingClass(m_context, varyingClass::COMPONENTS_LAYOUT::GVEC3_SCALAR,
+ EnhancedLayouts::Utils::Type::Int));
+ addChild(new varyingClass(m_context, varyingClass::COMPONENTS_LAYOUT::GVEC2_GVEC2,
+ EnhancedLayouts::Utils::Type::Int));
+ addChild(new varyingClass(m_context, varyingClass::COMPONENTS_LAYOUT::GVEC2_SCALAR_SCALAR,
+ EnhancedLayouts::Utils::Type::Int));
+ addChild(new varyingClass(m_context, varyingClass::COMPONENTS_LAYOUT::SCALAR_GVEC2_SCALAR,
+ EnhancedLayouts::Utils::Type::Int));
+ addChild(new varyingClass(m_context, varyingClass::COMPONENTS_LAYOUT::SCALAR_SCALAR_GVEC2,
+ EnhancedLayouts::Utils::Type::Int));
+ addChild(new varyingClass(m_context,
+ varyingClass::COMPONENTS_LAYOUT::SCALAR_SCALAR_SCALAR_SCALAR,
+ EnhancedLayouts::Utils::Type::Int));
+ addChild(new varyingClass(m_context, varyingClass::COMPONENTS_LAYOUT::GVEC4,
+ EnhancedLayouts::Utils::Type::Uint));
+ addChild(new varyingClass(m_context, varyingClass::COMPONENTS_LAYOUT::SCALAR_GVEC3,
+ EnhancedLayouts::Utils::Type::Uint));
+ addChild(new varyingClass(m_context, varyingClass::COMPONENTS_LAYOUT::GVEC3_SCALAR,
+ EnhancedLayouts::Utils::Type::Uint));
+ addChild(new varyingClass(m_context, varyingClass::COMPONENTS_LAYOUT::GVEC2_GVEC2,
+ EnhancedLayouts::Utils::Type::Uint));
+ addChild(new varyingClass(m_context, varyingClass::COMPONENTS_LAYOUT::GVEC2_SCALAR_SCALAR,
+ EnhancedLayouts::Utils::Type::Uint));
+ addChild(new varyingClass(m_context, varyingClass::COMPONENTS_LAYOUT::SCALAR_GVEC2_SCALAR,
+ EnhancedLayouts::Utils::Type::Uint));
+ addChild(new varyingClass(m_context, varyingClass::COMPONENTS_LAYOUT::SCALAR_SCALAR_GVEC2,
+ EnhancedLayouts::Utils::Type::Uint));
+ addChild(new varyingClass(m_context,
+ varyingClass::COMPONENTS_LAYOUT::SCALAR_SCALAR_SCALAR_SCALAR,
+ EnhancedLayouts::Utils::Type::Uint));
+}
+
+void EnhancedLayoutsTests::addVaryingComponentsTest()
+{
+ addVaryingTest<EnhancedLayouts::VaryingComponentsTest>();
+}
+
+void EnhancedLayoutsTests::addVaryingArrayComponentsTest()
+{
+ addVaryingTest<EnhancedLayouts::VaryingArrayComponentsTest>();
+}
+
+} // namespace gl4cts