| /*------------------------------------------------------------------------- |
| * OpenGL Conformance Test Suite |
| * ----------------------------- |
| * |
| * Copyright (c) 2014-2016 The Khronos Group Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| */ /*! |
| * \file |
| * \brief |
| */ /*-------------------------------------------------------------------*/ |
| |
| /** |
| * \file gl4cShadingLanguage420PackTests.cpp |
| * \brief Implements conformance tests for "Shading Language 420Pack" functionality. |
| */ /*-------------------------------------------------------------------*/ |
| |
| #include "gl4cShadingLanguage420PackTests.hpp" |
| |
| #include "gluContextInfo.hpp" |
| #include "gluDefs.hpp" |
| #include "glwEnums.hpp" |
| #include "glwFunctions.hpp" |
| #include "tcuTestLog.hpp" |
| |
| #include <algorithm> |
| #include <iomanip> |
| #include <stdio.h> |
| #include <string.h> |
| #include <string> |
| #include <vector> |
| |
| #define IS_DEBUG 0 |
| |
| using namespace glw; |
| |
| namespace gl4cts |
| { |
| |
| namespace GLSL420Pack |
| { |
| /** Check binding of uniform |
| * |
| * @param program Program object |
| * @param name Array name |
| * @param expected_binding Expected binding value |
| * |
| * @return true if binding is as expected, false otherwise |
| **/ |
| bool Utils::checkUniformBinding(Utils::program& program, const glw::GLchar* name, glw::GLint expected_binding) |
| { |
| const GLint uniform_location = program.getUniformLocation(name); |
| if (-1 == uniform_location) |
| { |
| TCU_FAIL("Uniform is inactive"); |
| } |
| |
| GLint binding = program.getUniform1i(uniform_location); |
| |
| return (expected_binding == binding); |
| } |
| /** Check binding of uniform array element at <index> |
| * |
| * @param program Program object |
| * @param name Array name |
| * @param index Index |
| * @param expected_binding Expected binding value |
| * |
| * @return true if binding is as expected, false otherwise |
| **/ |
| bool Utils::checkUniformArrayBinding(Utils::program& program, const glw::GLchar* name, glw::GLuint index, |
| glw::GLint expected_binding) |
| { |
| GLchar buffer[64]; |
| sprintf(buffer, "%s[%d]", name, index); |
| |
| const GLint uniform_location = program.getUniformLocation(buffer); |
| if (-1 == uniform_location) |
| { |
| TCU_FAIL("Uniform is inactive"); |
| } |
| |
| GLint binding = program.getUniform1i(uniform_location); |
| |
| return (expected_binding == binding); |
| } |
| |
| /** Check if given qualifier is present in set |
| * |
| * @param qualifier Specific qualifier |
| * @param qualifiers Qualifiers' set |
| * |
| * @return true if qualifier is present, false otherwise |
| **/ |
| bool Utils::doesContainQualifier(Utils::QUALIFIERS qualifier, const Utils::qualifierSet& qualifiers) |
| { |
| for (GLuint i = 0; i < qualifiers.size(); ++i) |
| { |
| if (qualifiers[i] == qualifier) |
| { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| /** Check if given stage supports specific qualifier |
| * |
| * @param stage Shader stage |
| * @param storage Storage of variable |
| * @param qualifier Qualifier |
| * |
| * @return true if qualifier can be used in given stage, false otherwise |
| **/ |
| bool Utils::doesStageSupportQualifier(Utils::SHADER_STAGES stage, Utils::VARIABLE_STORAGE storage, |
| Utils::QUALIFIERS qualifier) |
| { |
| bool result = true; |
| |
| switch (stage) |
| { |
| case COMPUTE_SHADER: |
| switch (qualifier) |
| { |
| case QUAL_NONE: |
| case QUAL_UNIFORM: |
| case QUAL_LOWP: |
| case QUAL_MEDIUMP: |
| case QUAL_HIGHP: |
| case QUAL_INVARIANT: |
| result = true; |
| break; |
| default: |
| result = false; |
| break; |
| } |
| break; |
| case FRAGMENT_SHADER: |
| if (QUAL_PATCH == qualifier) |
| { |
| result = false; |
| } |
| else if ((OUTPUT == storage) && |
| ((QUAL_SMOOTH == qualifier) || (QUAL_NOPERSPECTIVE == qualifier) || (QUAL_FLAT == qualifier))) |
| { |
| result = false; |
| } |
| break; |
| case VERTEX_SHADER: |
| if (QUAL_PATCH == qualifier) |
| { |
| result = false; |
| } |
| else if ((INPUT == storage) && |
| ((QUAL_SMOOTH == qualifier) || (QUAL_NOPERSPECTIVE == qualifier) || (QUAL_FLAT == qualifier) || |
| (QUAL_INVARIANT == qualifier) || (QUAL_CENTROID == qualifier) || (QUAL_SAMPLE == qualifier))) |
| { |
| result = false; |
| } |
| break; |
| case GEOMETRY_SHADER: |
| if (QUAL_PATCH == qualifier) |
| { |
| result = false; |
| } |
| break; |
| case TESS_CTRL_SHADER: |
| if ((INPUT == storage) && (QUAL_PATCH == qualifier)) |
| { |
| result = false; |
| } |
| break; |
| case TESS_EVAL_SHADER: |
| if ((OUTPUT == storage) && (QUAL_PATCH == qualifier)) |
| { |
| result = false; |
| } |
| break; |
| default: |
| break; |
| } |
| |
| return result; |
| } |
| |
| /** Get string for qualifier |
| * |
| * @param qualifier Qualifier |
| * |
| * @return A string for given qualifier |
| **/ |
| const GLchar* Utils::getQualifierString(Utils::QUALIFIERS qualifier) |
| { |
| const GLchar* result = 0; |
| switch (qualifier) |
| { |
| case QUAL_NONE: |
| result = ""; |
| break; |
| case QUAL_CONST: |
| result = "const"; |
| break; |
| case QUAL_IN: |
| result = "in"; |
| break; |
| case QUAL_OUT: |
| result = "out"; |
| break; |
| case QUAL_INOUT: |
| result = "inout"; |
| break; |
| case QUAL_UNIFORM: |
| result = "uniform"; |
| break; |
| case QUAL_PATCH: |
| result = "patch"; |
| break; |
| case QUAL_CENTROID: |
| result = "centroid"; |
| break; |
| case QUAL_SAMPLE: |
| result = "sample"; |
| break; |
| case QUAL_FLAT: |
| result = "flat"; |
| break; |
| case QUAL_NOPERSPECTIVE: |
| result = "noperspective"; |
| break; |
| case QUAL_SMOOTH: |
| result = "smooth"; |
| break; |
| case QUAL_LOCATION: |
| result = "layout (location = LOC_VALUE)"; |
| break; |
| case QUAL_LOWP: |
| result = "lowp"; |
| break; |
| case QUAL_MEDIUMP: |
| result = "mediump"; |
| break; |
| case QUAL_HIGHP: |
| result = "highp"; |
| break; |
| case QUAL_PRECISE: |
| result = "precise"; |
| break; |
| case QUAL_INVARIANT: |
| result = "invariant"; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| }; |
| |
| return result; |
| } |
| |
| /** Returns a string with set of qualifiers. |
| * |
| * @param qualifiers Set of qualifiers |
| * |
| * @return String |
| **/ |
| std::string Utils::getQualifiersListString(const qualifierSet& qualifiers) |
| { |
| static const GLchar* qualifier_list = "QUALIFIER QUALIFIER_LIST"; |
| const GLuint qualifier_list_length = static_cast<GLuint>(strlen(qualifier_list)); |
| |
| /* Tokens */ |
| static const GLchar* token_qualifier = "QUALIFIER"; |
| static const GLchar* token_qual_list = "QUALIFIER_LIST"; |
| |
| /* Variables */ |
| std::string list = token_qual_list; |
| size_t position = 0; |
| |
| /* Replace tokens */ |
| for (GLuint i = 0; i < qualifiers.size(); ++i) |
| { |
| Utils::replaceToken(token_qual_list, position, qualifier_list, list); |
| position -= qualifier_list_length; |
| |
| const GLchar* qualifier_str = getQualifierString(qualifiers[i]); |
| |
| Utils::replaceToken(token_qualifier, position, qualifier_str, list); |
| } |
| |
| Utils::replaceToken(token_qual_list, position, "", list); |
| |
| return list; |
| } |
| |
| /** Prepare a set of qualifiers for given shader stage and variable storage. |
| * Filters out not supported qualifiers from in_qualifiers |
| * |
| * @param in_qualifiers Origiranl set of qualifiers |
| * @param stage Shader stage |
| * @param storage Variable storage |
| * |
| * @return Set of qualifiers |
| **/ |
| Utils::qualifierSet Utils::prepareQualifiersSet(const qualifierSet& in_qualifiers, SHADER_STAGES stage, |
| VARIABLE_STORAGE storage) |
| { |
| qualifierSet result; |
| |
| for (GLuint i = 0; i < in_qualifiers.size(); ++i) |
| { |
| Utils::QUALIFIERS qualifier = in_qualifiers[i]; |
| |
| if (false == doesStageSupportQualifier(stage, storage, qualifier)) |
| { |
| continue; |
| }; |
| |
| /* Replace wrong storage qualifiers */ |
| if ((Utils::INPUT == storage) && ((Utils::QUAL_UNIFORM == qualifier) || (Utils::QUAL_OUT == qualifier))) |
| { |
| qualifier = QUAL_IN; |
| } |
| else if ((Utils::OUTPUT == storage) && ((Utils::QUAL_IN == qualifier) || (Utils::QUAL_UNIFORM == qualifier))) |
| { |
| qualifier = QUAL_OUT; |
| } |
| else if ((Utils::UNIFORM == storage) && ((Utils::QUAL_IN == qualifier) || (Utils::QUAL_OUT == qualifier))) |
| { |
| qualifier = QUAL_UNIFORM; |
| } |
| |
| result.push_back(qualifier); |
| } |
| |
| return result; |
| } |
| |
| /** Get image type for given texture type |
| * |
| * @param type Texture type |
| * |
| * @return String representing sampler type |
| **/ |
| const GLchar* Utils::getImageType(Utils::TEXTURE_TYPES type) |
| { |
| const GLchar* result = 0; |
| |
| switch (type) |
| { |
| case TEX_BUFFER: |
| result = "imageBuffer"; |
| break; |
| case TEX_2D: |
| result = "image2D"; |
| break; |
| case TEX_2D_RECT: |
| result = "image2DRect"; |
| break; |
| case TEX_2D_ARRAY: |
| result = "image2DArray"; |
| break; |
| case TEX_3D: |
| result = "image3D"; |
| break; |
| case TEX_CUBE: |
| result = "imageCube"; |
| break; |
| case TEX_1D: |
| result = "image1D"; |
| break; |
| case TEX_1D_ARRAY: |
| result = "image1DArray"; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| return result; |
| } |
| |
| /** Get number of coordinates required to address texture of given type |
| * |
| * @param type Type of texture |
| * |
| * @return Number of coordinates |
| **/ |
| GLuint Utils::getNumberOfCoordinates(Utils::TEXTURE_TYPES type) |
| { |
| GLuint result = 0; |
| |
| switch (type) |
| { |
| case TEX_BUFFER: |
| result = 1; |
| break; |
| case TEX_2D: |
| result = 2; |
| break; |
| case TEX_2D_RECT: |
| result = 2; |
| break; |
| case TEX_2D_ARRAY: |
| result = 3; |
| break; |
| case TEX_3D: |
| result = 3; |
| break; |
| case TEX_CUBE: |
| result = 3; |
| break; |
| case TEX_1D: |
| result = 1; |
| break; |
| case TEX_1D_ARRAY: |
| result = 2; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| return result; |
| } |
| |
| /** Get sampler type for given texture type |
| * |
| * @param type Texture type |
| * |
| * @return String representing sampler type |
| **/ |
| const GLchar* Utils::getSamplerType(Utils::TEXTURE_TYPES type) |
| { |
| const GLchar* result = 0; |
| |
| switch (type) |
| { |
| case TEX_BUFFER: |
| result = "samplerBuffer"; |
| break; |
| case TEX_2D: |
| result = "sampler2D"; |
| break; |
| case TEX_2D_RECT: |
| result = "sampler2DRect"; |
| break; |
| case TEX_2D_ARRAY: |
| result = "sampler2DArray"; |
| break; |
| case TEX_3D: |
| result = "sampler3D"; |
| break; |
| case TEX_CUBE: |
| result = "samplerCube"; |
| break; |
| case TEX_1D: |
| result = "sampler1D"; |
| break; |
| case TEX_1D_ARRAY: |
| result = "sampler1DArray"; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| return result; |
| } |
| |
| /** Get target for given texture type |
| * |
| * @param type Type of texture |
| * |
| * @return Target |
| **/ |
| GLenum Utils::getTextureTartet(Utils::TEXTURE_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; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| return result; |
| } |
| |
| /** Get name of given texture type |
| * |
| * @param type Texture type |
| * |
| * @return String representing name of texture type |
| **/ |
| const GLchar* Utils::getTextureTypeName(Utils::TEXTURE_TYPES type) |
| { |
| const GLchar* result = 0; |
| |
| switch (type) |
| { |
| case TEX_BUFFER: |
| result = "buffer"; |
| break; |
| case TEX_2D: |
| result = "2D"; |
| break; |
| case TEX_2D_RECT: |
| result = "2D rectangle"; |
| break; |
| case TEX_2D_ARRAY: |
| result = "2D array"; |
| break; |
| case TEX_3D: |
| result = "3D"; |
| break; |
| case TEX_CUBE: |
| result = "cube"; |
| break; |
| case TEX_1D: |
| result = "1D"; |
| break; |
| case TEX_1D_ARRAY: |
| result = "1D array"; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| return result; |
| } |
| |
| /** Check if glsl support matrices for specific basic type |
| * |
| * @param type Basic type |
| * |
| * @return true if matrices of <type> are supported, false otherwise |
| **/ |
| bool Utils::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("Invliad enum"); |
| } |
| |
| return result; |
| } |
| |
| /** Get string representing name of shader stage |
| * |
| * @param stage Shader stage |
| * |
| * @return String with name of shader stage |
| **/ |
| const glw::GLchar* Utils::getShaderStageName(Utils::SHADER_STAGES stage) |
| { |
| const GLchar* result = 0; |
| |
| switch (stage) |
| { |
| case COMPUTE_SHADER: |
| result = "compute"; |
| break; |
| case VERTEX_SHADER: |
| result = "vertex"; |
| break; |
| case TESS_CTRL_SHADER: |
| result = "tesselation control"; |
| break; |
| case TESS_EVAL_SHADER: |
| result = "tesselation evaluation"; |
| break; |
| case GEOMETRY_SHADER: |
| result = "geomtery"; |
| break; |
| case FRAGMENT_SHADER: |
| result = "fragment"; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| return result; |
| } |
| |
| /** Get glsl name of specified type |
| * |
| * @param type Basic type |
| * @param n_columns Number of columns |
| * @param n_rows Number of rows |
| * |
| * @return Name of glsl type |
| **/ |
| const glw::GLchar* Utils::getTypeName(TYPES type, glw::GLuint n_columns, glw::GLuint n_rows) |
| { |
| 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 > n_columns) || (1 > n_rows) || (4 < n_columns) || (4 < n_rows)) |
| { |
| return 0; |
| } |
| |
| switch (type) |
| { |
| case FLOAT: |
| result = float_lut[n_columns - 1][n_rows - 1]; |
| break; |
| case DOUBLE: |
| result = double_lut[n_columns - 1][n_rows - 1]; |
| break; |
| case INT: |
| result = int_lut[n_rows - 1]; |
| break; |
| case UINT: |
| result = uint_lut[n_rows - 1]; |
| break; |
| default: |
| TCU_FAIL("Invliad enum"); |
| } |
| |
| return result; |
| } |
| |
| /** Get proper glUniformNdv routine for vectors with specified number of rows |
| * |
| * @param gl GL functions |
| * @param n_rows Number of rows |
| * |
| * @return Function address |
| **/ |
| Utils::uniformNdv Utils::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 |
| **/ |
| Utils::uniformNfv Utils::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 |
| **/ |
| Utils::uniformNiv Utils::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 |
| **/ |
| Utils::uniformNuiv Utils::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 |
| **/ |
| Utils::uniformMatrixNdv Utils::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 |
| **/ |
| Utils::uniformMatrixNfv Utils::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; |
| } |
| |
| /** Prepare definition of input or output block's variable |
| * |
| * @param qualifiers Set of qualifiers |
| * @param type_name Name of type |
| * @param variable_name Meaningful part of variable name, eg. tex_coord |
| * |
| * @return Definition of variable |
| **/ |
| std::string Utils::getBlockVariableDefinition(const qualifierSet& qualifiers, const glw::GLchar* type_name, |
| const glw::GLchar* variable_name) |
| { |
| /* Templates */ |
| static const GLchar* def_template = "QUALIFIER_LISTTYPE VARIABLE_NAME"; |
| |
| /* Tokens */ |
| static const GLchar* token_type = "TYPE"; |
| static const GLchar* token_variable_name = "VARIABLE_NAME"; |
| static const GLchar* token_qual_list = "QUALIFIER_LIST"; |
| |
| /* Variables */ |
| std::string variable_definition = def_template; |
| size_t position = 0; |
| |
| /* Get qualifiers list */ |
| const std::string& list = getQualifiersListString(qualifiers); |
| |
| /* Replace tokens */ |
| Utils::replaceToken(token_qual_list, position, list.c_str(), variable_definition); |
| Utils::replaceToken(token_type, position, type_name, variable_definition); |
| Utils::replaceToken(token_variable_name, position, variable_name, variable_definition); |
| |
| /* Done */ |
| return variable_definition; |
| } |
| |
| /** Prepare reference to input or output variable |
| * |
| * @param flavour "Flavour" of variable |
| * @param variable_name Meaningful part of variable name, eg. tex_coord |
| * @param block_name Name of block |
| * |
| * @return Reference to variable |
| **/ |
| std::string Utils::getBlockVariableReference(VARIABLE_FLAVOUR flavour, const glw::GLchar* variable_name, |
| const glw::GLchar* block_name) |
| { |
| /* Templates */ |
| static const GLchar* ref_template = "BLOCK_NAME.VARIABLE_NAME"; |
| static const GLchar* array_ref_template = "BLOCK_NAME[0].VARIABLE_NAME"; |
| static const GLchar* tcs_ref_template = "BLOCK_NAME[gl_InvocationID].VARIABLE_NAME"; |
| |
| /* Token */ |
| static const GLchar* token_block_name = "BLOCK_NAME"; |
| static const GLchar* token_variable_name = "VARIABLE_NAME"; |
| |
| /* Variables */ |
| std::string variable_definition; |
| size_t position = 0; |
| |
| /* Select variable reference template */ |
| switch (flavour) |
| { |
| case BASIC: |
| variable_definition = ref_template; |
| break; |
| case ARRAY: |
| variable_definition = array_ref_template; |
| break; |
| case INDEXED_BY_INVOCATION_ID: |
| variable_definition = tcs_ref_template; |
| break; |
| default: |
| variable_definition = ref_template; |
| break; |
| } |
| |
| /* Replace tokens */ |
| replaceAllTokens(token_block_name, block_name, variable_definition); |
| replaceToken(token_variable_name, position, variable_name, variable_definition); |
| |
| /* Done */ |
| return variable_definition; |
| } |
| |
| /** Prepare definition of input or output variable |
| * |
| * @param flavour "Flavour" of variable |
| * @param qualifiers Set of qualifiers |
| * @param type_name Name of type |
| * @param variable_name Meaningful part of variable name, eg. tex_coord |
| * |
| * @return Definition of variable |
| **/ |
| std::string Utils::getVariableDefinition(VARIABLE_FLAVOUR flavour, const qualifierSet& qualifiers, |
| const glw::GLchar* type_name, const glw::GLchar* variable_name) |
| { |
| /* Templates */ |
| static const GLchar* def_template = "QUALIFIER_LISTTYPE VARIABLE_NAME"; |
| static const GLchar* def_array_template = "QUALIFIER_LISTTYPE VARIABLE_NAME[]"; |
| |
| /* Tokens */ |
| static const GLchar* token_type = "TYPE"; |
| static const GLchar* token_variable_name = "VARIABLE_NAME"; |
| static const GLchar* token_qual_list = "QUALIFIER_LIST"; |
| |
| /* Variables */ |
| std::string variable_definition; |
| size_t position = 0; |
| |
| /* Select variable definition template */ |
| switch (flavour) |
| { |
| case BASIC: |
| variable_definition = def_template; |
| break; |
| case ARRAY: |
| case INDEXED_BY_INVOCATION_ID: |
| variable_definition = def_array_template; |
| break; |
| default: |
| TCU_FAIL("Invliad enum"); |
| break; |
| } |
| |
| /* Get qualifiers list */ |
| const std::string& list = getQualifiersListString(qualifiers); |
| |
| /* Replace tokens */ |
| replaceToken(token_qual_list, position, list.c_str(), variable_definition); |
| replaceToken(token_type, position, type_name, variable_definition); |
| replaceToken(token_variable_name, position, variable_name, variable_definition); |
| |
| /* Done */ |
| return variable_definition; |
| } |
| |
| /** Get "flavour" of variable |
| * |
| * @param stage Shader stage |
| * @param storage Storage of variable |
| * @param qualifiers Set of qualifiers for variable |
| * |
| * @return "Flavour" of variable |
| **/ |
| Utils::VARIABLE_FLAVOUR Utils::getVariableFlavour(SHADER_STAGES stage, VARIABLE_STORAGE storage, |
| const qualifierSet& qualifiers) |
| { |
| VARIABLE_FLAVOUR result; |
| |
| if (UNIFORM == storage) |
| { |
| result = BASIC; |
| } |
| else |
| { |
| switch (stage) |
| { |
| case Utils::GEOMETRY_SHADER: |
| if (Utils::INPUT == storage) |
| { |
| result = ARRAY; |
| } |
| else /* OUTPUT */ |
| { |
| result = BASIC; |
| } |
| break; |
| case Utils::TESS_EVAL_SHADER: |
| if ((false == Utils::doesContainQualifier(Utils::QUAL_PATCH, qualifiers)) && (Utils::INPUT == storage)) |
| { |
| result = ARRAY; |
| } |
| else /* OUTPUT */ |
| { |
| result = BASIC; |
| } |
| break; |
| case Utils::TESS_CTRL_SHADER: |
| if ((true == Utils::doesContainQualifier(Utils::QUAL_PATCH, qualifiers)) && (Utils::OUTPUT == storage)) |
| { |
| result = BASIC; |
| } |
| else |
| { |
| result = INDEXED_BY_INVOCATION_ID; |
| } |
| break; |
| case Utils::VERTEX_SHADER: |
| case Utils::FRAGMENT_SHADER: |
| result = BASIC; |
| break; |
| default: |
| TCU_FAIL("Invliad enum"); |
| break; |
| } |
| } |
| |
| return result; |
| } |
| |
| /** Prepare name of input or output variable |
| * |
| * @param stage Shader stage |
| * @param storage Storage of variable |
| * @param variable_name Meaningful part of variable name, eg. tex_coord |
| * |
| * @return Name of variable |
| **/ |
| std::string Utils::getVariableName(SHADER_STAGES stage, VARIABLE_STORAGE storage, const glw::GLchar* variable_name) |
| { |
| /* Variable name template */ |
| static const GLchar* variable_name_template = "PRECEEDING_PREFIX_VARIABLE_NAME"; |
| |
| /* Tokens */ |
| static const GLchar* token_preceeding = "PRECEEDING"; |
| static const GLchar* token_prefix = "PREFIX"; |
| static const GLchar* token_variable_name = "VARIABLE_NAME"; |
| |
| static const GLchar* prefixes[Utils::STORAGE_MAX][Utils::SHADER_STAGES_MAX][2] = { |
| /* COMPUTE, VERTEX, TCS, TES, GEOMETRY, FRAGMENT */ |
| { { "", "" }, |
| { "in", "vs" }, |
| { "vs", "tcs" }, |
| { "tcs", "tes" }, |
| { "tes", "gs" }, |
| { "gs", "fs" } }, /* INPUT */ |
| { { "", "" }, |
| { "vs", "tcs" }, |
| { "tcs", "tes" }, |
| { "tes", "gs" }, |
| { "gs", "fs" }, |
| { "fs", "out" } }, /* OUTPUT */ |
| { { "uni", "comp" }, |
| { "uni", "vs" }, |
| { "uni", "tcs" }, |
| { "uni", "tes" }, |
| { "uni", "gs" }, |
| { "uni", "fs" } } /* UNIFORM */ |
| }; |
| |
| /* Variables */ |
| const GLchar* preceeding = prefixes[storage][stage][0]; |
| const GLchar* prefix = prefixes[storage][stage][1]; |
| std::string name = variable_name_template; |
| size_t position = 0; |
| |
| /* Replace tokens */ |
| Utils::replaceToken(token_preceeding, position, preceeding, name); |
| Utils::replaceToken(token_prefix, position, prefix, name); |
| Utils::replaceToken(token_variable_name, position, variable_name, name); |
| |
| /* Done */ |
| return name; |
| } |
| |
| /** Prepare reference to input or output variable |
| * |
| * @param flavour "Flavour" of variable |
| * @param variable_name Meaningful part of variable name, eg. tex_coord |
| * |
| * @return Reference to variable |
| **/ |
| std::string Utils::getVariableReference(VARIABLE_FLAVOUR flavour, const glw::GLchar* variable_name) |
| { |
| /* Templates */ |
| static const GLchar* ref_template = "VARIABLE_NAME"; |
| static const GLchar* array_ref_template = "VARIABLE_NAME[0]"; |
| static const GLchar* tcs_ref_template = "VARIABLE_NAME[gl_InvocationID]"; |
| |
| /* Token */ |
| static const GLchar* token_variable_name = "VARIABLE_NAME"; |
| |
| /* Variables */ |
| std::string variable_definition; |
| size_t position = 0; |
| |
| /* Select variable reference template */ |
| switch (flavour) |
| { |
| case BASIC: |
| variable_definition = ref_template; |
| break; |
| case ARRAY: |
| variable_definition = array_ref_template; |
| break; |
| case INDEXED_BY_INVOCATION_ID: |
| variable_definition = tcs_ref_template; |
| break; |
| default: |
| variable_definition = ref_template; |
| break; |
| } |
| |
| /* Replace token */ |
| Utils::replaceToken(token_variable_name, position, variable_name, variable_definition); |
| |
| /* Done */ |
| return variable_definition; |
| } |
| |
| /** Prepare definition and reference string for block varaible |
| * |
| * @param in_stage Shader stage |
| * @param in_storage Storage of variable |
| * @param in_qualifiers Set of qualifiers |
| * @param in_type_name Type name |
| * @param in_variable_name Meaningful part of variable name, like "color" |
| * @param in_block_name Name of block, like "input" |
| * @param out_definition Definition string |
| * @param out_reference Reference string |
| **/ |
| void Utils::prepareBlockVariableStrings(Utils::SHADER_STAGES in_stage, Utils::VARIABLE_STORAGE in_storage, |
| const Utils::qualifierSet& in_qualifiers, const glw::GLchar* in_type_name, |
| const glw::GLchar* in_variable_name, const glw::GLchar* in_block_name, |
| std::string& out_definition, std::string& out_reference) |
| { |
| VARIABLE_FLAVOUR flavour = getVariableFlavour(in_stage, in_storage, in_qualifiers); |
| const qualifierSet& qualifiers = prepareQualifiersSet(in_qualifiers, in_stage, in_storage); |
| const std::string& name = getVariableName(in_stage, in_storage, in_variable_name); |
| |
| out_definition = getBlockVariableDefinition(qualifiers, in_type_name, name.c_str()); |
| out_reference = getBlockVariableReference(flavour, name.c_str(), in_block_name); |
| } |
| |
| /** Prepare definition and reference string for block varaible |
| * |
| * @param in_stage Shader stage |
| * @param in_storage Storage of variable |
| * @param in_qualifiers Set of qualifiers |
| * @param in_type_name Type name |
| * @param in_variable_name Meaningful part of variable name, like "color" |
| * @param out_definition Definition string |
| * @param out_reference Reference string |
| **/ |
| void Utils::prepareVariableStrings(Utils::SHADER_STAGES in_stage, Utils::VARIABLE_STORAGE in_storage, |
| const Utils::qualifierSet& in_qualifiers, const glw::GLchar* in_type_name, |
| const glw::GLchar* in_variable_name, std::string& out_definition, |
| std::string& out_reference) |
| { |
| VARIABLE_FLAVOUR flavour = getVariableFlavour(in_stage, in_storage, in_qualifiers); |
| const qualifierSet& qualifiers = prepareQualifiersSet(in_qualifiers, in_stage, in_storage); |
| const std::string& name = getVariableName(in_stage, in_storage, in_variable_name); |
| |
| out_definition = getVariableDefinition(flavour, qualifiers, in_type_name, name.c_str()); |
| out_reference = getVariableReference(flavour, name.c_str()); |
| } |
| |
| /** Returns string with UTF8 character for current test case |
| * |
| * @return String with UTF8 character |
| **/ |
| const GLchar* Utils::getUtf8Character(Utils::UTF8_CHARACTERS character) |
| { |
| static const unsigned char two_bytes[] = { 0xd7, 0x84, 0x00 }; |
| static const unsigned char three_bytes[] = { 0xe3, 0x82, 0x81, 0x00 }; |
| static const unsigned char four_bytes[] = { 0xf0, 0x93, 0x83, 0x93, 0x00 }; |
| static const unsigned char five_bytes[] = { 0xfa, 0x82, 0x82, 0x82, 0x82, 0x00 }; |
| static const unsigned char six_bytes[] = { 0xfd, 0x82, 0x82, 0x82, 0x82, 0x82, 0x00 }; |
| static const unsigned char redundant_bytes[] = { 0xf2, 0x80, 0x80, 0x5e, 0x00 }; |
| |
| const GLchar* result = 0; |
| |
| switch (character) |
| { |
| case TWO_BYTES: |
| result = (const GLchar*)two_bytes; |
| break; |
| case THREE_BYTES: |
| result = (const GLchar*)three_bytes; |
| break; |
| case FOUR_BYTES: |
| result = (const GLchar*)four_bytes; |
| break; |
| case FIVE_BYTES: |
| result = (const GLchar*)five_bytes; |
| break; |
| case SIX_BYTES: |
| result = (const GLchar*)six_bytes; |
| break; |
| case REDUNDANT_ASCII: |
| result = (const GLchar*)redundant_bytes; |
| break; |
| case EMPTY: |
| result = ""; |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| } |
| |
| 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 Utils::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 Utils::isGLVersionAtLeast(const glw::Functions& gl, glw::GLint required_major, glw::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 Utils::replaceToken(const glw::GLchar* token, size_t& search_position, const glw::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); |
| |
| 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 Utils::replaceAllTokens(const glw::GLchar* token, const glw::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); |
| } |
| } |
| |
| /** Constructor |
| * |
| * @param context Test context |
| * @param test_name Test name |
| * @param test_description Test description |
| **/ |
| TestBase::TestBase(deqp::Context& context, const glw::GLchar* test_name, const glw::GLchar* test_description) |
| : TestCase(context, test_name, test_description) |
| , m_is_compute_shader_supported(false) |
| , m_is_explicit_uniform_location(false) |
| , m_is_shader_language_420pack(false) |
| { |
| /* Nothing to be done here */ |
| } |
| |
| /** Execute test |
| * |
| * @return tcu::TestNode::CONTINUE after executing test case, tcu::TestNode::STOP otherwise |
| **/ |
| tcu::TestNode::IterateResult TestBase::iterate() |
| { |
| /* GL entry points */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Check extension support and version */ |
| m_is_explicit_uniform_location = Utils::isExtensionSupported(m_context, "GL_ARB_explicit_uniform_location"); |
| m_is_shader_language_420pack = Utils::isExtensionSupported(m_context, "GL_ARB_shading_language_420pack"); |
| m_is_compute_shader_supported = Utils::isGLVersionAtLeast(gl, 4, 3); |
| |
| /* Execute test */ |
| bool test_result = test(); |
| |
| /* 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; |
| } |
| |
| /** Basic implementation of getShaderSourceConfig method. |
| * |
| * @param out_n_parts Number of source parts used by this test case |
| * @param out_use_lengths If source lengths shall be provided to compiler |
| **/ |
| void TestBase::getShaderSourceConfig(glw::GLuint& out_n_parts, bool& out_use_lengths) |
| { |
| out_n_parts = 1; |
| out_use_lengths = false; |
| } |
| |
| /** Basic implementation of prepareNextTestCase method. |
| * |
| * @param test_case_index Index of test case |
| * |
| * @return true if index is -1 or 0, false otherwise |
| **/ |
| bool TestBase::prepareNextTestCase(GLuint test_case_index) |
| { |
| if (((GLuint)-1 == test_case_index) || (0 == test_case_index)) |
| { |
| return true; |
| } |
| else |
| { |
| return false; |
| } |
| } |
| |
| /** Basic implementation of prepareUniforms method |
| * |
| * @param ignored |
| **/ |
| void TestBase::prepareUniforms(Utils::program& /* program */) |
| { |
| /* Nothing to be done */ |
| } |
| |
| /** Basic implementation of testInit method |
| * |
| * @return true if test can be executed, false otherwise |
| **/ |
| bool TestBase::testInit() |
| { |
| return true; |
| } |
| |
| /** Get layout specific for given stage |
| * |
| * @param stage Shader stage |
| * |
| * @return Stage specific part |
| **/ |
| const GLchar* TestBase::getStageSpecificLayout(Utils::SHADER_STAGES stage) const |
| { |
| static const GLchar* stage_layout_geometry = "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n"; |
| static const GLchar* stage_layout_tess_ctrl = "layout(vertices = 1) out;\n"; |
| static const GLchar* stage_layout_tess_eval = "layout(isolines, point_mode) in;\n"; |
| |
| const GLchar* result = ""; |
| |
| switch (stage) |
| { |
| case Utils::GEOMETRY_SHADER: |
| result = stage_layout_geometry; |
| break; |
| case Utils::TESS_CTRL_SHADER: |
| result = stage_layout_tess_ctrl; |
| break; |
| case Utils::TESS_EVAL_SHADER: |
| result = stage_layout_tess_eval; |
| break; |
| case Utils::VERTEX_SHADER: |
| case Utils::FRAGMENT_SHADER: |
| default: |
| break; |
| } |
| |
| return result; |
| } |
| |
| /** Get "version" string |
| * |
| * @param stage Shader stage, compute shader will use 430 |
| * @param use_version_400 Select if 400 or 420 should be used |
| * |
| * @return Version string |
| **/ |
| const GLchar* TestBase::getVersionString(Utils::SHADER_STAGES stage, bool use_version_400) const |
| { |
| static const GLchar* version_400 = "#version 400\n" |
| "#extension GL_ARB_shading_language_420pack : require\n" |
| "#extension GL_ARB_separate_shader_objects : enable"; |
| static const GLchar* version_420 = "#version 420"; |
| static const GLchar* version_430 = "#version 430"; |
| |
| const GLchar* result = ""; |
| |
| if (Utils::COMPUTE_SHADER == stage) |
| { |
| result = version_430; |
| } |
| else if (true == use_version_400) |
| { |
| result = version_400; |
| } |
| else |
| { |
| result = version_420; |
| } |
| |
| return result; |
| } |
| |
| /** Initialize shaderSource instance, reserve storage and prepare shader source |
| * |
| * @param in_stage Shader stage |
| * @param in_use_version_400 If version 400 or 420 should be used |
| * @param out_source Shader source instance |
| **/ |
| void TestBase::initShaderSource(Utils::SHADER_STAGES in_stage, bool in_use_version_400, Utils::shaderSource& out_source) |
| { |
| /* Shader source configuration */ |
| glw::GLuint n_parts = 0; |
| bool use_lengths = false; |
| |
| getShaderSourceConfig(n_parts, use_lengths); |
| |
| out_source.m_parts.resize(n_parts); |
| out_source.m_use_lengths = use_lengths; |
| |
| /* Request child class to prepare shader sources */ |
| prepareShaderSource(in_stage, in_use_version_400, out_source); |
| |
| /* Prepare source lengths */ |
| if (true == use_lengths) |
| { |
| for (GLuint i = 0; i < n_parts; ++i) |
| { |
| out_source.m_parts[i].m_length = static_cast<glw::GLint>(out_source.m_parts[i].m_code.length()); |
| |
| out_source.m_parts[i].m_code.append("This should be ignored by compiler, as source length is provided"); |
| } |
| } |
| else |
| { |
| for (GLuint i = 0; i < n_parts; ++i) |
| { |
| out_source.m_parts[i].m_length = 0; |
| } |
| } |
| } |
| |
| /** Execute test |
| * |
| * @return true if test pass, false otherwise |
| **/ |
| bool TestBase::test() |
| { |
| bool result = true; |
| GLuint test_case_index = 0; |
| |
| /* Prepare test cases */ |
| testInit(); |
| |
| /* GL entry points */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Tesselation patch set up */ |
| gl.patchParameteri(GL_PATCH_VERTICES, 1); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "PatchParameteri"); |
| |
| while (true == prepareNextTestCase(test_case_index)) |
| { |
| bool case_result = true; |
| |
| /* Execute drawing case */ |
| if (false == testDrawArray(false)) |
| { |
| case_result = false; |
| } |
| |
| if (true == m_is_shader_language_420pack) |
| { |
| if (false == testDrawArray(true)) |
| { |
| case_result = false; |
| } |
| } |
| |
| /* Execute compute shader case */ |
| if (true == m_is_compute_shader_supported) |
| { |
| if (false == testCompute()) |
| { |
| case_result = false; |
| } |
| } |
| |
| /* Log failure */ |
| if (false == case_result) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "Test case failed." |
| << tcu::TestLog::EndMessage; |
| |
| result = false; |
| } |
| |
| /* Go to next test case */ |
| test_case_index += 1; |
| } |
| |
| /* Done */ |
| return result; |
| } |
| |
| int TestBase::maxImageUniforms(Utils::SHADER_STAGES stage) const |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| GLint max_image_uniforms; |
| |
| switch (stage) |
| { |
| case Utils::COMPUTE_SHADER: |
| gl.getIntegerv(GL_MAX_COMPUTE_IMAGE_UNIFORMS, &max_image_uniforms); |
| break; |
| case Utils::FRAGMENT_SHADER: |
| gl.getIntegerv(GL_MAX_FRAGMENT_IMAGE_UNIFORMS, &max_image_uniforms); |
| break; |
| case Utils::GEOMETRY_SHADER: |
| gl.getIntegerv(GL_MAX_GEOMETRY_IMAGE_UNIFORMS, &max_image_uniforms); |
| break; |
| case Utils::TESS_CTRL_SHADER: |
| gl.getIntegerv(GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS, &max_image_uniforms); |
| break; |
| case Utils::TESS_EVAL_SHADER: |
| gl.getIntegerv(GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS, &max_image_uniforms); |
| break; |
| case Utils::VERTEX_SHADER: |
| gl.getIntegerv(GL_MAX_VERTEX_IMAGE_UNIFORMS, &max_image_uniforms); |
| break; |
| default: |
| TCU_FAIL("Invalid enum"); |
| break; |
| } |
| return max_image_uniforms; |
| } |
| |
| /** Constructor |
| * |
| * @param context Test context |
| * @param test_name Name of test |
| * @param test_description Description of test |
| **/ |
| APITestBase::APITestBase(deqp::Context& context, const glw::GLchar* test_name, const glw::GLchar* test_description) |
| : TestBase(context, test_name, test_description) |
| { |
| /* Nothing to be done here */ |
| } |
| |
| /** Execute test with compute shader |
| * |
| * @return true if test pass, false otherwise |
| **/ |
| bool APITestBase::testCompute() |
| { |
| /* GL objects */ |
| Utils::program program(m_context); |
| |
| /* Shaders */ |
| Utils::shaderSource compute_shader; |
| initShaderSource(Utils::COMPUTE_SHADER, false, compute_shader); |
| |
| /* Check if test support compute shaders */ |
| if (true == compute_shader.m_parts[0].m_code.empty()) |
| { |
| return true; |
| } |
| |
| /* Build program */ |
| try |
| { |
| program.build(compute_shader, 0 /* fragment shader */, 0 /* geometry shader */, |
| 0 /* tesselation control shader */, 0 /* tesselation evaluation shader */, 0 /* vertex shader */, |
| 0 /* varying names */, 0 /* n varying names */, false); |
| } |
| catch (Utils::shaderCompilationException& exc) |
| { |
| /* Something wrong with compilation, test case failed */ |
| tcu::MessageBuilder message = m_context.getTestContext().getLog() << tcu::TestLog::Message; |
| |
| message << "Shader compilation failed. Error message: " << exc.m_error_message; |
| |
| Utils::program::printShaderSource(exc.m_shader_source, message); |
| |
| message << tcu::TestLog::EndMessage; |
| |
| return false; |
| } |
| catch (Utils::programLinkageException& exc) |
| { |
| /* Something wrong with linking, test case failed */ |
| m_context.getTestContext().getLog() << tcu::TestLog::Message |
| << "Program linking failed. Error message: " << exc.m_error_message |
| << tcu::TestLog::EndMessage; |
| return false; |
| } |
| |
| /* Set current program */ |
| program.use(); |
| |
| /* Return result of verification */ |
| return checkResults(program); |
| } |
| |
| /** Execute test with VS, TCS, TES, GS and FS |
| * |
| * @param use_version_400 Select if 400 or 420 should be used |
| * |
| * @return true if test pass, false otherwise |
| **/ |
| bool APITestBase::testDrawArray(bool use_version_400) |
| { |
| /* GL objects */ |
| Utils::program program(m_context); |
| |
| /* Shaders */ |
| Utils::shaderSource fragment_data; |
| Utils::shaderSource geometry_data; |
| Utils::shaderSource tess_ctrl_data; |
| Utils::shaderSource tess_eval_data; |
| Utils::shaderSource vertex_data; |
| |
| initShaderSource(Utils::FRAGMENT_SHADER, use_version_400, fragment_data); |
| initShaderSource(Utils::GEOMETRY_SHADER, use_version_400, geometry_data); |
| initShaderSource(Utils::TESS_CTRL_SHADER, use_version_400, tess_ctrl_data); |
| initShaderSource(Utils::TESS_EVAL_SHADER, use_version_400, tess_eval_data); |
| initShaderSource(Utils::VERTEX_SHADER, use_version_400, vertex_data); |
| |
| /* Build program */ |
| try |
| { |
| program.build(0 /* compute shader */, fragment_data, geometry_data, tess_ctrl_data, tess_eval_data, vertex_data, |
| 0 /* varying names */, 0 /* n varying names */, false); |
| } |
| catch (Utils::shaderCompilationException& exc) |
| { |
| /* Something wrong with compilation, test case failed */ |
| tcu::MessageBuilder message = m_context.getTestContext().getLog() << tcu::TestLog::Message; |
| |
| message << "Shader compilation failed. Error message: " << exc.m_error_message; |
| |
| Utils::program::printShaderSource(exc.m_shader_source, message); |
| |
| message << tcu::TestLog::EndMessage; |
| |
| return false; |
| } |
| catch (Utils::programLinkageException& exc) |
| { |
| /* Something wrong with linking, test case failed */ |
| m_context.getTestContext().getLog() << tcu::TestLog::Message |
| << "Program linking failed. Error message: " << exc.m_error_message |
| << tcu::TestLog::EndMessage; |
| return false; |
| } |
| |
| /* Set current program */ |
| program.use(); |
| |
| /* Return result of verification */ |
| return checkResults(program); |
| } |
| |
| /* Constants used by GLSLTestBase */ |
| const glw::GLenum GLSLTestBase::m_color_texture_internal_format = GL_RGBA8; |
| const glw::GLenum GLSLTestBase::m_color_texture_format = GL_RGBA; |
| const glw::GLenum GLSLTestBase::m_color_texture_type = GL_UNSIGNED_BYTE; |
| const glw::GLuint GLSLTestBase::m_color_texture_width = 16; |
| const glw::GLuint GLSLTestBase::m_color_texture_height = 16; |
| |
| /** Constructor |
| * |
| * @param context Test context |
| * @param test_name Test name |
| * @param test_description Test description |
| **/ |
| GLSLTestBase::GLSLTestBase(deqp::Context& context, const glw::GLchar* test_name, const glw::GLchar* test_description) |
| : TestBase(context, test_name, test_description) |
| { |
| /* Nothing to be done here */ |
| } |
| |
| /** Basic implementation of prepareSourceTexture method. |
| * |
| * @param ignored Texture instance |
| * |
| * @return 0 |
| **/ |
| const GLchar* GLSLTestBase::prepareSourceTexture(Utils::texture&) |
| { |
| return 0; |
| } |
| |
| /** Basic implementation of prepareVertexBuffer method. |
| * |
| * @param ignored Program instance |
| * @param ignored Buffer instance |
| * @param vao VertexArray instance |
| * |
| * @return 0 |
| **/ |
| void GLSLTestBase::prepareVertexBuffer(const Utils::program&, Utils::buffer&, Utils::vertexArray& vao) |
| { |
| vao.generate(); |
| vao.bind(); |
| } |
| |
| /** Basic implementation of verifyAdditionalResults |
| * |
| * @return true |
| **/ |
| bool GLSLTestBase::verifyAdditionalResults() const |
| { |
| return true; |
| } |
| |
| /** Basic implementation of releaseResource method |
| * |
| * @param ignored |
| **/ |
| void GLSLTestBase::releaseResource() |
| { |
| /* Nothing to be done */ |
| } |
| |
| /** Bind texture to first image unit and set image uniform to that unit |
| * |
| * @param program Program object |
| * @param texture Texture object |
| * @param uniform_name Name of image uniform |
| **/ |
| void GLSLTestBase::bindTextureToimage(Utils::program& program, Utils::texture& texture, |
| const glw::GLchar* uniform_name) const |
| { |
| /* GL entry points */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| gl.bindImageTexture(0 /* unit */, texture.m_id, 0 /* level */, GL_FALSE /* layered */, 0 /* layer */, GL_WRITE_ONLY, |
| GL_RGBA8); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture"); |
| |
| GLint location = program.getUniformLocation(uniform_name); |
| gl.uniform1i(location, 0); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i"); |
| } |
| |
| /** Bind texture to first texture unit and set sampler uniform to that unit |
| * |
| * @param program Program object |
| * @param texture Texture object |
| * @param uniform_name Name of sampler uniform |
| **/ |
| void GLSLTestBase::bindTextureToSampler(Utils::program& program, Utils::texture& texture, |
| const glw::GLchar* uniform_name) const |
| { |
| /* GL entry points */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| gl.activeTexture(GL_TEXTURE0); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "ActiveTexture"); |
| |
| texture.bind(); |
| |
| GLint location = program.getUniformLocation(uniform_name); |
| gl.uniform1i(location, 0); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Uniform1i"); |
| } |
| |
| /** Check contents of texture. It is expected that it will be filled with green color |
| * |
| * @param color_texture Texture that will be verified |
| * |
| * @return true if texture is all green, false otherwise |
| **/ |
| bool GLSLTestBase::checkResults(Utils::texture& color_texture) const |
| { |
| static const GLuint green_color = 0xff00ff00; |
| const GLuint texture_data_size = m_color_texture_width * m_color_texture_height; |
| std::vector<glw::GLuint> texture_data; |
| |
| texture_data.resize(texture_data_size); |
| |
| color_texture.get(m_color_texture_format, m_color_texture_type, &texture_data[0]); |
| |
| for (GLuint i = 0; i < texture_data_size; ++i) |
| { |
| if (green_color != texture_data[i]) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "Invalid texel: " << std::setbase(16) |
| << std::setfill('0') << std::setw(8) << texture_data[i] |
| << " at index: " << i << tcu::TestLog::EndMessage; |
| |
| return false; |
| } |
| } |
| |
| return verifyAdditionalResults(); |
| } |
| |
| /** Prepare framebuffer with texture used as attachment |
| * |
| * @param framebuffer Framebuffer |
| * @param color_texture Textue used as color attachment 0 |
| **/ |
| void GLSLTestBase::prepareFramebuffer(Utils::framebuffer& framebuffer, Utils::texture& color_texture) const |
| { |
| framebuffer.generate(); |
| |
| color_texture.create(m_color_texture_width, m_color_texture_height, m_color_texture_internal_format); |
| |
| framebuffer.attachTexture(GL_COLOR_ATTACHMENT0, color_texture.m_id, m_color_texture_width, m_color_texture_height); |
| |
| framebuffer.clearColor(0.0f, 0.0f, 0.0f, 0.0f); |
| framebuffer.clear(GL_COLOR_BUFFER_BIT); |
| } |
| |
| /** Prepare texture and bind it to image uniform |
| * |
| * @param framebuffer Framebuffer |
| * @param color_texture Textue used as color attachment 0 |
| **/ |
| void GLSLTestBase::prepareImage(Utils::program& program, Utils::texture& color_texture) const |
| { |
| color_texture.create(m_color_texture_width, m_color_texture_height, m_color_texture_internal_format); |
| |
| bindTextureToimage(program, color_texture, "uni_image"); |
| } |
| |
| /** Execute test with compute shader |
| * |
| * @return true if test pass, false otherwise |
| **/ |
| bool GLSLTestBase::testCompute() |
| { |
| /* Test Result */ |
| bool result = true; |
| |
| /* GL objects */ |
| Utils::texture color_tex(m_context); |
| Utils::program program(m_context); |
| Utils::texture source_tex(m_context); |
| |
| /* Shaders */ |
| Utils::shaderSource compute_shader; |
| initShaderSource(Utils::COMPUTE_SHADER, false, compute_shader); |
| |
| /* Check if test support compute shaders */ |
| if (true == compute_shader.m_parts[0].m_code.empty()) |
| { |
| return true; |
| } |
| |
| /* Build program */ |
| try |
| { |
| program.build(compute_shader, 0 /* fragment shader */, 0 /* geometry shader */, |
| 0 /* tesselation control shader */, 0 /* tesselation evaluation shader */, 0 /* vertex shader */, |
| 0 /* varying names */, 0 /* n varying names */, false); |
| } |
| catch (Utils::shaderCompilationException& exc) |
| { |
| /* Something wrong with compilation, test case failed */ |
| tcu::MessageBuilder message = m_context.getTestContext().getLog() << tcu::TestLog::Message; |
| |
| message << "Shader compilation failed. Error message: " << exc.m_error_message; |
| |
| Utils::program::printShaderSource(exc.m_shader_source, message); |
| |
| message << tcu::TestLog::EndMessage; |
| |
| return false; |
| } |
| catch (Utils::programLinkageException& exc) |
| { |
| /* Something wrong with linking, test case failed */ |
| m_context.getTestContext().getLog() << tcu::TestLog::Message |
| << "Program linking failed. Error message: " << exc.m_error_message |
| << tcu::TestLog::EndMessage; |
| return false; |
| } |
| |
| /* Log shaders, for debugging */ |
| #if IS_DEBUG |
| { |
| tcu::MessageBuilder message = m_context.getTestContext().getLog() << tcu::TestLog::Message; |
| |
| Utils::program::printShaderSource(compute_shader, message); |
| |
| message << tcu::TestLog::EndMessage; |
| } |
| #endif /* IS_DEBUG */ |
| |
| /* Set current program */ |
| program.use(); |
| |
| /* Prepare image unit */ |
| prepareImage(program, color_tex); |
| |
| /* Test specific preparation of source texture */ |
| const GLchar* sampler_name = prepareSourceTexture(source_tex); |
| if (0 != sampler_name) |
| { |
| bindTextureToSampler(program, source_tex, sampler_name); |
| } |
| |
| /* Set up uniforms */ |
| prepareUniforms(program); |
| |
| /* GL entry points */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Draw */ |
| gl.dispatchCompute(m_color_texture_width, m_color_texture_height, 1); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute"); |
| |
| /* Return result of verification */ |
| result = checkResults(color_tex); |
| |
| /* Release extra resource for the test */ |
| releaseResource(); |
| |
| return result; |
| } |
| |
| /** Execute test with draw array operation |
| * |
| * @param use_version_400 Select if 400 or 420 should be used |
| * |
| * @return true if test pass, false otherwise |
| **/ |
| bool GLSLTestBase::testDrawArray(bool use_version_400) |
| { |
| /* Test Result */ |
| bool result = true; |
| |
| /* GL objects */ |
| Utils::texture color_tex(m_context); |
| Utils::framebuffer framebuffer(m_context); |
| Utils::program program(m_context); |
| Utils::texture source_tex(m_context); |
| Utils::vertexArray vao(m_context); |
| Utils::buffer vertex_buffer(m_context); |
| |
| /* Shaders */ |
| Utils::shaderSource fragment_data; |
| Utils::shaderSource geometry_data; |
| Utils::shaderSource tess_ctrl_data; |
| Utils::shaderSource tess_eval_data; |
| Utils::shaderSource vertex_data; |
| |
| initShaderSource(Utils::FRAGMENT_SHADER, use_version_400, fragment_data); |
| initShaderSource(Utils::GEOMETRY_SHADER, use_version_400, geometry_data); |
| initShaderSource(Utils::TESS_CTRL_SHADER, use_version_400, tess_ctrl_data); |
| initShaderSource(Utils::TESS_EVAL_SHADER, use_version_400, tess_eval_data); |
| initShaderSource(Utils::VERTEX_SHADER, use_version_400, vertex_data); |
| |
| /* Build program */ |
| try |
| { |
| program.build(0 /* compute shader */, fragment_data, geometry_data, tess_ctrl_data, tess_eval_data, vertex_data, |
| 0 /* varying names */, 0 /* n varying names */, false); |
| } |
| catch (Utils::shaderCompilationException& exc) |
| { |
| /* Something wrong with compilation, test case failed */ |
| tcu::MessageBuilder message = m_context.getTestContext().getLog() << tcu::TestLog::Message; |
| |
| message << "Shader compilation failed. Error message: " << exc.m_error_message; |
| |
| Utils::program::printShaderSource(exc.m_shader_source, message); |
| |
| message << tcu::TestLog::EndMessage; |
| |
| return false; |
| } |
| catch (Utils::programLinkageException& exc) |
| { |
| /* Something wrong with linking, test case failed */ |
| m_context.getTestContext().getLog() << tcu::TestLog::Message |
| << "Program linking failed. Error message: " << exc.m_error_message |
| << tcu::TestLog::EndMessage; |
| return false; |
| } |
| |
| /* Log shaders, for debugging */ |
| #if IS_DEBUG |
| { |
| const Utils::shaderSource* data[] = { &vertex_data, &tess_ctrl_data, &tess_eval_data, &geometry_data, |
| &fragment_data }; |
| |
| tcu::MessageBuilder message = m_context.getTestContext().getLog() << tcu::TestLog::Message; |
| |
| for (GLuint i = 0; i < 5; ++i) |
| { |
| Utils::program::printShaderSource(*data[i], message); |
| } |
| |
| message << tcu::TestLog::EndMessage; |
| } |
| #endif /* IS_DEBUG */ |
| |
| /* Test specific preparation of vertex buffer and vao*/ |
| prepareVertexBuffer(program, vertex_buffer, vao); |
| |
| /* Set current program */ |
| program.use(); |
| |
| /* Prepare framebuffer */ |
| prepareFramebuffer(framebuffer, color_tex); |
| |
| /* Test specific preparation of source texture */ |
| const GLchar* sampler_name = prepareSourceTexture(source_tex); |
| if (0 != sampler_name) |
| { |
| bindTextureToSampler(program, source_tex, sampler_name); |
| } |
| |
| /* Set up uniforms */ |
| prepareUniforms(program); |
| |
| /* GL entry points */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Draw */ |
| gl.drawArrays(GL_PATCHES, 0 /* first */, 1 /* count */); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays"); |
| |
| /* Return result of verification */ |
| result = checkResults(color_tex); |
| |
| /* Release extra resource for the test */ |
| releaseResource(); |
| |
| return result; |
| } |
| |
| /** Constructor |
| * |
| * @param context Test context |
| * @param test_name Test name |
| * @param test_description Test description |
| **/ |
| NegativeTestBase::NegativeTestBase(deqp::Context& context, const glw::GLchar* test_name, |
| const glw::GLchar* test_description) |
| : TestBase(context, test_name, test_description) |
| { |
| /* Nothing to be done here */ |
| } |
| |
| /** Execute test with compute shader |
| * |
| * @return true if test pass, false otherwise |
| **/ |
| bool NegativeTestBase::testCompute() |
| { |
| /* GL objects */ |
| Utils::program program(m_context); |
| |
| /* Shaders */ |
| Utils::shaderSource conmpute_data; |
| initShaderSource(Utils::COMPUTE_SHADER, false, conmpute_data); |
| |
| /* Build program */ |
| try |
| { |
| program.build(conmpute_data /* compute shader */, 0 /* fragment shader */, 0 /* geometry shader */, |
| 0 /* tesselation control shader */, 0 /* tesselation evaluation shader */, 0 /* vertex shader */, |
| 0 /* varying names */, 0 /* n varying names */, false); |
| } |
| catch (Utils::shaderCompilationException& exc) |
| { |
| /* Compilation failed, as expected. Verify that reason of failure is as expected */ |
| m_context.getTestContext().getLog() << tcu::TestLog::Message |
| << "Shader compilation error message: " << exc.m_error_message |
| << tcu::TestLog::EndMessage; |
| return true; |
| } |
| catch (Utils::programLinkageException& exc) |
| { |
| /* Something wrong with linking, test case failed */ |
| m_context.getTestContext().getLog() << tcu::TestLog::Message |
| << "Program linking failed. Error message: " << exc.m_error_message |
| << tcu::TestLog::EndMessage; |
| return true; |
| } |
| |
| /* Build process succeded */ |
| return false; |
| } |
| |
| /** Execute test with draw array operation |
| * |
| * @param use_version_400 Select if 400 or 420 should be used |
| * |
| * @return true if test pass, false otherwise |
| **/ |
| bool NegativeTestBase::testDrawArray(bool use_version_400) |
| { |
| /* GL objects */ |
| Utils::program program(m_context); |
| |
| /* Shaders */ |
| Utils::shaderSource fragment_data; |
| Utils::shaderSource geometry_data; |
| Utils::shaderSource tess_ctrl_data; |
| Utils::shaderSource tess_eval_data; |
| Utils::shaderSource vertex_data; |
| |
| initShaderSource(Utils::FRAGMENT_SHADER, use_version_400, fragment_data); |
| initShaderSource(Utils::GEOMETRY_SHADER, use_version_400, geometry_data); |
| initShaderSource(Utils::TESS_CTRL_SHADER, use_version_400, tess_ctrl_data); |
| initShaderSource(Utils::TESS_EVAL_SHADER, use_version_400, tess_eval_data); |
| initShaderSource(Utils::VERTEX_SHADER, use_version_400, vertex_data); |
| |
| /* Build program */ |
| try |
| { |
| program.build(0 /* compute shader */, fragment_data, geometry_data, tess_ctrl_data, tess_eval_data, vertex_data, |
| 0 /* varying names */, 0 /* n varying names */, false); |
| } |
| catch (Utils::shaderCompilationException& exc) |
| { |
| /* Compilation failed, as expected. Verify that reason of failure is as expected */ |
| m_context.getTestContext().getLog() << tcu::TestLog::Message |
| << "Shader compilation error message: " << exc.m_error_message |
| << tcu::TestLog::EndMessage; |
| return true; |
| } |
| catch (Utils::programLinkageException& exc) |
| { |
| /* Something wrong with linking, test case failed */ |
| m_context.getTestContext().getLog() << tcu::TestLog::Message |
| << "Program linking failed. Error message: " << exc.m_error_message |
| << tcu::TestLog::EndMessage; |
| return true; |
| } |
| |
| /* Build process succeded */ |
| return false; |
| } |
| |
| /* Constants used by BindingImageTest */ |
| const GLuint BindingImageTest::m_width = 16; |
| const GLuint BindingImageTest::m_green_color = 0xff00ff00; |
| const GLuint BindingImageTest::m_height = 16; |
| const GLuint BindingImageTest::m_depth = 6; |
| |
| /** Constructor |
| * |
| * @param context Test context |
| **/ |
| BindingImageTest::BindingImageTest(deqp::Context& context, const glw::GLchar* test_name, |
| const glw::GLchar* test_description) |
| : GLSLTestBase(context, test_name, test_description) |
| { |
| /* Nothing to be done */ |
| } |
| |
| /** Prepare buffer, filled with given color |
| * |
| * @param buffer Buffer object |
| * @param color Color |
| **/ |
| void BindingImageTest::prepareBuffer(Utils::buffer& buffer, GLuint color) |
| { |
| std::vector<GLuint> texture_data; |
| texture_data.resize(m_width); |
| |
| buffer.generate(GL_TEXTURE_BUFFER); |
| |
| for (GLuint i = 0; i < texture_data.size(); ++i) |
| { |
| texture_data[i] = color; |
| } |
| |
| buffer.update(m_width * sizeof(GLuint), &texture_data[0], GL_STATIC_DRAW); |
| } |
| |
| /** Prepare texture of given type filled with given color and bind to specified image unit |
| * |
| * @param texture Texture |
| * @param buffer Buffer |
| * @param texture_type Type of texture |
| * @param color Color |
| **/ |
| void BindingImageTest::prepareTexture(Utils::texture& texture, const Utils::buffer& buffer, |
| Utils::TEXTURE_TYPES texture_type, GLuint color, GLuint unit) |
| { |
| std::vector<GLuint> texture_data; |
| texture_data.resize(m_width * m_height * m_depth); |
| |
| GLboolean is_layered = GL_FALSE; |
| |
| for (GLuint i = 0; i < texture_data.size(); ++i) |
| { |
| texture_data[i] = color; |
| } |
| |
| if (Utils::TEX_BUFFER != texture_type) |
| { |
| texture.create(m_width, m_height, m_depth, GL_RGBA8, texture_type); |
| |
| texture.update(m_width, m_height, m_depth, GL_RGBA, GL_UNSIGNED_BYTE, &texture_data[0]); |
| } |
| else |
| { |
| buffer.bind(); |
| |
| texture.createBuffer(GL_RGBA8, buffer.m_id); |
| } |
| |
| switch (texture_type) |
| { |
| case Utils::TEX_1D_ARRAY: |
| case Utils::TEX_2D_ARRAY: |
| case Utils::TEX_3D: |
| case Utils::TEX_CUBE: |
| is_layered = GL_TRUE; |
| break; |
| default: |
| break; |
| } |
| |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| gl.bindImageTexture(unit, texture.m_id, 0 /* level */, is_layered /* layered */, 0 /* layer */, GL_READ_WRITE, |
| GL_RGBA8); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture"); |
| } |
| |
| /** Verifies that texel at offset 0 is green |
| * |
| * @param buffer Buffer object |
| * |
| * @return true if texel at offset 0 is green, false otherwise |
| **/ |
| bool BindingImageTest::verifyBuffer(const Utils::buffer& buffer) const |
| { |
| GLuint* data = (GLuint*)buffer.map(GL_READ_ONLY); |
| |
| GLuint color = data[0]; |
| |
| buffer.unmap(); |
| |
| return (m_green_color == color); |
| } |
| |
| /** Verifies that texel at offset 0 is green |
| * |
| * @param buffer Buffer object |
| * |
| * @return true if texel at offset 0 is green, false otherwise |
| **/ |
| bool BindingImageTest::verifyTexture(const Utils::texture& texture) const |
| { |
| static const GLuint texture_data_size = m_width * m_height * m_depth; |
| |
| std::vector<glw::GLuint> texture_data; |
| texture_data.resize(texture_data_size); |
| |
| texture.get(GL_RGBA, GL_UNSIGNED_BYTE, &texture_data[0]); |
| |
| GLuint color = texture_data[0]; |
| |
| return (m_green_color == color); |
| } |
| |
| /* Constants used by LineContinuationTest */ |
| const GLuint LineContinuationTest::m_n_repetitions = 20; |
| const GLchar* LineContinuationTest::m_texture_coordinates_name = "texture_coordinates"; |
| |
| /** Constructor |
| * |
| * @param context Test context |
| **/ |
| LineContinuationTest::LineContinuationTest(deqp::Context& context) : GLSLTestBase(context, "line_continuation", "desc") |
| { |
| /* Nothing to be done here */ |
| } |
| |
| /** Overwrite getShaderSourceConfig method |
| * |
| * @param out_n_parts Number of source parts used by this test case |
| * @param out_use_lengths If source lengths shall be provided to compiler |
| **/ |
| void LineContinuationTest::getShaderSourceConfig(GLuint& out_n_parts, bool& out_use_lengths) |
| { |
| out_n_parts = (true == isShaderMultipart()) ? 2 : 1; |
| out_use_lengths = useSourceLengths(); |
| } |
| |
| /** Set up next test case |
| * |
| * @param test_case_index Index of next test case |
| * |
| * @return false if there is no more test cases, true otherwise |
| **/ |
| bool LineContinuationTest::prepareNextTestCase(glw::GLuint test_case_index) |
| { |
| static const testCase test_cases[] = { { ASSIGNMENT_BEFORE_OPERATOR, ONCE, UNIX }, |
| { ASSIGNMENT_BEFORE_OPERATOR, ONCE, DOS }, |
| { ASSIGNMENT_BEFORE_OPERATOR, MULTIPLE_TIMES, UNIX }, |
| { ASSIGNMENT_BEFORE_OPERATOR, MULTIPLE_TIMES, DOS }, |
| { ASSIGNMENT_AFTER_OPERATOR, ONCE, UNIX }, |
| { ASSIGNMENT_AFTER_OPERATOR, ONCE, DOS }, |
| { ASSIGNMENT_AFTER_OPERATOR, MULTIPLE_TIMES, UNIX }, |
| { ASSIGNMENT_AFTER_OPERATOR, MULTIPLE_TIMES, DOS }, |
| { VECTOR_VARIABLE_INITIALIZER, ONCE, UNIX }, |
| { VECTOR_VARIABLE_INITIALIZER, ONCE, DOS }, |
| { VECTOR_VARIABLE_INITIALIZER, MULTIPLE_TIMES, UNIX }, |
| { VECTOR_VARIABLE_INITIALIZER, MULTIPLE_TIMES, DOS }, |
| { TOKEN_INSIDE_FUNCTION_NAME, ONCE, UNIX }, |
| { TOKEN_INSIDE_FUNCTION_NAME, ONCE, DOS }, |
| { TOKEN_INSIDE_FUNCTION_NAME, MULTIPLE_TIMES, UNIX }, |
| { TOKEN_INSIDE_FUNCTION_NAME, MULTIPLE_TIMES, DOS }, |
| { TOKEN_INSIDE_TYPE_NAME, ONCE, UNIX }, |
| { TOKEN_INSIDE_TYPE_NAME, ONCE, DOS }, |
| { TOKEN_INSIDE_TYPE_NAME, MULTIPLE_TIMES, UNIX }, |
| { TOKEN_INSIDE_TYPE_NAME, MULTIPLE_TIMES, DOS }, |
| { TOKEN_INSIDE_VARIABLE_NAME, ONCE, UNIX }, |
| { TOKEN_INSIDE_VARIABLE_NAME, ONCE, DOS }, |
| { TOKEN_INSIDE_VARIABLE_NAME, MULTIPLE_TIMES, UNIX }, |
| { TOKEN_INSIDE_VARIABLE_NAME, MULTIPLE_TIMES, DOS }, |
| { PREPROCESSOR_TOKEN_INSIDE, ONCE, UNIX }, |
| { PREPROCESSOR_TOKEN_INSIDE, ONCE, DOS }, |
| { PREPROCESSOR_TOKEN_INSIDE, MULTIPLE_TIMES, UNIX }, |
| { PREPROCESSOR_TOKEN_INSIDE, MULTIPLE_TIMES, DOS }, |
| { PREPROCESSOR_TOKEN_BETWEEN, ONCE, UNIX }, |
| { PREPROCESSOR_TOKEN_BETWEEN, ONCE, DOS }, |
| { PREPROCESSOR_TOKEN_BETWEEN, MULTIPLE_TIMES, UNIX }, |
| { PREPROCESSOR_TOKEN_BETWEEN, MULTIPLE_TIMES, DOS }, |
| { COMMENT, ONCE, UNIX }, |
| { COMMENT, ONCE, DOS }, |
| { COMMENT, MULTIPLE_TIMES, UNIX }, |
| { COMMENT, MULTIPLE_TIMES, DOS }, |
| { SOURCE_TERMINATION_NULL, ONCE, UNIX }, |
| { SOURCE_TERMINATION_NULL, ONCE, DOS }, |
| { SOURCE_TERMINATION_NULL, MULTIPLE_TIMES, UNIX }, |
| { SOURCE_TERMINATION_NULL, MULTIPLE_TIMES, DOS }, |
| { SOURCE_TERMINATION_NON_NULL, ONCE, UNIX }, |
| { SOURCE_TERMINATION_NON_NULL, ONCE, DOS }, |
| { SOURCE_TERMINATION_NON_NULL, MULTIPLE_TIMES, UNIX }, |
| { SOURCE_TERMINATION_NON_NULL, MULTIPLE_TIMES, DOS }, |
| { PART_TERMINATION_NULL, ONCE, UNIX }, |
| { PART_TERMINATION_NULL, ONCE, DOS }, |
| { PART_TERMINATION_NULL, MULTIPLE_TIMES, UNIX }, |
| { PART_TERMINATION_NULL, MULTIPLE_TIMES, DOS }, |
| { PART_NEXT_TO_TERMINATION_NULL, ONCE, UNIX }, |
| { PART_NEXT_TO_TERMINATION_NULL, ONCE, DOS }, |
| { PART_NEXT_TO_TERMINATION_NULL, MULTIPLE_TIMES, UNIX }, |
| { PART_NEXT_TO_TERMINATION_NULL, MULTIPLE_TIMES, DOS }, |
| { PART_TERMINATION_NON_NULL, ONCE, UNIX }, |
| { PART_TERMINATION_NON_NULL, ONCE, DOS }, |
| { PART_TERMINATION_NON_NULL, MULTIPLE_TIMES, UNIX }, |
| { PART_TERMINATION_NON_NULL, MULTIPLE_TIMES, DOS }, |
| { PART_NEXT_TO_TERMINATION_NON_NULL, ONCE, UNIX }, |
| { PART_NEXT_TO_TERMINATION_NON_NULL, ONCE, DOS }, |
| { PART_NEXT_TO_TERMINATION_NON_NULL, MULTIPLE_TIMES, UNIX }, |
| { PART_NEXT_TO_TERMINATION_NON_NULL, MULTIPLE_TIMES, DOS } }; |
| |
| static const GLuint max_test_cases = sizeof(test_cases) / sizeof(testCase); |
| |
| if ((GLuint)-1 == test_case_index) |
| { |
| m_test_case.m_case = DEBUG_CASE; |
| } |
| else if (max_test_cases <= test_case_index) |
| { |
| return false; |
| } |
| else |
| { |
| m_test_case = test_cases[test_case_index]; |
| } |
| |
| m_context.getTestContext().getLog() << tcu::TestLog::Message |
| << "Test case: " << repetitionsToStr((REPETITIONS)m_test_case.m_repetitions) |
| << " line continuation, with " |
| << lineEndingsToStr((LINE_ENDINGS)m_test_case.m_line_endings) |
| << " line endings, is placed " << casesToStr((CASES)m_test_case.m_case) |
| << tcu::TestLog::EndMessage; |
| |
| return true; |
| } |
| |
| /** Prepare source for given shader stage |
| * |
| * @param in_stage Shader stage, compute shader will use 430 |
| * @param in_use_version_400 Select if 400 or 420 should be used |
| * @param out_source Prepared shader source instance |
| **/ |
| void LineContinuationTest::prepareShaderSource(Utils::SHADER_STAGES in_stage, bool in_use_version_400, |
| Utils::shaderSource& out_source) |
| { |
| if (Utils::COMPUTE_SHADER == in_stage) |
| { |
| prepareComputShaderSource(out_source); |
| } |
| else |
| { |
| prepareShaderSourceForDraw(in_stage, in_use_version_400, out_source); |
| } |
| } |
| |
| /** Prepare compute shader source |
| * |
| * @param source Result shader source |
| **/ |
| void LineContinuationTest::prepareComputShaderSource(Utils::shaderSource& source) |
| { |
| static const GLchar* shader_template_part_0 = |
| "#version 430\n" |
| "\n" |
| "// Lorem ipsum dolor sit amCOMMENT_CASEet, consectetur adipiscing elit posuere.\n" |
| "\n" |
| "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n" |
| "\n" |
| "/* Lorem ipsum dolor sit amet, conCOMMENT_CASEsectetur adipiscing elit posuere. */\n" |
| "\n" |
| "writeonly uniform image2D uni_image;\n" |
| " uniform sampler2D uni_sampler;\n" |
| "\n" |
| "void funFUNCTION_CASEction(in veTYPE_CASEc4 in_vVARIABLE_CASEalue)\n" |
| "{\n" |
| " imageStore(uni_image, ivec2(gl_GlobalInvocationID.xy), inVARIABLE_CASE_value);\n" |
| "}\n" |
| "\n" |
| "#define SET_PREPROCESSOR_INSIDE_CASERESULT(XX) " |
| "PREPROCESSOR_BETWEEN_CASEfuncFUNCTION_CASEtion(XPREPROCESSOR_INSIDE_CASEX)\n" |
| "NEXT_TO_TERMINATION_CASE\nTERMINATION_CASE"; |
| |
| static const GLchar* shader_template_part_1 = |
| "void main()\n" |
| "{\n" |
| " ivec2 coordinates ASSIGNMENT_BEFORE_OPERATOR_CASE=ASSIGNMENT_AFTER_OPERATOR_CASE " |
| "ivec2(gl_GlobalInvocationID.xy + ivec2(16, 16));\n" |
| " vec4 sampled_color = texelFetch(uni_sampler, coordinates, 0 /* lod */);\n" |
| " vec4 result = vec4(0, 0VECTOR_VARIABLE_INITIALIZER_CASE, 0, 1);\n" |
| "\n" |
| " if (vec4(0, 0, 1, 1) == sampled_color)\n" |
| " {\n" |
| " result = vecTYPE_CASE4(VECTOR_VARIABLE_INITIALIZER_CASE0, 1, 0, 1);\n" |
| " }\n" |
| " else\n" |
| " {\n" |
| " result = vec4(coordinates.xy, sampled_color.rg);\n" |
| " }\n" |
| "\n" |
| " SET_RESULT(result);" |
| "}\n"; |
| |
| /* Init strings with templates and replace all CASE tokens */ |
| if (true == isShaderMultipart()) |
| { |
| source.m_parts[0].m_code = shader_template_part_0; |
| source.m_parts[1].m_code = shader_template_part_1; |
| |
| replaceAllCaseTokens(source.m_parts[0].m_code); |
| replaceAllCaseTokens(source.m_parts[1].m_code); |
| } |
| else |
| { |
| source.m_parts[0].m_code = shader_template_part_0; |
| source.m_parts[0].m_code.append(shader_template_part_1); |
| |
| replaceAllCaseTokens(source.m_parts[0].m_code); |
| } |
| } |
| |
| /** Prepare source for given shader stage |
| * |
| * @param stage Shader stage, compute shader will use 430 |
| * @param use_version_400 Select if 400 or 420 should be used |
| * @param source Result shader sources |
| **/ |
| void LineContinuationTest::prepareShaderSourceForDraw(Utils::SHADER_STAGES stage, bool use_version_400, |
| Utils::shaderSource& source) |
| { |
| /* Templates */ |
| static const GLchar* shader_template_part_0 = |
| "VERSION\n" |
| "\n" |
| "// Lorem ipsum dolor sit amCOMMENT_CASEet, consectetur adipiscing elit posuere.\n" |
| "\n" |
| "STAGE_SPECIFIC\n" |
| "\n" |
| "/* Lorem ipsum dolor sit amet, conCOMMENT_CASEsectetur adipiscing elit posuere. */\n" |
| "\n" |
| "IN_COLOR_DEFINITION\n" |
| "IN_TEXTURE_COORDINATES_DEFINITION\n" |
| "OUT_COLOR_DEFINITION\n" |
| "OUT_TEXTURE_COORDINATES_DEFINITION\n" |
| "uniform sampler2D uni_sampler;\n" |
| "\n" |
| "void funFUNCTION_CASEction(in veTYPE_CASEc4 in_vVARIABLE_CASEalue)\n" |
| "{\n" |
| " OUT_COLOR ASSIGNMENT_BEFORE_OPERATOR_CASE=ASSIGNMENT_AFTER_OPERATOR_CASE inVARIABLE_CASE_value;\n" |
| "}\n" |
| "\n" |
| "#define SET_PREPROCESSOR_INSIDE_CASERESULT(XX) " |
| "PREPROCESSOR_BETWEEN_CASEfuncFUNCTION_CASEtion(XPREPROCESSOR_INSIDE_CASEX)\n" |
| "NEXT_TO_TERMINATION_CASE\nTERMINATION_CASE"; |
| |
| static const GLchar* shader_template_part_1 = |
| "void main()\n" |
| "{\n" |
| " vec2 coordinates = TEXTURE_COORDINATES;\n" |
| " vec4 sampled_color = texture(uni_sampler, coordinates);\n" |
| " vec4 result = vec4(0, 0VECTOR_VARIABLE_INITIALIZER_CASE, 0, 1);\n" |
| "\n" |
| " if (PASS_CONDITION)\n" |
| " {\n" |
| " result = vecTYPE_CASE4(VECTOR_VARIABLE_INITIALIZER_CASE0, 1, 0, 1);\n" |
| " }\n" |
| " else\n" |
| " {\n" |
| " result = vec4(coordinates.xy, sampled_color.rg);\n" |
| " }\n" |
| "\n" |
| "STORE_RESULTS" |
| "}\n" |
| "NEXT_TO_TERMINATION_CASE\nTERMINATION_CASE"; |
| |
| static const GLchar* store_results_template = " SET_RESULT(result);\n" |
| " TEXTURE_COORDINATES = coordinates;\n"; |
| |
| static const GLchar* store_results_tcs_template = " SET_RESULT(result);\n" |
| " TEXTURE_COORDINATES = coordinates;\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"; |
| |
| static const GLchar* store_results_fs_template = " SET_RESULT(result);\n"; |
| |
| static const GLchar* store_results_gs_template = " gl_Position = vec4(-1, -1, 0, 1);\n" |
| " SET_RESULT(result);\n" |
| " TEXTURE_COORDINATES = coordinates + vec2(-0.25, -0.25);\n" |
| " EmitVertex();\n" |
| " gl_Position = vec4(-1, 1, 0, 1);\n" |
| " SET_RESULT(result);\n" |
| " TEXTURE_COORDINATES = coordinates + vec2(-0.25, 0.25);\n" |
| " EmitVertex();\n" |
| " gl_Position = vec4(1, -1, 0, 1);\n" |
| " SET_RESULT(result);\n" |
| " TEXTURE_COORDINATES = coordinates + vec2(0.25, -0.25);\n" |
| " EmitVertex();\n" |
| " gl_Position = vec4(1, 1, 0, 1);\n" |
| " SET_RESULT(result);\n" |
| " TEXTURE_COORDINATES = coordinates + vec2(0.25, 0.25);\n" |
| " EmitVertex();\n"; |
| |
| static const GLchar* pass_condition_template = "(EXPECTED_VALUE == sampled_color) &&\n" |
| " (vec4(0, 1, 0, 1) == IN_COLOR) "; |
| |
| static const GLchar* pass_condition_vs_template = "EXPECTED_VALUE == sampled_color"; |
| |
| /* Tokens to be replaced with GLSL stuff */ |
| static const GLchar* token_version = "VERSION"; |
| static const GLchar* token_stage_specific = "STAGE_SPECIFIC"; |
| |
| static const GLchar* token_in_color_definition = "IN_COLOR_DEFINITION"; |
| static const GLchar* token_in_tex_coord_definition = "IN_TEXTURE_COORDINATES_DEFINITION"; |
| static const GLchar* token_out_color_definition = "OUT_COLOR_DEFINITION"; |
| static const GLchar* token_out_tex_coord_definition = "OUT_TEXTURE_COORDINATES_DEFINITION"; |
| |
| static const GLchar* token_expected_value = "EXPECTED_VALUE"; |
| static const GLchar* token_texture_coordinates = "TEXTURE_COORDINATES"; |
| static const GLchar* token_in_color = "IN_COLOR"; |
| static const GLchar* token_out_color = "OUT_COLOR"; |
| |
| static const GLchar* token_store_results = "STORE_RESULTS"; |
| static const GLchar* token_pass_condition = "PASS_CONDITION"; |
| |
| /* Name of variable and empty string*/ |
| static const GLchar* color_name = "color"; |
| static const GLchar* empty = ""; |
| |
| /* GLSL stuff */ |
| const GLchar* version = getVersionString(stage, use_version_400); |
| const GLchar* stage_specific_layout = getStageSpecificLayout(stage); |
| const GLchar* expected_value = getExpectedValueString(); |
| |
| /* Qualifiers */ |
| Utils::qualifierSet in; |
| Utils::qualifierSet out; |
| in.push_back(Utils::QUAL_IN); |
| out.push_back(Utils::QUAL_OUT); |
| |
| /* In/Out variables definitions and references */ |
| std::string in_tex_coord_reference; |
| std::string out_tex_coord_reference; |
| std::string in_color_reference; |
| std::string out_color_reference; |
| std::string in_tex_coord_definition; |
| std::string out_tex_coord_definition; |
| std::string in_color_definition; |
| std::string out_color_definition; |
| |
| Utils::prepareVariableStrings(stage, Utils::INPUT, in, "vec2", m_texture_coordinates_name, in_tex_coord_definition, |
| in_tex_coord_reference); |
| Utils::prepareVariableStrings(stage, Utils::OUTPUT, out, "vec2", m_texture_coordinates_name, |
| out_tex_coord_definition, out_tex_coord_reference); |
| Utils::prepareVariableStrings(stage, Utils::INPUT, in, "vec4", color_name, in_color_definition, in_color_reference); |
| Utils::prepareVariableStrings(stage, Utils::OUTPUT, out, "vec4", color_name, out_color_definition, |
| out_color_reference); |
| |
| in_tex_coord_definition.append(";"); |
| out_tex_coord_definition.append(";"); |
| in_color_definition.append(";"); |
| out_color_definition.append(";"); |
| |
| /* Select pass condition and store results tempaltes */ |
| const GLchar* store_results = store_results_template; |
| const GLchar* pass_condition = pass_condition_template; |
| |
| switch (stage) |
| { |
| case Utils::FRAGMENT_SHADER: |
| store_results = store_results_fs_template; |
| break; |
| case Utils::GEOMETRY_SHADER: |
| store_results = store_results_gs_template; |
| break; |
| case Utils::TESS_CTRL_SHADER: |
| store_results = store_results_tcs_template; |
| break; |
| case Utils::VERTEX_SHADER: |
| pass_condition = pass_condition_vs_template; |
| break; |
| default: |
| break; |
| }; |
| const GLuint store_results_length = static_cast<GLuint>(strlen(store_results)); |
| const GLuint pass_condition_length = static_cast<GLuint>(strlen(pass_condition)); |
| |
| /* Init strings with templates and replace all CASE tokens */ |
| if (true == isShaderMultipart()) |
| { |
| source.m_parts[0].m_code = shader_template_part_0; |
| source.m_parts[1].m_code = shader_template_part_1; |
| |
| replaceAllCaseTokens(source.m_parts[0].m_code); |
| replaceAllCaseTokens(source.m_parts[1].m_code); |
| } |
| else |
| { |
| source.m_parts[0].m_code = shader_template_part_0; |
| source.m_parts[0].m_code.append(shader_template_part_1); |
| |
| replaceAllCaseTokens(source.m_parts[0].m_code); |
| } |
| |
| /* Get memory for shader source parts */ |
| const bool is_multipart = isShaderMultipart(); |
| size_t position = 0; |
| std::string& shader_source_part_0 = source.m_parts[0].m_code; |
| std::string& shader_source_part_1 = (true == is_multipart) ? source.m_parts[1].m_code : source.m_parts[0].m_code; |
| |
| /* Replace tokens */ |
| /* Part 0 */ |
| Utils::replaceToken(token_version, position, version, shader_source_part_0); |
| |
| Utils::replaceToken(token_stage_specific, position, stage_specific_layout, shader_source_part_0); |
| |
| if (Utils::VERTEX_SHADER != stage) |
| { |
| Utils::replaceToken(token_in_color_definition, position, in_color_definition.c_str(), shader_source_part_0); |
| } |
| else |
| { |
| Utils::replaceToken(token_in_color_definition, position, empty, shader_source_part_0); |
| } |
| Utils::replaceToken(token_in_tex_coord_definition, position, in_tex_coord_definition.c_str(), shader_source_part_0); |
| Utils::replaceToken(token_out_color_definition, position, out_color_definition.c_str(), shader_source_part_0); |
| if (Utils::FRAGMENT_SHADER == stage) |
| { |
| Utils::replaceToken(token_out_tex_coord_definition, position, empty, shader_source_part_0); |
| } |
| else |
| { |
| Utils::replaceToken(token_out_tex_coord_definition, position, out_tex_coord_definition.c_str(), |
| shader_source_part_0); |
| } |
| |
| Utils::replaceToken(token_out_color, position, out_color_reference.c_str(), shader_source_part_0); |
| |
| /* Part 1 */ |
| if (true == is_multipart) |
| { |
| position = 0; |
| } |
| |
| Utils::replaceToken(token_texture_coordinates, position, in_tex_coord_reference.c_str(), shader_source_part_1); |
| |
| Utils::replaceToken(token_pass_condition, position, pass_condition, shader_source_part_1); |
| position -= pass_condition_length; |
| |
| Utils::replaceToken(token_expected_value, position, expected_value, shader_source_part_1); |
| if (Utils::VERTEX_SHADER != stage) |
| { |
| Utils::replaceToken(token_in_color, position, in_color_reference.c_str(), shader_source_part_1); |
| } |
| |
| Utils::replaceToken(token_store_results, position, store_results, shader_source_part_1); |
| position -= store_results_length; |
| |
| if (Utils::GEOMETRY_SHADER == stage) |
| { |
| for (GLuint i = 0; i < 4; ++i) |
| { |
| Utils::replaceToken(token_texture_coordinates, position, out_tex_coord_reference.c_str(), |
| shader_source_part_1); |
| } |
| } |
| else if (Utils::FRAGMENT_SHADER == stage) |
| { |
| /* Nothing to be done */ |
| } |
| else |
| { |
| Utils::replaceToken(token_texture_coordinates, position, out_tex_coord_reference.c_str(), shader_source_part_1); |
| } |
| } |
| |
| /** Prepare texture |
| * |
| * @param texture Texutre to be created and filled with content |
| * |
| * @return Name of sampler uniform that should be used for the texture |
| **/ |
| const GLchar* LineContinuationTest::prepareSourceTexture(Utils::texture& texture) |
| { |
| std::vector<GLuint> data; |
| static const GLuint width = 64; |
| static const GLuint height = 64; |
| static const GLuint data_size = width * height; |
| static const GLuint blue_color = 0xffff0000; |
| static const GLuint grey_color = 0xaaaaaaaa; |
| |
| data.resize(data_size); |
| |
| for (GLuint i = 0; i < data_size; ++i) |
| { |
| data[i] = grey_color; |
| } |
| |
| for (GLuint y = 16; y < 48; ++y) |
| { |
| const GLuint line_offset = y * 64; |
| |
| for (GLuint x = 16; x < 48; ++x) |
| { |
| const GLuint pixel_offset = x + line_offset; |
| |
| data[pixel_offset] = blue_color; |
| } |
| } |
| |
| texture.create(width, height, GL_RGBA8); |
| |
| texture.update(width, height, 0 /* depth */, GL_RGBA, GL_UNSIGNED_BYTE, &data[0]); |
| |
| return "uni_sampler"; |
| } |
| |
| /** Prepare vertex buffer, vec2 tex_coord |
| * |
| * @param program Program object |
| * @param buffer Vertex buffer |
| * @param vao Vertex array object |
| **/ |
| void LineContinuationTest::prepareVertexBuffer(const Utils::program& program, Utils::buffer& buffer, |
| Utils::vertexArray& vao) |
| { |
| std::string tex_coord_name = Utils::getVariableName(Utils::VERTEX_SHADER, Utils::INPUT, m_texture_coordinates_name); |
| GLint tex_coord_loc = program.getAttribLocation(tex_coord_name.c_str()); |
| |
| if (-1 == tex_coord_loc) |
| { |
| TCU_FAIL("Vertex attribute location is invalid"); |
| } |
| |
| vao.generate(); |
| vao.bind(); |
| |
| buffer.generate(GL_ARRAY_BUFFER); |
| |
| GLfloat data[] = { 0.5f, 0.5f, 0.5f, 0.5f }; |
| GLsizeiptr data_size = sizeof(data); |
| |
| buffer.update(data_size, data, GL_STATIC_DRAW); |
| |
| /* GL entry points */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Set up vao */ |
| gl.vertexAttribPointer(tex_coord_loc, 2 /* size */, GL_FLOAT /* type */, GL_FALSE /* normalized*/, 0 /* stride */, |
| 0 /* offset */); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "VertexAttribPointer"); |
| |
| /* Enable attribute */ |
| gl.enableVertexAttribArray(tex_coord_loc); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "EnableVertexAttribArray"); |
| } |
| |
| /** Get string describing test cases |
| * |
| * @param cases Test case |
| * |
| * @return String describing current test case |
| **/ |
| const GLchar* LineContinuationTest::casesToStr(CASES cases) const |
| { |
| const GLchar* result = 0; |
| switch (cases) |
| { |
| case ASSIGNMENT_BEFORE_OPERATOR: |
| result = "just before assignment operator"; |
| break; |
| case ASSIGNMENT_AFTER_OPERATOR: |
| result = "just after assignment operator"; |
| break; |
| case VECTOR_VARIABLE_INITIALIZER: |
| result = "inside vector variable initializer"; |
| break; |
| case TOKEN_INSIDE_FUNCTION_NAME: |
| result = "inside function name"; |
| break; |
| case TOKEN_INSIDE_TYPE_NAME: |
| result = "inside type name"; |
| break; |
| case TOKEN_INSIDE_VARIABLE_NAME: |
| result = "inside variable name"; |
| break; |
| case PREPROCESSOR_TOKEN_INSIDE: |
| result = "inside preprocessor token"; |
| break; |
| case PREPROCESSOR_TOKEN_BETWEEN: |
| result = "between preprocessor token"; |
| break; |
| case COMMENT: |
| result = "inside comment"; |
| break; |
| case SOURCE_TERMINATION_NULL: |
| result = "just before null terminating source"; |
| break; |
| case SOURCE_TERMINATION_NON_NULL: |
| result = "as last character in source string, without null termination"; |
| break; |
| case PART_TERMINATION_NULL: |
| result = "just before null terminating part of source"; |
| break; |
| case PART_NEXT_TO_TERMINATION_NULL: |
| result = "just before last character in part of source"; |
| break; |
| case PART_TERMINATION_NON_NULL: |
| result = "as last character in part string, without null termination"; |
| break; |
| case PART_NEXT_TO_TERMINATION_NON_NULL: |
| result = "just before last character in part string, without null termination"; |
| break; |
| case DEBUG_CASE: /* intended fall through */ |
| default: |
| result = "nowhere at all. This is debug!"; |
| break; |
| } |
| |
| return result; |
| } |
| |
| /** Get expected value, blue color as vec4 |
| * |
| * @return blue color |
| **/ |
| const GLchar* LineContinuationTest::getExpectedValueString() const |
| { |
| return "vec4(0, 0, 1, 1)"; |
| } |
| |
| /** Get line continuation string, single or multiple \ |
| * |
| * @return String |
| **/ |
| std::string LineContinuationTest::getLineContinuationString() const |
| { |
| static const GLchar line_continuation_ending_dos[] = { '\\', 0x0d, 0x0a, 0x00 }; |
| static const GLchar line_continuation_ending_unix[] = { '\\', 0x0a, 0x00 }; |
| |
| std::string result; |
| const GLchar* selected_string; |
| |
| if (DOS == m_test_case.m_line_endings) |
| { |
| selected_string = line_continuation_ending_dos; |
| } |
| else |
| { |
| selected_string = line_continuation_ending_unix; |
| } |
| |
| GLuint n_repetitions = (ONCE == m_test_case.m_repetitions) ? 1 : m_n_repetitions; |
| |
| for (GLuint i = 0; i < n_repetitions; ++i) |
| { |
| result.append(selected_string); |
| } |
| |
| return result; |
| } |
| |
| /** Decides if shader should consist of multiple parts for the current test case |
| * |
| * @return true if test case requires multiple parts, false otherwise |
| **/ |
| bool LineContinuationTest::isShaderMultipart() const |
| { |
| bool result; |
| |
| switch (m_test_case.m_case) |
| { |
| case ASSIGNMENT_BEFORE_OPERATOR: |
| case ASSIGNMENT_AFTER_OPERATOR: |
| case VECTOR_VARIABLE_INITIALIZER: |
| case TOKEN_INSIDE_FUNCTION_NAME: |
| case TOKEN_INSIDE_TYPE_NAME: |
| case TOKEN_INSIDE_VARIABLE_NAME: |
| case PREPROCESSOR_TOKEN_INSIDE: |
| case PREPROCESSOR_TOKEN_BETWEEN: |
| case COMMENT: |
| case SOURCE_TERMINATION_NULL: |
| case SOURCE_TERMINATION_NON_NULL: |
| default: |
| result = false; |
| break; |
| case PART_TERMINATION_NULL: |
| case PART_NEXT_TO_TERMINATION_NULL: |
| case PART_TERMINATION_NON_NULL: |
| case PART_NEXT_TO_TERMINATION_NON_NULL: |
| result = true; |
| break; |
| }; |
| |
| return result; |
| } |
| |
| /** String describing line endings |
| * |
| * @param line_ending Line ending enum |
| * |
| * @return "unix" or "dos" strings |
| **/ |
| const GLchar* LineContinuationTest::lineEndingsToStr(LINE_ENDINGS line_ending) const |
| { |
| const GLchar* result = 0; |
| |
| if (UNIX == line_ending) |
| { |
| result = "unix"; |
| } |
| else |
| { |
| result = "dos"; |
| } |
| |
| return result; |
| } |
| |
| /** String describing number of repetitions |
| * |
| * @param repetitions Repetitions enum |
| * |
| * @return "single" or "multiple" strings |
| **/ |
| const GLchar* LineContinuationTest::repetitionsToStr(REPETITIONS repetitions) const |
| { |
| const GLchar* result = 0; |
| |
| if (ONCE == repetitions) |
| { |
| result = "single"; |
| } |
| else |
| { |
| result = "multiple"; |
| } |
| |
| return result; |
| } |
| |
| /** Replace all CASES tokens |
| * |
| * @param source String with shader template |
| **/ |
| void LineContinuationTest::replaceAllCaseTokens(std::string& source) const |
| { |
| |
| /* Tokens to be replaced with line continuation */ |
| static const GLchar* token_assignment_before_operator_case = "ASSIGNMENT_BEFORE_OPERATOR_CASE"; |
| static const GLchar* token_assignment_after_operator_case = "ASSIGNMENT_AFTER_OPERATOR_CASE"; |
| static const |