blob: 879efc0c461b3e1468fef00808f40d6699dddac1 [file] [log] [blame]
/*-------------------------------------------------------------------------
* 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 gl4GPUShaderFP64Tests.cpp
* \brief Implements conformance tests for "GPU Shader FP64" functionality.
*/ /*-------------------------------------------------------------------*/
#include "gl4cGPUShaderFP64Tests.hpp"
#include "gluContextInfo.hpp"
#include "glwFunctions.hpp"
#include "tcuMatrix.hpp"
#include "tcuTestLog.hpp"
#include <iomanip>
#include "deMath.h"
#include "deUniquePtr.hpp"
#include "tcuMatrixUtil.hpp"
#include "tcuVectorUtil.hpp"
#include <cstdlib>
#include <cstring>
#include <limits>
#include <memory>
namespace gl4cts
{
const glw::GLenum Utils::programInfo::ARB_COMPUTE_SHADER = 0x91B9;
/** Constructor
*
* @param context Test context
**/
Utils::programInfo::programInfo(deqp::Context& context)
: m_context(context)
, m_compute_shader_id(0)
, m_fragment_shader_id(0)
, m_geometry_shader_id(0)
, m_program_object_id(0)
, m_tesselation_control_shader_id(0)
, m_tesselation_evaluation_shader_id(0)
, m_vertex_shader_id(0)
{
/* Nothing to be done here */
}
/** Destructor
*
**/
Utils::programInfo::~programInfo()
{
/* GL entry points */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Make sure program object is no longer used by GL */
gl.useProgram(0);
/* Clean program object */
if (0 != m_program_object_id)
{
gl.deleteProgram(m_program_object_id);
m_program_object_id = 0;
}
/* Clean shaders */
if (0 != m_compute_shader_id)
{
gl.deleteShader(m_compute_shader_id);
m_compute_shader_id = 0;
}
if (0 != m_fragment_shader_id)
{
gl.deleteShader(m_fragment_shader_id);
m_fragment_shader_id = 0;
}
if (0 != m_geometry_shader_id)
{
gl.deleteShader(m_geometry_shader_id);
m_geometry_shader_id = 0;
}
if (0 != m_tesselation_control_shader_id)
{
gl.deleteShader(m_tesselation_control_shader_id);
m_tesselation_control_shader_id = 0;
}
if (0 != m_tesselation_evaluation_shader_id)
{
gl.deleteShader(m_tesselation_evaluation_shader_id);
m_tesselation_evaluation_shader_id = 0;
}
if (0 != m_vertex_shader_id)
{
gl.deleteShader(m_vertex_shader_id);
m_vertex_shader_id = 0;
}
}
/** Build program
*
* @param compute_shader_code Compute shader source code
* @param fragment_shader_code Fragment shader source code
* @param geometry_shader_code Geometry shader source code
* @param tesselation_control_shader_code Tesselation control shader source code
* @param tesselation_evaluation_shader_code Tesselation evaluation shader source code
* @param vertex_shader_code Vertex shader source code
* @param varying_names Array of strings containing names of varyings to be captured with transfrom feedback
* @param n_varying_names Number of varyings to be captured with transfrom feedback
**/
void Utils::programInfo::build(const glw::GLchar* compute_shader_code, const glw::GLchar* fragment_shader_code,
const glw::GLchar* geometry_shader_code,
const glw::GLchar* tesselation_control_shader_code,
const glw::GLchar* tesselation_evaluation_shader_code,
const glw::GLchar* vertex_shader_code, const glw::GLchar* const* varying_names,
glw::GLuint n_varying_names)
{
/* GL entry points */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Create shader objects and compile */
if (0 != compute_shader_code)
{
m_compute_shader_id = gl.createShader(ARB_COMPUTE_SHADER);
GLU_EXPECT_NO_ERROR(gl.getError(), "CreateShader");
compile(m_compute_shader_id, compute_shader_code);
}
if (0 != fragment_shader_code)
{
m_fragment_shader_id = gl.createShader(GL_FRAGMENT_SHADER);
GLU_EXPECT_NO_ERROR(gl.getError(), "CreateShader");
compile(m_fragment_shader_id, fragment_shader_code);
}
if (0 != geometry_shader_code)
{
m_geometry_shader_id = gl.createShader(GL_GEOMETRY_SHADER);
GLU_EXPECT_NO_ERROR(gl.getError(), "CreateShader");
compile(m_geometry_shader_id, geometry_shader_code);
}
if (0 != tesselation_control_shader_code)
{
m_tesselation_control_shader_id = gl.createShader(GL_TESS_CONTROL_SHADER);
GLU_EXPECT_NO_ERROR(gl.getError(), "CreateShader");
compile(m_tesselation_control_shader_id, tesselation_control_shader_code);
}
if (0 != tesselation_evaluation_shader_code)
{
m_tesselation_evaluation_shader_id = gl.createShader(GL_TESS_EVALUATION_SHADER);
GLU_EXPECT_NO_ERROR(gl.getError(), "CreateShader");
compile(m_tesselation_evaluation_shader_id, tesselation_evaluation_shader_code);
}
if (0 != vertex_shader_code)
{
m_vertex_shader_id = gl.createShader(GL_VERTEX_SHADER);
GLU_EXPECT_NO_ERROR(gl.getError(), "CreateShader");
compile(m_vertex_shader_id, vertex_shader_code);
}
/* Create program object */
m_program_object_id = gl.createProgram();
GLU_EXPECT_NO_ERROR(gl.getError(), "CreateProgram");
/* Set up captyured varyings' names */
if (0 != n_varying_names)
{
gl.transformFeedbackVaryings(m_program_object_id, n_varying_names, varying_names, GL_INTERLEAVED_ATTRIBS);
GLU_EXPECT_NO_ERROR(gl.getError(), "TransformFeedbackVaryings");
}
/* Link program */
link();
}
/** Compile shader
*
* @param shader_id Shader object id
* @param shader_code Shader source code
**/
void Utils::programInfo::compile(glw::GLuint shader_id, const glw::GLchar* shader_code) const
{
/* GL entry points */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Compilation status */
glw::GLint status = GL_FALSE;
/* Set source code */
gl.shaderSource(shader_id, 1 /* count */, &shader_code, 0);
GLU_EXPECT_NO_ERROR(gl.getError(), "ShaderSource");
/* Compile */
gl.compileShader(shader_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "CompileShader");
/* Get compilation status */
gl.getShaderiv(shader_id, GL_COMPILE_STATUS, &status);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetShaderiv");
/* Log compilation error */
if (GL_TRUE != status)
{
glw::GLint length = 0;
std::vector<glw::GLchar> message;
/* Error log length */
gl.getShaderiv(shader_id, GL_INFO_LOG_LENGTH, &length);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetShaderiv");
/* Prepare storage */
message.resize(length);
/* Get error log */
gl.getShaderInfoLog(shader_id, length, 0, &message[0]);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetShaderInfoLog");
/* Log */
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Failed to compile shader:\n"
<< &message[0] << "\nShader source\n"
<< shader_code << tcu::TestLog::EndMessage;
TCU_FAIL("Failed to compile shader");
}
}
/** Attach shaders and link program
*
**/
void Utils::programInfo::link() const
{
/* GL entry points */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Link status */
glw::GLint status = GL_FALSE;
/* Attach shaders */
if (0 != m_compute_shader_id)
{
gl.attachShader(m_program_object_id, m_compute_shader_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "AttachShader");
}
if (0 != m_fragment_shader_id)
{
gl.attachShader(m_program_object_id, m_fragment_shader_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "AttachShader");
}
if (0 != m_geometry_shader_id)
{
gl.attachShader(m_program_object_id, m_geometry_shader_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "AttachShader");
}
if (0 != m_tesselation_control_shader_id)
{
gl.attachShader(m_program_object_id, m_tesselation_control_shader_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "AttachShader");
}
if (0 != m_tesselation_evaluation_shader_id)
{
gl.attachShader(m_program_object_id, m_tesselation_evaluation_shader_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "AttachShader");
}
if (0 != m_vertex_shader_id)
{
gl.attachShader(m_program_object_id, m_vertex_shader_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "AttachShader");
}
/* Link */
gl.linkProgram(m_program_object_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "LinkProgram");
/* Get link status */
gl.getProgramiv(m_program_object_id, GL_LINK_STATUS, &status);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramiv");
/* Log link error */
if (GL_TRUE != status)
{
glw::GLint length = 0;
std::vector<glw::GLchar> message;
/* Get error log length */
gl.getProgramiv(m_program_object_id, GL_INFO_LOG_LENGTH, &length);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramiv");
message.resize(length);
/* Get error log */
gl.getProgramInfoLog(m_program_object_id, length, 0, &message[0]);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramInfoLog");
/* Log */
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Failed to link program:\n"
<< &message[0] << tcu::TestLog::EndMessage;
TCU_FAIL("Failed to link program");
}
}
/** Retrieves base type of user-provided variable type. (eg. VARIABLE_TYPE_DOUBLE for double-precision
* matrix types.
*
* @param type Variable type to return base type for.
*
* @return Requested value or VARAIBLE_TYPE_UNKNOWN if @param type was not recognized.
**/
Utils::_variable_type Utils::getBaseVariableType(_variable_type type)
{
_variable_type result = VARIABLE_TYPE_UNKNOWN;
switch (type)
{
case VARIABLE_TYPE_BOOL:
{
result = VARIABLE_TYPE_BOOL;
break;
}
case VARIABLE_TYPE_DOUBLE:
case VARIABLE_TYPE_DMAT2:
case VARIABLE_TYPE_DMAT2X3:
case VARIABLE_TYPE_DMAT2X4:
case VARIABLE_TYPE_DMAT3:
case VARIABLE_TYPE_DMAT3X2:
case VARIABLE_TYPE_DMAT3X4:
case VARIABLE_TYPE_DMAT4:
case VARIABLE_TYPE_DMAT4X2:
case VARIABLE_TYPE_DMAT4X3:
case VARIABLE_TYPE_DVEC2:
case VARIABLE_TYPE_DVEC3:
case VARIABLE_TYPE_DVEC4:
{
result = VARIABLE_TYPE_DOUBLE;
break;
}
case VARIABLE_TYPE_INT:
case VARIABLE_TYPE_IVEC2:
case VARIABLE_TYPE_IVEC3:
case VARIABLE_TYPE_IVEC4:
{
result = VARIABLE_TYPE_INT;
break;
}
case VARIABLE_TYPE_UINT:
case VARIABLE_TYPE_UVEC2:
case VARIABLE_TYPE_UVEC3:
case VARIABLE_TYPE_UVEC4:
{
result = VARIABLE_TYPE_UINT;
break;
}
case VARIABLE_TYPE_FLOAT:
case VARIABLE_TYPE_MAT2:
case VARIABLE_TYPE_MAT2X3:
case VARIABLE_TYPE_MAT2X4:
case VARIABLE_TYPE_MAT3:
case VARIABLE_TYPE_MAT3X2:
case VARIABLE_TYPE_MAT3X4:
case VARIABLE_TYPE_MAT4:
case VARIABLE_TYPE_MAT4X2:
case VARIABLE_TYPE_MAT4X3:
case VARIABLE_TYPE_VEC2:
case VARIABLE_TYPE_VEC3:
case VARIABLE_TYPE_VEC4:
{
result = VARIABLE_TYPE_FLOAT;
break;
}
default:
{
TCU_FAIL("Unrecognized variable type");
}
} /* switch (type) */
return result;
}
/** Returns size (in bytes) of a single component of a base variable type.
*
* @param type Base variable type to use for the query.
*
* @return Requested value or 0 if @param type was not recognized.
**/
unsigned int Utils::getBaseVariableTypeComponentSize(_variable_type type)
{
unsigned int result = 0;
switch (type)
{
case VARIABLE_TYPE_BOOL:
result = sizeof(bool);
break;
case VARIABLE_TYPE_DOUBLE:
result = sizeof(double);
break;
case VARIABLE_TYPE_FLOAT:
result = sizeof(float);
break;
case VARIABLE_TYPE_INT:
result = sizeof(int);
break;
case VARIABLE_TYPE_UINT:
result = sizeof(unsigned int);
break;
default:
{
TCU_FAIL("Unrecognized variable type");
}
} /* switch (type) */
return result;
}
/** Returns component, corresponding to user-specified index
* (eg. index:0 corresponds to 'x', index:1 corresponds to 'y',
* and so on.
*
* @param index Component index.
*
* @return As per description.
**/
unsigned char Utils::getComponentAtIndex(unsigned int index)
{
unsigned char result = '?';
switch (index)
{
case 0:
result = 'x';
break;
case 1:
result = 'y';
break;
case 2:
result = 'z';
break;
case 3:
result = 'w';
break;
default:
{
TCU_FAIL("Unrecognized component index");
}
}
return result;
}
/** Get _variable_type representing double-precision type with given dimmensions
*
* @param n_columns Number of columns
* @param n_row Number of rows
*
* @return Corresponding _variable_type
**/
Utils::_variable_type Utils::getDoubleVariableType(glw::GLuint n_columns, glw::GLuint n_rows)
{
Utils::_variable_type type = VARIABLE_TYPE_UNKNOWN;
static const _variable_type types[4][4] = {
{ VARIABLE_TYPE_DOUBLE, VARIABLE_TYPE_DVEC2, VARIABLE_TYPE_DVEC3, VARIABLE_TYPE_DVEC4 },
{ VARIABLE_TYPE_UNKNOWN, VARIABLE_TYPE_DMAT2, VARIABLE_TYPE_DMAT2X3, VARIABLE_TYPE_DMAT2X4 },
{ VARIABLE_TYPE_UNKNOWN, VARIABLE_TYPE_DMAT3X2, VARIABLE_TYPE_DMAT3, VARIABLE_TYPE_DMAT3X4 },
{ VARIABLE_TYPE_UNKNOWN, VARIABLE_TYPE_DMAT4X2, VARIABLE_TYPE_DMAT4X3, VARIABLE_TYPE_DMAT4 }
};
type = types[n_columns - 1][n_rows - 1];
return type;
}
/** Returns a single-precision equivalent of a double-precision floating-point variable
* type.
*
* @param type Double-precision variable type. Only VARIABLE_TYPE_D* variable types
* are accepted.
*
* @return Requested GLSL type.
**/
std::string Utils::getFPVariableTypeStringForVariableType(_variable_type type)
{
std::string result = "[?]";
switch (type)
{
case VARIABLE_TYPE_DOUBLE:
result = "float";
break;
case VARIABLE_TYPE_DMAT2:
result = "mat2";
break;
case VARIABLE_TYPE_DMAT2X3:
result = "mat2x3";
break;
case VARIABLE_TYPE_DMAT2X4:
result = "mat2x4";
break;
case VARIABLE_TYPE_DMAT3:
result = "mat3";
break;
case VARIABLE_TYPE_DMAT3X2:
result = "mat3x2";
break;
case VARIABLE_TYPE_DMAT3X4:
result = "mat3x4";
break;
case VARIABLE_TYPE_DMAT4:
result = "mat4";
break;
case VARIABLE_TYPE_DMAT4X2:
result = "mat4x2";
break;
case VARIABLE_TYPE_DMAT4X3:
result = "mat4x3";
break;
case VARIABLE_TYPE_DVEC2:
result = "vec2";
break;
case VARIABLE_TYPE_DVEC3:
result = "vec3";
break;
case VARIABLE_TYPE_DVEC4:
result = "vec4";
break;
default:
{
TCU_FAIL("Unrecognized variable type");
}
} /* switch (type) */
return result;
}
/** Returns GL data type enum corresponding to user-provided base variable type.
*
* @param type Base variable type to return corresponding GLenum value for.
*
* @return Corresponding GLenum value or GL_NONE if the input value was not
* recognized.
**/
glw::GLenum Utils::getGLDataTypeOfBaseVariableType(_variable_type type)
{
glw::GLenum result = GL_NONE;
switch (type)
{
case VARIABLE_TYPE_BOOL:
result = GL_BOOL;
break;
case VARIABLE_TYPE_DOUBLE:
result = GL_DOUBLE;
break;
case VARIABLE_TYPE_FLOAT:
result = GL_FLOAT;
break;
case VARIABLE_TYPE_INT:
result = GL_INT;
break;
case VARIABLE_TYPE_UINT:
result = GL_UNSIGNED_INT;
break;
default:
{
TCU_FAIL("Unrecognized variable type");
}
}
return result;
}
/** Return GLenum representing given <type>
*
* @param type Type of variable
*
* @return GL enumeration
**/
glw::GLenum Utils::getGLDataTypeOfVariableType(_variable_type type)
{
glw::GLenum result = GL_NONE;
switch (type)
{
case VARIABLE_TYPE_BOOL:
result = GL_BOOL;
break;
case VARIABLE_TYPE_DOUBLE:
result = GL_DOUBLE;
break;
case VARIABLE_TYPE_DMAT2:
result = GL_DOUBLE_MAT2;
break;
case VARIABLE_TYPE_DMAT2X3:
result = GL_DOUBLE_MAT2x3;
break;
case VARIABLE_TYPE_DMAT2X4:
result = GL_DOUBLE_MAT2x4;
break;
case VARIABLE_TYPE_DMAT3:
result = GL_DOUBLE_MAT3;
break;
case VARIABLE_TYPE_DMAT3X2:
result = GL_DOUBLE_MAT3x2;
break;
case VARIABLE_TYPE_DMAT3X4:
result = GL_DOUBLE_MAT3x4;
break;
case VARIABLE_TYPE_DMAT4:
result = GL_DOUBLE_MAT4;
break;
case VARIABLE_TYPE_DMAT4X2:
result = GL_DOUBLE_MAT4x2;
break;
case VARIABLE_TYPE_DMAT4X3:
result = GL_DOUBLE_MAT4x3;
break;
case VARIABLE_TYPE_DVEC2:
result = GL_DOUBLE_VEC2;
break;
case VARIABLE_TYPE_DVEC3:
result = GL_DOUBLE_VEC3;
break;
case VARIABLE_TYPE_DVEC4:
result = GL_DOUBLE_VEC4;
break;
case VARIABLE_TYPE_FLOAT:
result = GL_FLOAT;
break;
case VARIABLE_TYPE_INT:
result = GL_INT;
break;
case VARIABLE_TYPE_IVEC2:
result = GL_INT_VEC2;
break;
case VARIABLE_TYPE_IVEC3:
result = GL_INT_VEC3;
break;
case VARIABLE_TYPE_IVEC4:
result = GL_INT_VEC4;
break;
case VARIABLE_TYPE_MAT2:
result = GL_FLOAT_MAT2;
break;
case VARIABLE_TYPE_MAT2X3:
result = GL_FLOAT_MAT2x3;
break;
case VARIABLE_TYPE_MAT2X4:
result = GL_FLOAT_MAT2x4;
break;
case VARIABLE_TYPE_MAT3:
result = GL_FLOAT_MAT3;
break;
case VARIABLE_TYPE_MAT3X2:
result = GL_FLOAT_MAT3x2;
break;
case VARIABLE_TYPE_MAT3X4:
result = GL_FLOAT_MAT3x4;
break;
case VARIABLE_TYPE_MAT4:
result = GL_FLOAT_MAT4;
break;
case VARIABLE_TYPE_MAT4X2:
result = GL_FLOAT_MAT4x2;
break;
case VARIABLE_TYPE_MAT4X3:
result = GL_FLOAT_MAT4x3;
break;
case VARIABLE_TYPE_UINT:
result = GL_UNSIGNED_INT;
break;
case VARIABLE_TYPE_UVEC2:
result = GL_UNSIGNED_INT_VEC2;
break;
case VARIABLE_TYPE_UVEC3:
result = GL_UNSIGNED_INT_VEC3;
break;
case VARIABLE_TYPE_UVEC4:
result = GL_UNSIGNED_INT_VEC4;
break;
case VARIABLE_TYPE_VEC2:
result = GL_FLOAT_VEC2;
break;
case VARIABLE_TYPE_VEC3:
result = GL_FLOAT_VEC3;
break;
case VARIABLE_TYPE_VEC4:
result = GL_FLOAT_VEC4;
break;
default:
{
TCU_FAIL("Unrecognized variable type");
}
}
return result;
}
/** Get _variable_type representing integer type with given dimmensions
*
* @param n_columns Number of columns
* @param n_row Number of rows
*
* @return Corresponding _variable_type
**/
Utils::_variable_type Utils::getIntVariableType(glw::GLuint n_columns, glw::GLuint n_rows)
{
Utils::_variable_type type = VARIABLE_TYPE_UNKNOWN;
static const _variable_type types[4] = { VARIABLE_TYPE_INT, VARIABLE_TYPE_IVEC2, VARIABLE_TYPE_IVEC3,
VARIABLE_TYPE_IVEC4 };
if (1 != n_columns)
{
TCU_FAIL("Not implemented");
}
else
{
type = types[n_rows - 1];
}
return type;
}
/** Returns te number of components that variables defined with user-specified type
* support. For matrix types, total amount of values accessible for the type will be
* returned.
*
* @param type Variable type to return the described vale for.
*
* @return As per description or 0 if @param type was not recognized.
*/
unsigned int Utils::getNumberOfComponentsForVariableType(_variable_type type)
{
unsigned int result = 0;
switch (type)
{
case VARIABLE_TYPE_BOOL:
case VARIABLE_TYPE_DOUBLE:
case VARIABLE_TYPE_FLOAT:
case VARIABLE_TYPE_INT:
case VARIABLE_TYPE_UINT:
{
result = 1;
break;
}
case VARIABLE_TYPE_DVEC2:
case VARIABLE_TYPE_IVEC2:
case VARIABLE_TYPE_UVEC2:
case VARIABLE_TYPE_VEC2:
{
result = 2;
break;
}
case VARIABLE_TYPE_DVEC3:
case VARIABLE_TYPE_IVEC3:
case VARIABLE_TYPE_UVEC3:
case VARIABLE_TYPE_VEC3:
{
result = 3;
break;
}
case VARIABLE_TYPE_DVEC4:
case VARIABLE_TYPE_IVEC4:
case VARIABLE_TYPE_UVEC4:
case VARIABLE_TYPE_VEC4:
{
result = 4;
break;
}
case VARIABLE_TYPE_DMAT2:
case VARIABLE_TYPE_MAT2:
{
result = 2 * 2;
break;
}
case VARIABLE_TYPE_DMAT2X3:
case VARIABLE_TYPE_DMAT3X2:
case VARIABLE_TYPE_MAT2X3:
case VARIABLE_TYPE_MAT3X2:
{
result = 2 * 3;
break;
}
case VARIABLE_TYPE_DMAT2X4:
case VARIABLE_TYPE_DMAT4X2:
case VARIABLE_TYPE_MAT2X4:
case VARIABLE_TYPE_MAT4X2:
{
result = 2 * 4;
break;
}
case VARIABLE_TYPE_DMAT3:
case VARIABLE_TYPE_MAT3:
{
result = 3 * 3;
break;
}
case VARIABLE_TYPE_DMAT3X4:
case VARIABLE_TYPE_DMAT4X3:
case VARIABLE_TYPE_MAT3X4:
case VARIABLE_TYPE_MAT4X3:
{
result = 3 * 4;
break;
}
case VARIABLE_TYPE_DMAT4:
case VARIABLE_TYPE_MAT4:
{
result = 4 * 4;
break;
}
default:
{
TCU_FAIL("Unrecognized type");
}
} /* switch (type) */
return result;
}
/** Returns number of columns user-specified matrix variable type describes.
*
* @param type Variable type to use for the query. Only VARIABLE_TYPE_DMAT*
* values are valid.
*
* @return As per description.
**/
unsigned int Utils::getNumberOfColumnsForVariableType(_variable_type type)
{
unsigned int result = 0;
switch (type)
{
case VARIABLE_TYPE_BOOL:
case VARIABLE_TYPE_DOUBLE:
case VARIABLE_TYPE_FLOAT:
case VARIABLE_TYPE_INT:
case VARIABLE_TYPE_UINT:
case VARIABLE_TYPE_DVEC2:
case VARIABLE_TYPE_IVEC2:
case VARIABLE_TYPE_UVEC2:
case VARIABLE_TYPE_VEC2:
case VARIABLE_TYPE_DVEC3:
case VARIABLE_TYPE_IVEC3:
case VARIABLE_TYPE_UVEC3:
case VARIABLE_TYPE_VEC3:
case VARIABLE_TYPE_DVEC4:
case VARIABLE_TYPE_IVEC4:
case VARIABLE_TYPE_UVEC4:
case VARIABLE_TYPE_VEC4:
{
result = 1;
break;
}
case VARIABLE_TYPE_DMAT2:
case VARIABLE_TYPE_DMAT2X3:
case VARIABLE_TYPE_DMAT2X4:
case VARIABLE_TYPE_MAT2:
case VARIABLE_TYPE_MAT2X3:
case VARIABLE_TYPE_MAT2X4:
{
result = 2;
break;
}
case VARIABLE_TYPE_DMAT3:
case VARIABLE_TYPE_DMAT3X2:
case VARIABLE_TYPE_DMAT3X4:
case VARIABLE_TYPE_MAT3:
case VARIABLE_TYPE_MAT3X2:
case VARIABLE_TYPE_MAT3X4:
{
result = 3;
break;
}
case VARIABLE_TYPE_DMAT4:
case VARIABLE_TYPE_DMAT4X2:
case VARIABLE_TYPE_DMAT4X3:
case VARIABLE_TYPE_MAT4:
case VARIABLE_TYPE_MAT4X2:
case VARIABLE_TYPE_MAT4X3:
{
result = 4;
break;
}
default:
{
TCU_FAIL("Unrecognized type");
}
} /* switch (type) */
return result;
}
/** Returns maximum number of uniform locations taken by user-specified double-precision
* variable type.
*
* @param type Variable type to use for the query. Only VARIABLE_TYPE_D* values are valid.
*
* @return As per description.
**/
unsigned int Utils::getNumberOfLocationsUsedByDoublePrecisionVariableType(_variable_type type)
{
unsigned int result = 0;
switch (type)
{
case VARIABLE_TYPE_DOUBLE:
result = 1;
break;
case VARIABLE_TYPE_DVEC2:
result = 1;
break;
case VARIABLE_TYPE_DVEC3:
result = 2;
break;
case VARIABLE_TYPE_DVEC4:
result = 2;
break;
case VARIABLE_TYPE_DMAT2:
result = 2;
break;
case VARIABLE_TYPE_DMAT2X3:
result = 6;
break;
case VARIABLE_TYPE_DMAT2X4:
result = 8;
break;
case VARIABLE_TYPE_DMAT3:
result = 6;
break;
case VARIABLE_TYPE_DMAT3X2:
result = 4;
break;
case VARIABLE_TYPE_DMAT3X4:
result = 8;
break;
case VARIABLE_TYPE_DMAT4:
result = 8;
break;
case VARIABLE_TYPE_DMAT4X2:
result = 4;
break;
case VARIABLE_TYPE_DMAT4X3:
result = 6;
break;
default:
{
TCU_FAIL("Unrecognized type");
}
} /* switch (type) */
return result;
}
/** Get number of rows for given variable type
*
* @param type Type of variable
*
* @return Number of rows
**/
unsigned int Utils::getNumberOfRowsForVariableType(_variable_type type)
{
unsigned int result = 0;
switch (type)
{
case VARIABLE_TYPE_BOOL:
case VARIABLE_TYPE_DOUBLE:
case VARIABLE_TYPE_FLOAT:
case VARIABLE_TYPE_INT:
case VARIABLE_TYPE_UINT:
{
result = 1;
break;
}
case VARIABLE_TYPE_DVEC2:
case VARIABLE_TYPE_IVEC2:
case VARIABLE_TYPE_UVEC2:
case VARIABLE_TYPE_VEC2:
case VARIABLE_TYPE_DMAT2:
case VARIABLE_TYPE_DMAT3X2:
case VARIABLE_TYPE_DMAT4X2:
case VARIABLE_TYPE_MAT2:
case VARIABLE_TYPE_MAT3X2:
case VARIABLE_TYPE_MAT4X2:
{
result = 2;
break;
}
case VARIABLE_TYPE_DVEC3:
case VARIABLE_TYPE_IVEC3:
case VARIABLE_TYPE_UVEC3:
case VARIABLE_TYPE_VEC3:
case VARIABLE_TYPE_DMAT2X3:
case VARIABLE_TYPE_DMAT3:
case VARIABLE_TYPE_DMAT4X3:
case VARIABLE_TYPE_MAT2X3:
case VARIABLE_TYPE_MAT3:
case VARIABLE_TYPE_MAT4X3:
{
result = 3;
break;
}
case VARIABLE_TYPE_DVEC4:
case VARIABLE_TYPE_IVEC4:
case VARIABLE_TYPE_UVEC4:
case VARIABLE_TYPE_VEC4:
case VARIABLE_TYPE_DMAT2X4:
case VARIABLE_TYPE_DMAT3X4:
case VARIABLE_TYPE_DMAT4:
case VARIABLE_TYPE_MAT2X4:
case VARIABLE_TYPE_MAT3X4:
case VARIABLE_TYPE_MAT4:
{
result = 4;
break;
}
default:
{
TCU_FAIL("Unrecognized type");
}
} /* switch (type) */
return result;
}
/** Returns variable type of a matrix constructed by multiplying two matrices.
*
* @param type_matrix_a L-side matrix type.
* @param type_matrix_b R-side matrix type.
*
* @return As per description.
**/
Utils::_variable_type Utils::getPostMatrixMultiplicationVariableType(_variable_type type_matrix_a,
_variable_type type_matrix_b)
{
const unsigned int n_a_columns = Utils::getNumberOfColumnsForVariableType(type_matrix_a);
const unsigned int n_a_components = Utils::getNumberOfComponentsForVariableType(type_matrix_a);
const unsigned int n_a_rows = n_a_components / n_a_columns;
const unsigned int n_b_columns = Utils::getNumberOfColumnsForVariableType(type_matrix_b);
const unsigned int n_result_columns = n_b_columns;
const unsigned int n_result_rows = n_a_rows;
Utils::_variable_type result;
switch (n_result_columns)
{
case 2:
{
switch (n_result_rows)
{
case 2:
result = VARIABLE_TYPE_DMAT2;
break;
case 3:
result = VARIABLE_TYPE_DMAT2X3;
break;
case 4:
result = VARIABLE_TYPE_DMAT2X4;
break;
default:
{
TCU_FAIL("Unrecognized amount of rows in result variable");
}
} /* switch (n_result_rows) */
break;
} /* case 2: */
case 3:
{
switch (n_result_rows)
{
case 2:
result = VARIABLE_TYPE_DMAT3X2;
break;
case 3:
result = VARIABLE_TYPE_DMAT3;
break;
case 4:
result = VARIABLE_TYPE_DMAT3X4;
break;
default:
{
TCU_FAIL("Unrecognized amount of rows in result variable");
}
} /* switch (n_result_rows) */
break;
} /* case 3: */
case 4:
{
switch (n_result_rows)
{
case 2:
result = VARIABLE_TYPE_DMAT4X2;
break;
case 3:
result = VARIABLE_TYPE_DMAT4X3;
break;
case 4:
result = VARIABLE_TYPE_DMAT4;
break;
default:
{
TCU_FAIL("Unrecognized amount of rows in result variable");
}
} /* switch (n_result_rows) */
break;
} /* case 4: */
default:
{
TCU_FAIL("Unrecognized amount of columns in result variable");
}
} /* switch (n_result_columns) */
/* Done */
return result;
}
/** Returns a string holding the value represented by user-provided variable, for which
* the data are represented in @param type variable type.
*
* @return As per description.
**/
std::string Utils::getStringForVariableTypeValue(_variable_type type, const unsigned char* data_ptr)
{
std::stringstream result_sstream;
switch (type)
{
case VARIABLE_TYPE_BOOL:
result_sstream << *((bool*)data_ptr);
break;
case VARIABLE_TYPE_DOUBLE:
result_sstream << *((double*)data_ptr);
break;
case VARIABLE_TYPE_FLOAT:
result_sstream << *((float*)data_ptr);
break;
case VARIABLE_TYPE_INT:
result_sstream << *((int*)data_ptr);
break;
case VARIABLE_TYPE_UINT:
result_sstream << *((unsigned int*)data_ptr);
break;
default:
{
TCU_FAIL("Unrecognized variable type requested");
}
} /* switch (type) */
return result_sstream.str();
}
/** Returns variable type of a transposed matrix of user-specified variable type.
*
* @param type Variable type of the matrix to be transposed.
*
* @return Transposed matrix variable type.
**/
Utils::_variable_type Utils::getTransposedMatrixVariableType(Utils::_variable_type type)
{
Utils::_variable_type result;
switch (type)
{
case VARIABLE_TYPE_DMAT2:
result = VARIABLE_TYPE_DMAT2;
break;
case VARIABLE_TYPE_DMAT2X3:
result = VARIABLE_TYPE_DMAT3X2;
break;
case VARIABLE_TYPE_DMAT2X4:
result = VARIABLE_TYPE_DMAT4X2;
break;
case VARIABLE_TYPE_DMAT3:
result = VARIABLE_TYPE_DMAT3;
break;
case VARIABLE_TYPE_DMAT3X2:
result = VARIABLE_TYPE_DMAT2X3;
break;
case VARIABLE_TYPE_DMAT3X4:
result = VARIABLE_TYPE_DMAT4X3;
break;
case VARIABLE_TYPE_DMAT4:
result = VARIABLE_TYPE_DMAT4;
break;
case VARIABLE_TYPE_DMAT4X2:
result = VARIABLE_TYPE_DMAT2X4;
break;
case VARIABLE_TYPE_DMAT4X3:
result = VARIABLE_TYPE_DMAT3X4;
break;
default:
{
TCU_FAIL("Unrecognized double-precision matrix variable type.");
}
} /* switch (type) */
return result;
}
/** Get _variable_type representing unsigned integer type with given dimmensions
*
* @param n_columns Number of columns
* @param n_row Number of rows
*
* @return Corresponding _variable_type
**/
Utils::_variable_type Utils::getUintVariableType(glw::GLuint n_columns, glw::GLuint n_rows)
{
Utils::_variable_type type = VARIABLE_TYPE_UNKNOWN;
static const _variable_type types[4] = { VARIABLE_TYPE_UINT, VARIABLE_TYPE_UVEC2, VARIABLE_TYPE_UVEC3,
VARIABLE_TYPE_UVEC4 };
if (1 != n_columns)
{
TCU_FAIL("Not implemented");
}
else
{
type = types[n_rows - 1];
}
return type;
}
/** Returns a literal corresponding to a GLSL keyword describing user-specified
* variable type.
*
* @param type Variable type to use for the query.
*
* @return Requested GLSL keyword or [?] if @param type was not recognized.
**/
std::string Utils::getVariableTypeString(_variable_type type)
{
std::string result = "[?]";
switch (type)
{
case VARIABLE_TYPE_BOOL:
result = "bool";
break;
case VARIABLE_TYPE_BVEC2:
result = "bvec2";
break;
case VARIABLE_TYPE_BVEC3:
result = "bvec3";
break;
case VARIABLE_TYPE_BVEC4:
result = "bvec4";
break;
case VARIABLE_TYPE_DOUBLE:
result = "double";
break;
case VARIABLE_TYPE_DMAT2:
result = "dmat2";
break;
case VARIABLE_TYPE_DMAT2X3:
result = "dmat2x3";
break;
case VARIABLE_TYPE_DMAT2X4:
result = "dmat2x4";
break;
case VARIABLE_TYPE_DMAT3:
result = "dmat3";
break;
case VARIABLE_TYPE_DMAT3X2:
result = "dmat3x2";
break;
case VARIABLE_TYPE_DMAT3X4:
result = "dmat3x4";
break;
case VARIABLE_TYPE_DMAT4:
result = "dmat4";
break;
case VARIABLE_TYPE_DMAT4X2:
result = "dmat4x2";
break;
case VARIABLE_TYPE_DMAT4X3:
result = "dmat4x3";
break;
case VARIABLE_TYPE_DVEC2:
result = "dvec2";
break;
case VARIABLE_TYPE_DVEC3:
result = "dvec3";
break;
case VARIABLE_TYPE_DVEC4:
result = "dvec4";
break;
case VARIABLE_TYPE_FLOAT:
result = "float";
break;
case VARIABLE_TYPE_INT:
result = "int";
break;
case VARIABLE_TYPE_IVEC2:
result = "ivec2";
break;
case VARIABLE_TYPE_IVEC3:
result = "ivec3";
break;
case VARIABLE_TYPE_IVEC4:
result = "ivec4";
break;
case VARIABLE_TYPE_MAT2:
result = "mat2";
break;
case VARIABLE_TYPE_MAT2X3:
result = "mat2x3";
break;
case VARIABLE_TYPE_MAT2X4:
result = "mat2x4";
break;
case VARIABLE_TYPE_MAT3:
result = "mat3";
break;
case VARIABLE_TYPE_MAT3X2:
result = "mat3x2";
break;
case VARIABLE_TYPE_MAT3X4:
result = "mat3x4";
break;
case VARIABLE_TYPE_MAT4:
result = "mat4";
break;
case VARIABLE_TYPE_MAT4X2:
result = "mat4x2";
break;
case VARIABLE_TYPE_MAT4X3:
result = "mat4x3";
break;
case VARIABLE_TYPE_UINT:
result = "uint";
break;
case VARIABLE_TYPE_UVEC2:
result = "uvec2";
break;
case VARIABLE_TYPE_UVEC3:
result = "uvec3";
break;
case VARIABLE_TYPE_UVEC4:
result = "uvec4";
break;
case VARIABLE_TYPE_VEC2:
result = "vec2";
break;
case VARIABLE_TYPE_VEC3:
result = "vec3";
break;
case VARIABLE_TYPE_VEC4:
result = "vec4";
break;
default:
{
TCU_FAIL("Unrecognized variable type");
}
} /* switch (type) */
return result;
}
/** 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;
}
}
/** Tells whether user-specified variable type corresponds to a matrix type.
*
* @param type Variable type to use for the query.
*
* @return true if the variable type describes a matrix, false otherwise.
**/
bool Utils::isMatrixVariableType(_variable_type type)
{
return (type == VARIABLE_TYPE_MAT2 || type == VARIABLE_TYPE_MAT3 || type == VARIABLE_TYPE_MAT4 ||
type == VARIABLE_TYPE_MAT2X3 || type == VARIABLE_TYPE_MAT2X4 || type == VARIABLE_TYPE_MAT3X2 ||
type == VARIABLE_TYPE_MAT3X4 || type == VARIABLE_TYPE_MAT4X2 || type == VARIABLE_TYPE_MAT4X3 ||
type == VARIABLE_TYPE_DMAT2 || type == VARIABLE_TYPE_DMAT3 || type == VARIABLE_TYPE_DMAT4 ||
type == VARIABLE_TYPE_DMAT2X3 || type == VARIABLE_TYPE_DMAT2X4 || type == VARIABLE_TYPE_DMAT3X2 ||
type == VARIABLE_TYPE_DMAT3X4 || type == VARIABLE_TYPE_DMAT4X2 || type == VARIABLE_TYPE_DMAT4X3);
}
/** Tells whether user-specified variable type is scalar.
*
* @return true if @param type is a scalar variable type, false otherwise.
**/
bool Utils::isScalarVariableType(_variable_type type)
{
bool result = false;
switch (type)
{
case VARIABLE_TYPE_BOOL:
result = true;
break;
case VARIABLE_TYPE_DOUBLE:
result = true;
break;
case VARIABLE_TYPE_FLOAT:
result = true;
break;
case VARIABLE_TYPE_INT:
result = true;
break;
case VARIABLE_TYPE_UINT:
result = true;
break;
default:
break;
} /* switch (type) */
return result;
}
/** 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;
}
/** Constructor.
*
* @param context Rendering context.
*
**/
GPUShaderFP64Test1::GPUShaderFP64Test1(deqp::Context& context)
: TestCase(context, "errors", "Verifies that various erroneous conditions related to double-precision "
"float uniform support & glUniform*() / glUniformMatrix*() API "
" are reported correctly.")
, m_has_test_passed(true)
, m_po_bool_arr_uniform_location(0)
, m_po_bool_uniform_location(0)
, m_po_bvec2_arr_uniform_location(0)
, m_po_bvec2_uniform_location(0)
, m_po_bvec3_arr_uniform_location(0)
, m_po_bvec3_uniform_location(0)
, m_po_bvec4_arr_uniform_location(0)
, m_po_bvec4_uniform_location(0)
, m_po_dmat2_arr_uniform_location(0)
, m_po_dmat2_uniform_location(0)
, m_po_dmat2x3_arr_uniform_location(0)
, m_po_dmat2x3_uniform_location(0)
, m_po_dmat2x4_arr_uniform_location(0)
, m_po_dmat2x4_uniform_location(0)
, m_po_dmat3_arr_uniform_location(0)
, m_po_dmat3_uniform_location(0)
, m_po_dmat3x2_arr_uniform_location(0)
, m_po_dmat3x2_uniform_location(0)
, m_po_dmat3x4_arr_uniform_location(0)
, m_po_dmat3x4_uniform_location(0)
, m_po_dmat4_arr_uniform_location(0)
, m_po_dmat4_uniform_location(0)
, m_po_dmat4x2_arr_uniform_location(0)
, m_po_dmat4x2_uniform_location(0)
, m_po_dmat4x3_arr_uniform_location(0)
, m_po_dmat4x3_uniform_location(0)
, m_po_double_arr_uniform_location(0)
, m_po_double_uniform_location(0)
, m_po_dvec2_arr_uniform_location(0)
, m_po_dvec2_uniform_location(0)
, m_po_dvec3_arr_uniform_location(0)
, m_po_dvec3_uniform_location(0)
, m_po_dvec4_arr_uniform_location(0)
, m_po_dvec4_uniform_location(0)
, m_po_float_arr_uniform_location(0)
, m_po_float_uniform_location(0)
, m_po_int_arr_uniform_location(0)
, m_po_int_uniform_location(0)
, m_po_ivec2_arr_uniform_location(0)
, m_po_ivec2_uniform_location(0)
, m_po_ivec3_arr_uniform_location(0)
, m_po_ivec3_uniform_location(0)
, m_po_ivec4_arr_uniform_location(0)
, m_po_ivec4_uniform_location(0)
, m_po_sampler_uniform_location(0)
, m_po_uint_arr_uniform_location(0)
, m_po_uint_uniform_location(0)
, m_po_uvec2_arr_uniform_location(0)
, m_po_uvec2_uniform_location(0)
, m_po_uvec3_arr_uniform_location(0)
, m_po_uvec3_uniform_location(0)
, m_po_uvec4_arr_uniform_location(0)
, m_po_uvec4_uniform_location(0)
, m_po_vec2_arr_uniform_location(0)
, m_po_vec2_uniform_location(0)
, m_po_vec3_arr_uniform_location(0)
, m_po_vec3_uniform_location(0)
, m_po_vec4_arr_uniform_location(0)
, m_po_vec4_uniform_location(0)
, m_po_id(0)
, m_vs_id(0)
{
/* Left blank intentionally */
}
/** Deinitializes all GL objects that may have been created during
* test execution.
**/
void GPUShaderFP64Test1::deinit()
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
if (m_po_id != 0)
{
gl.deleteProgram(m_po_id);
m_po_id = 0;
}
if (m_vs_id != 0)
{
gl.deleteShader(m_vs_id);
m_vs_id = 0;
}
}
/** Returns a string describing GL API function represented by user-provided enum.
*
* @param func Uniform function to return the string for.
*
* @return As per description. [?] will be returned if the function was not recognized.
**/
const char* GPUShaderFP64Test1::getUniformFunctionString(_uniform_function func)
{
const char* result = "[?]";
switch (func)
{
case UNIFORM_FUNCTION_1D:
result = "glUniform1d";
break;
case UNIFORM_FUNCTION_1DV:
result = "glUniform1dv";
break;
case UNIFORM_FUNCTION_2D:
result = "glUniform2d";
break;
case UNIFORM_FUNCTION_2DV:
result = "glUniform2dv";
break;
case UNIFORM_FUNCTION_3D:
result = "glUniform3d";
break;
case UNIFORM_FUNCTION_3DV:
result = "glUniform3dv";
break;
case UNIFORM_FUNCTION_4D:
result = "glUniform4d";
break;
case UNIFORM_FUNCTION_4DV:
result = "glUniform4dv";
break;
case UNIFORM_FUNCTION_MATRIX2DV:
result = "glUniformMatrix2dv";
break;
case UNIFORM_FUNCTION_MATRIX2X3DV:
result = "glUniformMatrix2x3dv";
break;
case UNIFORM_FUNCTION_MATRIX2X4DV:
result = "glUniformMatrix2x4dv";
break;
case UNIFORM_FUNCTION_MATRIX3DV:
result = "glUniformMatrix3dv";
break;
case UNIFORM_FUNCTION_MATRIX3X2DV:
result = "glUniformMatrix3x2dv";
break;
case UNIFORM_FUNCTION_MATRIX3X4DV:
result = "glUniformMatrix3x4dv";
break;
case UNIFORM_FUNCTION_MATRIX4DV:
result = "glUniformMatrix4dv";
break;
case UNIFORM_FUNCTION_MATRIX4X2DV:
result = "glUniformMatrix4x2dv";
break;
case UNIFORM_FUNCTION_MATRIX4X3DV:
result = "glUniformMatrix4x3dv";
break;
default:
break;
}
return result;
}
/** Returns name of an uniform bound to user-provided location.
*
* @param location Location of the uniform to return the name for.
*
* @return As per description. [?] will be returned if the location was not
* recognized.
**/
const char* GPUShaderFP64Test1::getUniformNameForLocation(glw::GLint location)
{
const char* result = "[?]";
if (location == m_po_bool_arr_uniform_location)
result = "uniform_bool_arr";
else if (location == m_po_bool_uniform_location)
result = "uniform_bool";
else if (location == m_po_bvec2_arr_uniform_location)
result = "uniform_bvec2_arr";
else if (location == m_po_bvec2_uniform_location)
result = "uniform_bvec2";
else if (location == m_po_bvec3_arr_uniform_location)
result = "uniform_bvec3_arr";
else if (location == m_po_bvec3_uniform_location)
result = "uniform_bvec3";
else if (location == m_po_bvec4_arr_uniform_location)
result = "uniform_bvec4_arr";
else if (location == m_po_bvec4_uniform_location)
result = "uniform_bvec4";
else if (location == m_po_dmat2_arr_uniform_location)
result = "uniform_dmat2_arr";
else if (location == m_po_dmat2_uniform_location)
result = "uniform_dmat2";
else if (location == m_po_dmat2x3_arr_uniform_location)
result = "uniform_dmat2x3_arr";
else if (location == m_po_dmat2x3_uniform_location)
result = "uniform_dmat2x3";
else if (location == m_po_dmat2x4_arr_uniform_location)
result = "uniform_dmat2x4_arr";
else if (location == m_po_dmat2x4_uniform_location)
result = "uniform_dmat2x4";
else if (location == m_po_dmat3_arr_uniform_location)
result = "uniform_dmat3_arr";
else if (location == m_po_dmat3_uniform_location)
result = "uniform_dmat3";
else if (location == m_po_dmat3x2_arr_uniform_location)
result = "uniform_dmat3x2_arr";
else if (location == m_po_dmat3x2_uniform_location)
result = "uniform_dmat3x2";
else if (location == m_po_dmat3x4_arr_uniform_location)
result = "uniform_dmat3x4_arr";
else if (location == m_po_dmat3x4_uniform_location)
result = "uniform_dmat3x4";
else if (location == m_po_dmat4_arr_uniform_location)
result = "uniform_dmat4_arr";
else if (location == m_po_dmat4_uniform_location)
result = "uniform_dmat4";
else if (location == m_po_dmat4x2_arr_uniform_location)
result = "uniform_dmat4x2_arr";
else if (location == m_po_dmat4x2_uniform_location)
result = "uniform_dmat4x2";
else if (location == m_po_dmat4x3_arr_uniform_location)
result = "uniform_dmat4x3_arr";
else if (location == m_po_dmat4x3_uniform_location)
result = "uniform_dmat4x3";
else if (location == m_po_double_arr_uniform_location)
result = "uniform_double_arr";
else if (location == m_po_double_uniform_location)
result = "uniform_double";
else if (location == m_po_dvec2_arr_uniform_location)
result = "uniform_dvec2_arr";
else if (location == m_po_dvec2_uniform_location)
result = "uniform_dvec2";
else if (location == m_po_dvec3_arr_uniform_location)
result = "uniform_dvec3_arr";
else if (location == m_po_dvec3_uniform_location)
result = "uniform_dvec3";
else if (location == m_po_dvec4_arr_uniform_location)
result = "uniform_dvec4_arr";
else if (location == m_po_dvec4_uniform_location)
result = "uniform_dvec4";
else if (location == m_po_float_arr_uniform_location)
result = "uniform_float_arr";
else if (location == m_po_float_uniform_location)
result = "uniform_float";
else if (location == m_po_int_arr_uniform_location)
result = "uniform_int_arr";
else if (location == m_po_int_uniform_location)
result = "uniform_int";
else if (location == m_po_ivec2_arr_uniform_location)
result = "uniform_ivec2_arr";
else if (location == m_po_ivec2_uniform_location)
result = "uniform_ivec2";
else if (location == m_po_ivec3_arr_uniform_location)
result = "uniform_ivec3_arr";
else if (location == m_po_ivec3_uniform_location)
result = "uniform_ivec3";
else if (location == m_po_ivec4_arr_uniform_location)
result = "uniform_ivec4_arr";
else if (location == m_po_ivec4_uniform_location)
result = "uniform_ivec4";
else if (location == m_po_uint_arr_uniform_location)
result = "uniform_uint_arr";
else if (location == m_po_uint_uniform_location)
result = "uniform_uint";
else if (location == m_po_uvec2_arr_uniform_location)
result = "uniform_uvec2_arr";
else if (location == m_po_uvec2_uniform_location)
result = "uniform_uvec2";
else if (location == m_po_uvec3_arr_uniform_location)
result = "uniform_uvec3_arr";
else if (location == m_po_uvec3_uniform_location)
result = "uniform_uvec3";
else if (location == m_po_uvec4_arr_uniform_location)
result = "uniform_uvec4_arr";
else if (location == m_po_uvec4_uniform_location)
result = "uniform_uvec4";
else if (location == m_po_vec2_arr_uniform_location)
result = "uniform_vec2_arr";
else if (location == m_po_vec2_uniform_location)
result = "uniform_vec2";
else if (location == m_po_vec3_arr_uniform_location)
result = "uniform_vec3_arr";
else if (location == m_po_vec3_uniform_location)
result = "uniform_vec3";
else if (location == m_po_vec4_arr_uniform_location)
result = "uniform_vec4_arr";
else if (location == m_po_vec4_uniform_location)
result = "uniform_vec4";
return result;
}
/** Initializes all GL objects required to run the test. Also extracts locations of all
* uniforms used by the test.
*
* This function can throw a TestError exception if the implementation misbehaves.
*/
void GPUShaderFP64Test1::initTest()
{
glw::GLint compile_status = GL_FALSE;
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
glw::GLint link_status = GL_FALSE;
/* Set up a program object using all new double-precision types */
const char* vs_body =
"#version 400\n"
"\n"
"uniform bool uniform_bool;\n"
"uniform bvec2 uniform_bvec2;\n"
"uniform bvec3 uniform_bvec3;\n"
"uniform bvec4 uniform_bvec4;\n"
"uniform dmat2 uniform_dmat2;\n"
"uniform dmat2x3 uniform_dmat2x3;\n"
"uniform dmat2x4 uniform_dmat2x4;\n"
"uniform dmat3 uniform_dmat3;\n"
"uniform dmat3x2 uniform_dmat3x2;\n"
"uniform dmat3x4 uniform_dmat3x4;\n"
"uniform dmat4 uniform_dmat4;\n"
"uniform dmat4x2 uniform_dmat4x2;\n"
"uniform dmat4x3 uniform_dmat4x3;\n"
"uniform double uniform_double;\n"
"uniform dvec2 uniform_dvec2;\n"
"uniform dvec3 uniform_dvec3;\n"
"uniform dvec4 uniform_dvec4;\n"
"uniform float uniform_float;\n"
"uniform int uniform_int;\n"
"uniform ivec2 uniform_ivec2;\n"
"uniform ivec3 uniform_ivec3;\n"
"uniform ivec4 uniform_ivec4;\n"
"uniform sampler2D uniform_sampler;\n"
"uniform uint uniform_uint;\n"
"uniform uvec2 uniform_uvec2;\n"
"uniform uvec3 uniform_uvec3;\n"
"uniform uvec4 uniform_uvec4;\n"
"uniform vec2 uniform_vec2;\n"
"uniform vec3 uniform_vec3;\n"
"uniform vec4 uniform_vec4;\n"
"uniform bool uniform_bool_arr [2];\n"
"uniform bvec2 uniform_bvec2_arr [2];\n"
"uniform bvec3 uniform_bvec3_arr [2];\n"
"uniform bvec4 uniform_bvec4_arr [2];\n"
"uniform dmat2 uniform_dmat2_arr [2];\n"
"uniform dmat2x3 uniform_dmat2x3_arr[2];\n"
"uniform dmat2x4 uniform_dmat2x4_arr[2];\n"
"uniform dmat3 uniform_dmat3_arr [2];\n"
"uniform dmat3x2 uniform_dmat3x2_arr[2];\n"
"uniform dmat3x4 uniform_dmat3x4_arr[2];\n"
"uniform dmat4 uniform_dmat4_arr [2];\n"
"uniform dmat4x2 uniform_dmat4x2_arr[2];\n"
"uniform dmat4x3 uniform_dmat4x3_arr[2];\n"
"uniform double uniform_double_arr [2];\n"
"uniform dvec2 uniform_dvec2_arr [2];\n"
"uniform dvec3 uniform_dvec3_arr [2];\n"
"uniform dvec4 uniform_dvec4_arr [2];\n"
"uniform float uniform_float_arr [2];\n"
"uniform int uniform_int_arr [2];\n"
"uniform ivec2 uniform_ivec2_arr [2];\n"
"uniform ivec3 uniform_ivec3_arr [2];\n"
"uniform ivec4 uniform_ivec4_arr [2];\n"
"uniform uint uniform_uint_arr [2];\n"
"uniform uvec2 uniform_uvec2_arr [2];\n"
"uniform uvec3 uniform_uvec3_arr [2];\n"
"uniform uvec4 uniform_uvec4_arr [2];\n"
"uniform vec2 uniform_vec2_arr [2];\n"
"uniform vec3 uniform_vec3_arr [2];\n"
"uniform vec4 uniform_vec4_arr [2];\n"
"\n"
"void main()\n"
"{\n"
" gl_Position = vec4(0) + texture(uniform_sampler, vec2(0) );\n"
"\n"
" if (uniform_bool && uniform_bvec2.y && uniform_bvec3.z && uniform_bvec4.w &&\n"
" uniform_bool_arr[1] && uniform_bvec2_arr[1].y && uniform_bvec3_arr[1].z && uniform_bvec4_arr[1].w)\n"
" {\n"
" double sum = uniform_dmat2 [0].x + uniform_dmat2x3 [0].x + uniform_dmat2x4 [0].x +\n"
" uniform_dmat3 [0].x + uniform_dmat3x2 [0].x + uniform_dmat3x4 [0].x +\n"
" uniform_dmat4 [0].x + uniform_dmat4x2 [0].x + uniform_dmat4x3 [0].x +\n"
" uniform_dmat2_arr[0][0].x + uniform_dmat2x3_arr[0][0].x + uniform_dmat2x4_arr[0][0].x +\n"
" uniform_dmat3_arr[0][0].x + uniform_dmat3x2_arr[0][0].x + uniform_dmat3x4_arr[0][0].x +\n"
" uniform_dmat4_arr[0][0].x + uniform_dmat4x2_arr[0][0].x + uniform_dmat4x3_arr[0][0].x +\n"
" uniform_double + uniform_double_arr [0] +\n"
" uniform_dvec2.x + uniform_dvec3.x + uniform_dvec4.x +\n"
" uniform_dvec2_arr[0].x + uniform_dvec3_arr[0].x + uniform_dvec4_arr[0].x;\n"
" int sum2 = uniform_int + uniform_ivec2.x + uniform_ivec3.x +\n"
" uniform_ivec4.x + uniform_ivec2_arr[0].x + uniform_ivec3_arr[0].x +\n"
" uniform_ivec4_arr[0].x + uniform_int_arr[0];\n"
" uint sum3 = uniform_uint + uniform_uvec2.x + uniform_uvec3.x +\n"
" uniform_uvec4.x + uniform_uint_arr[0] + uniform_uvec2_arr[0].x +\n"
" uniform_uvec3_arr[0].x + uniform_uvec4_arr[0].x;\n"
" float sum4 = uniform_float + uniform_float_arr[0] + \n"
" uniform_vec2.x + uniform_vec2_arr[0].x + \n"
" uniform_vec3.x + uniform_vec3_arr[0].x + \n"
" uniform_vec4.x + uniform_vec4_arr[0].x;\n"
"\n"
" if (sum * sum4 > intBitsToFloat(sum2) * uintBitsToFloat(sum3) )\n"
" {\n"
" gl_Position = vec4(1);\n"
" }\n"
" }\n"
"}\n";
m_po_id = gl.createProgram();
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed.");
m_vs_id = gl.createShader(GL_VERTEX_SHADER);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed.");
gl.shaderSource(m_vs_id, 1 /* count */, &vs_body, DE_NULL /* length */);
GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed.");
gl.compileShader(m_vs_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed.");
gl.getShaderiv(m_vs_id, GL_COMPILE_STATUS, &compile_status);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed.");
if (compile_status != GL_TRUE)
{
TCU_FAIL("Shader compilation failed.");
}
gl.attachShader(m_po_id, m_vs_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call failed.");
gl.linkProgram(m_po_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed.");
gl.getProgramiv(m_po_id, GL_LINK_STATUS, &link_status);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed.");
if (link_status != GL_TRUE)
{
TCU_FAIL("Program linking failed.");
}
m_po_bool_arr_uniform_location = gl.getUniformLocation(m_po_id, "uniform_bool_arr[0]");
m_po_bool_uniform_location = gl.getUniformLocation(m_po_id, "uniform_bool");
m_po_bvec2_arr_uniform_location = gl.getUniformLocation(m_po_id, "uniform_bvec2_arr[0]");
m_po_bvec2_uniform_location = gl.getUniformLocation(m_po_id, "uniform_bvec2");
m_po_bvec3_arr_uniform_location = gl.getUniformLocation(m_po_id, "uniform_bvec3_arr[0]");
m_po_bvec3_uniform_location = gl.getUniformLocation(m_po_id, "uniform_bvec3");
m_po_bvec4_arr_uniform_location = gl.getUniformLocation(m_po_id, "uniform_bvec4_arr[0]");
m_po_bvec4_uniform_location = gl.getUniformLocation(m_po_id, "uniform_bvec4");
m_po_dmat2_arr_uniform_location = gl.getUniformLocation(m_po_id, "uniform_dmat2_arr[0]");
m_po_dmat2_uniform_location = gl.getUniformLocation(m_po_id, "uniform_dmat2");
m_po_dmat2x3_arr_uniform_location = gl.getUniformLocation(m_po_id, "uniform_dmat2x3_arr[0]");
m_po_dmat2x3_uniform_location = gl.getUniformLocation(m_po_id, "uniform_dmat2x3");
m_po_dmat2x4_arr_uniform_location = gl.getUniformLocation(m_po_id, "uniform_dmat2x4_arr[0]");
m_po_dmat2x4_uniform_location = gl.getUniformLocation(m_po_id, "uniform_dmat2x4");
m_po_dmat3_arr_uniform_location = gl.getUniformLocation(m_po_id, "uniform_dmat3_arr[0]");
m_po_dmat3_uniform_location = gl.getUniformLocation(m_po_id, "uniform_dmat3");
m_po_dmat3x2_arr_uniform_location = gl.getUniformLocation(m_po_id, "uniform_dmat3x2_arr[0]");
m_po_dmat3x2_uniform_location = gl.getUniformLocation(m_po_id, "uniform_dmat3x2");
m_po_dmat3x4_arr_uniform_location = gl.getUniformLocation(m_po_id, "uniform_dmat3x4_arr[0]");
m_po_dmat3x4_uniform_location = gl.getUniformLocation(m_po_id, "uniform_dmat3x4");
m_po_dmat4_arr_uniform_location = gl.getUniformLocation(m_po_id, "uniform_dmat4_arr[0]");
m_po_dmat4_uniform_location = gl.getUniformLocation(m_po_id, "uniform_dmat4");
m_po_dmat4x2_arr_uniform_location = gl.getUniformLocation(m_po_id, "uniform_dmat4x2_arr[0]");
m_po_dmat4x2_uniform_location = gl.getUniformLocation(m_po_id, "uniform_dmat4x2");
m_po_dmat4x3_arr_uniform_location = gl.getUniformLocation(m_po_id, "uniform_dmat4x3_arr[0]");
m_po_dmat4x3_uniform_location = gl.getUniformLocation(m_po_id, "uniform_dmat4x3");
m_po_double_arr_uniform_location = gl.getUniformLocation(m_po_id, "uniform_double_arr[0]");
m_po_double_uniform_location = gl.getUniformLocation(m_po_id, "uniform_double");
m_po_dvec2_arr_uniform_location = gl.getUniformLocation(m_po_id, "uniform_dvec2_arr[0]");
m_po_dvec2_uniform_location = gl.getUniformLocation(m_po_id, "uniform_dvec2");
m_po_dvec3_arr_uniform_location = gl.getUniformLocation(m_po_id, "uniform_dvec3_arr[0]");
m_po_dvec3_uniform_location = gl.getUniformLocation(m_po_id, "uniform_dvec3");
m_po_dvec4_arr_uniform_location = gl.getUniformLocation(m_po_id, "uniform_dvec4_arr[0]");
m_po_dvec4_uniform_location = gl.getUniformLocation(m_po_id, "uniform_dvec4");
m_po_float_arr_uniform_location = gl.getUniformLocation(m_po_id, "uniform_float_arr[0]");
m_po_float_uniform_location = gl.getUniformLocation(m_po_id, "uniform_float");
m_po_int_arr_uniform_location = gl.getUniformLocation(m_po_id, "uniform_int_arr[0]");
m_po_int_uniform_location = gl.getUniformLocation(m_po_id, "uniform_int");
m_po_ivec2_arr_uniform_location = gl.getUniformLocation(m_po_id, "uniform_ivec2_arr[0]");
m_po_ivec2_uniform_location = gl.getUniformLocation(m_po_id, "uniform_ivec2");
m_po_ivec3_arr_uniform_location = gl.getUniformLocation(m_po_id, "uniform_ivec3_arr[0]");
m_po_ivec3_uniform_location = gl.getUniformLocation(m_po_id, "uniform_ivec3");
m_po_ivec4_arr_uniform_location = gl.getUniformLocation(m_po_id, "uniform_ivec4_arr[0]");
m_po_ivec4_uniform_location = gl.getUniformLocation(m_po_id, "uniform_ivec4");
m_po_sampler_uniform_location = gl.getUniformLocation(m_po_id, "uniform_sampler");
m_po_uint_arr_uniform_location = gl.getUniformLocation(m_po_id, "uniform_uint_arr[0]");
m_po_uint_uniform_location = gl.getUniformLocation(m_po_id, "uniform_uint");
m_po_uvec2_arr_uniform_location = gl.getUniformLocation(m_po_id, "uniform_uvec2_arr[0]");
m_po_uvec2_uniform_location = gl.getUniformLocation(m_po_id, "uniform_uvec2");
m_po_uvec3_arr_uniform_location = gl.getUniformLocation(m_po_id, "uniform_uvec3_arr[0]");
m_po_uvec3_uniform_location = gl.getUniformLocation(m_po_id, "uniform_uvec3");
m_po_uvec4_arr_uniform_location = gl.getUniformLocation(m_po_id, "uniform_uvec4_arr[0]");
m_po_uvec4_uniform_location = gl.getUniformLocation(m_po_id, "uniform_uvec4");
m_po_vec2_arr_uniform_location = gl.getUniformLocation(m_po_id, "uniform_vec2_arr[0]");
m_po_vec2_uniform_location = gl.getUniformLocation(m_po_id, "uniform_vec2");
m_po_vec3_arr_uniform_location = gl.getUniformLocation(m_po_id, "uniform_vec3_arr[0]");
m_po_vec3_uniform_location = gl.getUniformLocation(m_po_id, "uniform_vec3");
m_po_vec4_arr_uniform_location = gl.getUniformLocation(m_po_id, "uniform_vec4_arr[0]");
m_po_vec4_uniform_location = gl.getUniformLocation(m_po_id, "uniform_vec4");
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetUniformLocation() call(s) failed.");
if (m_po_bool_arr_uniform_location == -1 || m_po_bool_uniform_location == -1 ||
m_po_bvec2_arr_uniform_location == -1 || m_po_bvec2_uniform_location == -1 ||
m_po_bvec3_arr_uniform_location == -1 || m_po_bvec3_uniform_location == -1 ||
m_po_bvec4_arr_uniform_location == -1 || m_po_bvec4_uniform_location == -1 ||
m_po_dmat2_arr_uniform_location == -1 || m_po_dmat2_uniform_location == -1 ||
m_po_dmat2x3_arr_uniform_location == -1 || m_po_dmat2x3_uniform_location == -1 ||
m_po_dmat2x4_arr_uniform_location == -1 || m_po_dmat2x4_uniform_location == -1 ||
m_po_dmat3_arr_uniform_location == -1 || m_po_dmat3_uniform_location == -1 ||
m_po_dmat3x2_arr_uniform_location == -1 || m_po_dmat3x2_uniform_location == -1 ||
m_po_dmat3x4_arr_uniform_location == -1 || m_po_dmat3x4_uniform_location == -1 ||
m_po_dmat4_arr_uniform_location == -1 || m_po_dmat4_uniform_location == -1 ||
m_po_dmat4x2_arr_uniform_location == -1 || m_po_dmat4x2_uniform_location == -1 ||
m_po_dmat4x3_arr_uniform_location == -1 || m_po_dmat4x3_uniform_location == -1 ||
m_po_double_arr_uniform_location == -1 || m_po_double_uniform_location == -1 ||
m_po_dvec2_arr_uniform_location == -1 || m_po_dvec2_uniform_location == -1 ||
m_po_dvec3_arr_uniform_location == -1 || m_po_dvec3_uniform_location == -1 ||
m_po_dvec4_arr_uniform_location == -1 || m_po_dvec4_uniform_location == -1 ||
m_po_float_arr_uniform_location == -1 || m_po_float_uniform_location == -1 ||
m_po_int_arr_uniform_location == -1 || m_po_int_uniform_location == -1 ||
m_po_ivec2_arr_uniform_location == -1 || m_po_ivec2_uniform_location == -1 ||
m_po_ivec3_arr_uniform_location == -1 || m_po_ivec3_uniform_location == -1 ||
m_po_ivec4_arr_uniform_location == -1 || m_po_ivec4_uniform_location == -1 ||
m_po_sampler_uniform_location == -1 || m_po_uint_arr_uniform_location == -1 ||
m_po_uint_uniform_location == -1 || m_po_uvec2_arr_uniform_location == -1 ||
m_po_uvec2_uniform_location == -1 || m_po_uvec3_arr_uniform_location == -1 ||
m_po_uvec3_uniform_location == -1 || m_po_uvec4_arr_uniform_location == -1 ||
m_po_uvec4_uniform_location == -1 || m_po_vec2_arr_uniform_location == -1 || m_po_vec2_uniform_location == -1 ||
m_po_vec3_arr_uniform_location == -1 || m_po_vec3_uniform_location == -1 ||
m_po_vec4_arr_uniform_location == -1 || m_po_vec4_uniform_location == -1)
{
TCU_FAIL("At last one of the required uniforms is considered inactive.");
}
}
/** Tells wheter uniform at user-specified location represents a double-precision
* matrix uniform.
*
* @param uniform_location Location of the uniform to use for the query.
*
* @return Requested information.
**/
bool GPUShaderFP64Test1::isMatrixUniform(glw::GLint uniform_location)
{
return (uniform_location == m_po_dmat2_uniform_location || uniform_location == m_po_dmat2x3_uniform_location ||
uniform_location == m_po_dmat2x4_uniform_location || uniform_location == m_po_dmat3_uniform_location ||
uniform_location == m_po_dmat3x2_uniform_location || uniform_location == m_po_dmat3x4_uniform_location ||
uniform_location == m_po_dmat4_uniform_location || uniform_location == m_po_dmat4x2_uniform_location ||
uniform_location == m_po_dmat4x3_uniform_location);
}
/** Tells whether user-specified uniform function corresponds to one of the
* functions in glUniformMatrix*() class.
*
* @param func Uniform function enum to use for the query.
*
* @return true if the specified enum represents one of the glUniformMatrix*() functions,
* false otherwise.
**/
bool GPUShaderFP64Test1::isMatrixUniformFunction(_uniform_function func)
{
return (func == UNIFORM_FUNCTION_MATRIX2DV || func == UNIFORM_FUNCTION_MATRIX2X3DV ||
func == UNIFORM_FUNCTION_MATRIX2X4DV || func == UNIFORM_FUNCTION_MATRIX3DV ||
func == UNIFORM_FUNCTION_MATRIX3X2DV || func == UNIFORM_FUNCTION_MATRIX3X4DV ||
func == UNIFORM_FUNCTION_MATRIX4DV || func == UNIFORM_FUNCTION_MATRIX4X2DV ||
func == UNIFORM_FUNCTION_MATRIX4X3DV);
}
/** Executes test iteration.
*
* @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
*/
tcu::TestNode::IterateResult GPUShaderFP64Test1::iterate()
{
/* Do not execute the test if GL_ARB_texture_view is not supported */
if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_gpu_shader_fp64"))
{
throw tcu::NotSupportedError("GL_ARB_gpu_shader_fp64 is not supported.");
}
/* Initialize all ES objects required to run all the checks */
initTest();
/* Make sure GL_INVALID_OPERATION is generated by glUniform*() and
* glUniformMatrix*() functions if there is no current program object.
*/
m_has_test_passed &= verifyErrorGenerationWhenUniformFunctionsCalledWithoutActivePO();
/* Make sure GL_INVALID_OPERATION is generated by glUniform*() if
* the size of the uniform variable declared in the shader does not
* match the size indicated by the command.
*/
m_has_test_passed &= verifyErrorGenerationWhenCallingSizeMismatchedUniformFunctions();
/* Make sure GL_INVALID_OPERATION is generated if glUniform*() and
* glUniformMatrix*() are used to load a uniform variable of type
* bool, bvec2, bvec3, bvec4, float, int, ivec2, ivec3, ivec4,
* unsigned int, uvec2, uvec3, uvec4, vec2, vec3, vec4 or an array
* of these.
*/
m_has_test_passed &= verifyErrorGenerationWhenCallingTypeMismatchedUniformFunctions();
/* Make sure GL_INVALID_OPERATION is generated if glUniform*() and
* glUniformMatrix*() are used to load incompatible double-typed
* uniforms, as presented below:
*
* I. double-typed uniform configured by glUniform2d();
* II. double-typed uniform configured by glUniform3d();
* III. double-typed uniform configured by glUniform4d();
* IV. double-typed uniform configured by glUniformMatrix*();
* V. dvec2-typed uniform configured by glUniform1d();
* VI. dvec2-typed uniform configured by glUniform3d();
* VII. dvec2-typed uniform configured by glUniform4d();
* VIII. dvec2-typed uniform configured by glUniformMatrix*();
*
* (etc.)
*
*/
m_has_test_passed &= verifyErrorGenerationWhenCallingMismatchedDoubleUniformFunctions();
/* Make sure GL_INVALID_OPERATION is generated if <location> of
* glUniform*() and glUniformMatrix*() is an invalid uniform
* location for the current program object and location is not
* equal to -1.
*/
m_has_test_passed &= verifyErrorGenerationWhenCallingDoubleUniformFunctionsWithInvalidLocation();
/* Make sure GL_INVALID_VALUE is generated if <count> of
* glUniform*() (*dv() functions only) and glUniformMatrix*() is
* negative.
*/
m_has_test_passed &= verifyErrorGenerationWhenCallingDoubleUniformFunctionsWithNegativeCount();
/* Make sure GL_INVALID_OPERATION is generated if <count> of
* glUniform*() (*dv() functions only) and glUniformMatrix*() is
* greater than 1 and the indicated uniform variable is not an
* array variable.
*/
m_has_test_passed &= verifyErrorGenerationWhenCallingDoubleUniformFunctionsWithInvalidCount();
/* Make sure GL_INVALID_OPERATION is generated if a sampler is
* loaded by glUniform*() and glUniformMatrix*().
*/
m_has_test_passed &= verifyErrorGenerationWhenCallingDoubleUniformFunctionsForSamplers();
/* Make sure GL_INVALID_OPERATION is generated if glUniform*() and
* glUniformMatrix*() is used to load values for uniforms of
* boolean types.
*/
m_has_test_passed &= verifyErrorGenerationWhenCallingDoubleUniformFunctionsForBooleans();
if (m_has_test_passed)
{
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
}
else
{
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
}
return STOP;
}
/** Verifies GL_INVALID_OPERATION is generated if any of the glUniform*d(), glUniform*dv() or
* glUniformMatrix*dv() functions is used to load a boolean uniform.
*
* @return true if the implementation was found to behave as expected, false otherwise.
**/
bool GPUShaderFP64Test1::verifyErrorGenerationWhenCallingDoubleUniformFunctionsForBooleans()
{
const double double_data[] = {
1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0
};
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
bool result = true;
glw::GLint uniform_locations[] = { m_po_bool_arr_uniform_location, m_po_bool_uniform_location,
m_po_bvec2_arr_uniform_location, m_po_bvec2_uniform_location,
m_po_bvec3_arr_uniform_location, m_po_bvec3_uniform_location,
m_po_bvec4_arr_uniform_location, m_po_bvec4_uniform_location };
const unsigned int n_uniform_locations = sizeof(uniform_locations) / sizeof(uniform_locations[0]);
for (unsigned int n_uniform_function = UNIFORM_FUNCTION_FIRST; n_uniform_function < UNIFORM_FUNCTION_COUNT;
++n_uniform_function)
{
const _uniform_function uniform_function = (_uniform_function)n_uniform_function;
for (unsigned int n_uniform_location = 0; n_uniform_location < n_uniform_locations; ++n_uniform_location)
{
const glw::GLint uniform_location = uniform_locations[n_uniform_location];
switch (uniform_function)
{
case UNIFORM_FUNCTION_1D:
gl.uniform1d(uniform_location, 0.0);
break;
case UNIFORM_FUNCTION_2D:
gl.uniform2d(uniform_location, 0.0, 1.0);
break;
case UNIFORM_FUNCTION_3D:
gl.uniform3d(uniform_location, 0.0, 1.0, 2.0);
break;
case UNIFORM_FUNCTION_4D:
gl.uniform4d(uniform_location, 0.0, 1.0, 2.0, 3.0);
break;
case UNIFORM_FUNCTION_1DV:
gl.uniform1dv(uniform_location, 1 /* count */, double_data);
break;
case UNIFORM_FUNCTION_2DV:
gl.uniform2dv(uniform_location, 1 /* count */, double_data);
break;
case UNIFORM_FUNCTION_3DV:
gl.uniform3dv(uniform_location, 1 /* count */, double_data);
break;
case UNIFORM_FUNCTION_4DV:
gl.uniform4dv(uniform_location, 1 /* count */, double_data);
break;
case UNIFORM_FUNCTION_MATRIX2DV:
gl.uniformMatrix2dv(uniform_location, 1 /* count */, GL_FALSE /* transpose */, double_data);
break;
case UNIFORM_FUNCTION_MATRIX2X3DV:
gl.uniformMatrix2x3dv(uniform_location, 1 /* count */, GL_FALSE /* transpose */, double_data);
break;
case UNIFORM_FUNCTION_MATRIX2X4DV:
gl.uniformMatrix2x4dv(uniform_location, 1 /* count */, GL_FALSE /* transpose */, double_data);
break;
case UNIFORM_FUNCTION_MATRIX3DV:
gl.uniformMatrix3dv(uniform_location, 1 /* count */, GL_FALSE /* transpose */, double_data);
break;
case UNIFORM_FUNCTION_MATRIX3X2DV:
gl.uniformMatrix3x2dv(uniform_location, 1 /* count */, GL_FALSE /* transpose */, double_data);
break;
case UNIFORM_FUNCTION_MATRIX3X4DV:
gl.uniformMatrix3x4dv(uniform_location, 1 /* count */, GL_FALSE /* transpose */, double_data);
break;
case UNIFORM_FUNCTION_MATRIX4DV:
gl.uniformMatrix4dv(uniform_location, 1 /* count */, GL_FALSE /* transpose */, double_data);
break;
case UNIFORM_FUNCTION_MATRIX4X2DV:
gl.uniformMatrix4x2dv(uniform_location, 1 /* count */, GL_FALSE /* transpose */, double_data);
break;
case UNIFORM_FUNCTION_MATRIX4X3DV:
gl.uniformMatrix4x3dv(uniform_location, 1 /* count */, GL_FALSE /* transpose */, double_data);
break;
default:
{
TCU_FAIL("Unrecognized uniform function");
}
}
/* Make sure GL_INVALID_OPERATION was generated by the call */
const glw::GLenum error_code = gl.getError();
if (error_code != GL_INVALID_OPERATION)
{
m_testCtx.getLog() << tcu::TestLog::Message << "Function " << getUniformFunctionString(uniform_function)
<< "() did not generate an error"
" when applied against a boolean uniform."
<< tcu::TestLog::EndMessage;
result = false;
}
} /* for (all bool uniforms) */
} /* for (all uniform functions) */
return result;
}
/** Verifies GL_INVALID_OPERATION is generated if any of the glUniform*d(), glUniform*dv() or
* glUniformMatrix*dv() functions is used to load a sampler2D uniform.
*
* @return true if the implementation was found to behave as expected, false otherwise.
**/
bool GPUShaderFP64Test1::verifyErrorGenerationWhenCallingDoubleUniformFunctionsForSamplers()
{
const double double_data[] = {
1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0
};
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
bool result = true;
for (unsigned int n_uniform_function = UNIFORM_FUNCTION_FIRST; n_uniform_function < UNIFORM_FUNCTION_COUNT;
++n_uniform_function)
{
_uniform_function uniform_function = (_uniform_function)n_uniform_function;
switch (uniform_function)
{
case UNIFORM_FUNCTION_1D:
gl.uniform1d(m_po_sampler_uniform_location, 0.0);
break;
case UNIFORM_FUNCTION_2D:
gl.uniform2d(m_po_sampler_uniform_location, 0.0, 1.0);
break;
case UNIFORM_FUNCTION_3D:
gl.uniform3d(m_po_sampler_uniform_location, 0.0, 1.0, 2.0);
break;
case UNIFORM_FUNCTION_4D:
gl.uniform4d(m_po_sampler_uniform_location, 0.0, 1.0, 2.0, 3.0);
break;
case UNIFORM_FUNCTION_1DV:
gl.uniform1dv(m_po_sampler_uniform_location, 1 /* count */, double_data);
break;
case UNIFORM_FUNCTION_2DV:
gl.uniform2dv(m_po_sampler_uniform_location, 1 /* count */, double_data);
break;
case UNIFORM_FUNCTION_3DV:
gl.uniform3dv(m_po_sampler_uniform_location, 1 /* count */, double_data);
break;
case UNIFORM_FUNCTION_4DV:
gl.uniform4dv(m_po_sampler_uniform_location, 1 /* count */, double_data);
break;
case UNIFORM_FUNCTION_MATRIX2DV:
gl.uniformMatrix2dv(m_po_sampler_uniform_location, 1 /* count */, GL_FALSE /* transpose */, double_data);
break;
case UNIFORM_FUNCTION_MATRIX2X3DV:
gl.uniformMatrix2x3dv(m_po_sampler_uniform_location, 1 /* count */, GL_FALSE /* transpose */, double_data);
break;
case UNIFORM_FUNCTION_MATRIX2X4DV:
gl.uniformMatrix2x4dv(m_po_sampler_uniform_location, 1 /* count */, GL_FALSE /* transpose */, double_data);
break;
case UNIFORM_FUNCTION_MATRIX3DV:
gl.uniformMatrix3dv(m_po_sampler_uniform_location, 1 /* count */, GL_FALSE /* transpose */, double_data);
break;
case UNIFORM_FUNCTION_MATRIX3X2DV:
gl.uniformMatrix3x2dv(m_po_sampler_uniform_location, 1 /* count */, GL_FALSE /* transpose */, double_data);
break;
case UNIFORM_FUNCTION_MATRIX3X4DV:
gl.uniformMatrix3x4dv(m_po_sampler_uniform_location, 1 /* count */, GL_FALSE /* transpose */, double_data);
break;
case UNIFORM_FUNCTION_MATRIX4DV:
gl.uniformMatrix4dv(m_po_sampler_uniform_location, 1 /* count */, GL_FALSE /* transpose */, double_data);
break;
case UNIFORM_FUNCTION_MATRIX4X2DV:
gl.uniformMatrix4x2dv(m_po_sampler_uniform_location, 1 /* count */, GL_FALSE /* transpose */, double_data);
break;
case UNIFORM_FUNCTION_MATRIX4X3DV:
gl.uniformMatrix4x3dv(m_po_sampler_uniform_location, 1 /* count */, GL_FALSE /* transpose */, double_data);
break;
default:
{
TCU_FAIL("Unrecognized uniform function");
}
}
/* Make sure GL_INVALID_OPERATION was generated by the call */
const glw::GLenum error_code = gl.getError();
if (error_code != GL_INVALID_OPERATION)
{
m_testCtx.getLog() << tcu::TestLog::Message << "Function " << getUniformFunctionString(uniform_function)
<< "() did not generate an error"
" when applied against a sampler uniform."
<< tcu::TestLog::EndMessage;
result = false;
}
} /* for (all uniform functions) */
return result;
}
/** Verifies GL_INVALID_OPERATION is generated if any of the glUniform*dv() or
* glUniformMatrix*dv() functions is used to load a compatible uniform using an
* invalid <count> argument.
*
* @return true if the implementation was found to behave as expected, false otherwise.
**/
bool GPUShaderFP64Test1::verifyErrorGenerationWhenCallingDoubleUniformFunctionsWithInvalidCount()
{
const glw::GLdouble double_values[16] = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0,
9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0 };
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
bool result = true;
const _uniform_function uniform_functions[] = { UNIFORM_FUNCTION_1DV, UNIFORM_FUNCTION_2DV,
UNIFORM_FUNCTION_3DV, UNIFORM_FUNCTION_4DV,
UNIFORM_FUNCTION_MATRIX2DV, UNIFORM_FUNCTION_MATRIX2X3DV,
UNIFORM_FUNCTION_MATRIX2X4DV, UNIFORM_FUNCTION_MATRIX3DV,
UNIFORM_FUNCTION_MATRIX3X2DV, UNIFORM_FUNCTION_MATRIX3X4DV,
UNIFORM_FUNCTION_MATRIX4DV, UNIFORM_FUNCTION_MATRIX4X2DV,
UNIFORM_FUNCTION_MATRIX4X3DV };
const glw::GLint uniforms[] = {
m_po_bool_uniform_location, m_po_bvec2_uniform_location, m_po_bvec3_uniform_location,
m_po_bvec4_uniform_location, m_po_dmat2_uniform_location, m_po_dmat2x3_uniform_location,
m_po_dmat2x4_uniform_location, m_po_dmat3_uniform_location, m_po_dmat3x2_uniform_location,
m_po_dmat3x4_uniform_location, m_po_dmat4_uniform_location, m_po_dmat4x2_uniform_location,
m_po_dmat4x3_uniform_location, m_po_double_uniform_location, m_po_dvec2_uniform_location,
m_po_dvec3_uniform_location, m_po_dvec4_uniform_location, m_po_float_uniform_location,
m_po_int_uniform_location, m_po_ivec2_uniform_location, m_po_ivec3_uniform_location,
m_po_ivec4_uniform_location, m_po_uint_uniform_location, m_po_uvec2_uniform_location,
m_po_uvec3_uniform_location, m_po_uvec4_uniform_location, m_po_vec2_uniform_location,
m_po_vec3_uniform_location, m_po_vec4_uniform_location
};
const unsigned int n_uniform_functions = sizeof(uniform_functions) / sizeof(uniform_functions[0]);
const unsigned int n_uniforms = sizeof(uniforms) / sizeof(uniforms[0]);
for (unsigned int n_uniform_function = 0; n_uniform_function < n_uniform_functions; ++n_uniform_function)
{
_uniform_function uniform_function = uniform_functions[n_uniform_function];
for (unsigned int n_uniform = 0; n_uniform < n_uniforms; ++n_uniform)
{
glw::GLint uniform_location = uniforms[n_uniform];
/* Make sure we only use glUniformMatrix*() functions with matrix uniforms,
* and glUniform*() functions with vector uniforms.
*/
bool is_matrix_uniform = isMatrixUniform(uniform_location);
if (((false == is_matrix_uniform) && (true == isMatrixUniformFunction(uniform_function))) ||
((true == is_matrix_uniform) && (false == isMatrixUniformFunction(uniform_function))))
{
continue;
}
/* Issue the call with an invalid <count> argument */
switch (uniform_function)
{
case UNIFORM_FUNCTION_1DV:
gl.uniform1dv(uniform_location, 2, double_values);
break;
case UNIFORM_FUNCTION_2DV:
gl.uniform2dv(uniform_location, 2, double_values);
break;
case UNIFORM_FUNCTION_3DV:
gl.uniform3dv(uniform_location, 2, double_values);
break;
case UNIFORM_FUNCTION_4DV:
gl.uniform4dv(uniform_location, 2, double_values);
break;
case UNIFORM_FUNCTION_MATRIX2DV:
gl.uniformMatrix2dv(uniform_location, 2, GL_FALSE, double_values);
break;
case UNIFORM_FUNCTION_MATRIX2X3DV:
gl.uniformMatrix2x3dv(uniform_location, 2, GL_FALSE, double_values);
break;
case UNIFORM_FUNCTION_MATRIX2X4DV:
gl.uniformMatrix2x4dv(uniform_location, 2, GL_FALSE, double_values);
break;
case UNIFORM_FUNCTION_MATRIX3DV:
gl.uniformMatrix3dv(uniform_location, 2, GL_FALSE, double_values);
break;
case UNIFORM_FUNCTION_MATRIX3X2DV:
gl.uniformMatrix3x2dv(uniform_location, 2, GL_FALSE, double_values);
break;
case UNIFORM_FUNCTION_MATRIX3X4DV:
gl.uniformMatrix3x4dv(uniform_location, 2, GL_FALSE, double_values);
break;
case UNIFORM_FUNCTION_MATRIX4DV:
gl.uniformMatrix4dv(uniform_location, 2, GL_FALSE, double_values);
break;
case UNIFORM_FUNCTION_MATRIX4X2DV:
gl.uniformMatrix4x2dv(uniform_location, 2, GL_FALSE, double_values);
break;
case UNIFORM_FUNCTION_MATRIX4X3DV:
gl.uniformMatrix4x3dv(uniform_location, 2, GL_FALSE, double_values);
break;
default:
{
TCU_FAIL("Unrecognized uniform function");
}
} /* switch (uniform_function) */
/* Make sure GL_INVALID_VALUE was generated */
glw::GLenum error_code = gl.getError();
if (error_code != GL_INVALID_OPERATION)
{
m_testCtx.getLog() << tcu::TestLog::Message << "Function " << getUniformFunctionString(uniform_function)
<< "() "
"was called with an invalid count argument but did not generate a "
"GL_INVALID_OPERATION error"
<< tcu::TestLog::EndMessage;
result = false;
}
} /* for (all non-arrayed uniforms) */
} /* for (all uniform functions) */
return result;
}
/** Verifies GL_INVALID_OPERATION is generated if any of the glUniform*d(), glUniform*dv() or
* glUniformMatrix*dv() functions is used to load an uniform at an invalid location.
*
* @return true if the implementation was found to behave as expected, false otherwise.
**/
bool GPUShaderFP64Test1::verifyErrorGenerationWhenCallingDoubleUniformFunctionsWithInvalidLocation()
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
bool result = true;
/* Find the largest valid uniform location */
const glw::GLint uniform_locations[] = {
m_po_bool_arr_uniform_location, m_po_bool_uniform_location, m_po_bvec2_arr_uniform_location,
m_po_bvec2_uniform_location, m_po_bvec3_arr_uniform_location, m_po_bvec3_uniform_location,
m_po_bvec4_arr_uniform_location, m_po_bvec4_uniform_location, m_po_dmat2_arr_uniform_location,
m_po_dmat2_uniform_location, m_po_dmat2x3_arr_uniform_location, m_po_dmat2x3_uniform_location,
m_po_dmat2x4_arr_uniform_location, m_po_dmat2x4_uniform_location, m_po_dmat3_arr_uniform_location,
m_po_dmat3_uniform_location, m_po_dmat3x2_arr_uniform_location, m_po_dmat3x2_uniform_location,
m_po_dmat3x4_arr_uniform_location, m_po_dmat3x4_uniform_location, m_po_dmat4_arr_uniform_location,
m_po_dmat4_uniform_location, m_po_dmat4x2_arr_uniform_location, m_po_dmat4x2_uniform_location,
m_po_dmat4x3_arr_uniform_location, m_po_dmat4x3_uniform_location, m_po_double_arr_uniform_location,
m_po_double_uniform_location, m_po_dvec2_arr_uniform_location, m_po_dvec2_uniform_location,
m_po_dvec3_arr_uniform_location, m_po_dvec3_uniform_location, m_po_dvec4_arr_uniform_location,
m_po_dvec4_uniform_location, m_po_float_arr_uniform_location, m_po_float_uniform_location,
m_po_int_arr_uniform_location, m_po_int_uniform_location, m_po_ivec2_arr_uniform_location,
m_po_ivec2_uniform_location, m_po_ivec3_arr_uniform_location, m_po_ivec3_uniform_location,
m_po_ivec4_arr_uniform_location, m_po_ivec4_uniform_location, m_po_uint_arr_uniform_location,
m_po_uint_uniform_location, m_po_uvec2_arr_uniform_location, m_po_uvec2_uniform_location,
m_po_uvec3_arr_uniform_location, m_po_uvec3_uniform_location, m_po_uvec4_arr_uniform_location,
m_po_uvec4_uniform_location, m_po_vec2_arr_uniform_location, m_po_vec2_uniform_location,
m_po_vec3_arr_uniform_location, m_po_vec3_uniform_location, m_po_vec4_arr_uniform_location,
m_po_vec4_uniform_location
};
const unsigned int n_uniform_locations = sizeof(uniform_locations) / sizeof(uniform_locations[0]);
glw::GLint valid_uniform_location = -1;
for (unsigned int n_uniform_location = 0; n_uniform_location < n_uniform_locations; ++n_uniform_location)
{
glw::GLint uniform_location = uniform_locations[n_uniform_location];
if (uniform_location > valid_uniform_location)
{
valid_uniform_location = uniform_location;
}
} /* for (all uniform locations) */
/* Iterate through all uniform functions and make sure GL_INVALID_OPERATION error is always generated
* for invalid uniform location that is != -1
*/
const double double_data[] = {
1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0
};
const glw::GLint invalid_uniform_location = valid_uniform_location + 1;
for (unsigned int n_uniform_function = UNIFORM_FUNCTION_FIRST; n_uniform_function < UNIFORM_FUNCTION_COUNT;
++n_uniform_function)
{
_uniform_function uniform_function = (_uniform_function)n_uniform_function;
switch (uniform_function)
{
case UNIFORM_FUNCTION_1D:
gl.uniform1d(invalid_uniform_location, 0.0);
break;
case UNIFORM_FUNCTION_2D:
gl.uniform2d(invalid_uniform_location, 0.0, 1.0);
break;
case UNIFORM_FUNCTION_3D:
gl.uniform3d(invalid_uniform_location, 0.0, 1.0, 2.0);
break;
case UNIFORM_FUNCTION_4D:
gl.uniform4d(invalid_uniform_location, 0.0, 1.0, 2.0, 3.0);
break;
case UNIFORM_FUNCTION_1DV:
gl.uniform1dv(invalid_uniform_location, 1 /* count */, double_data);
break;
case UNIFORM_FUNCTION_2DV:
gl.uniform2dv(invalid_uniform_location, 1 /* count */, double_data);
break;
case UNIFORM_FUNCTION_3DV:
gl.uniform3dv(invalid_uniform_location, 1 /* count */, double_data);
break;
case UNIFORM_FUNCTION_4DV:
gl.uniform4dv(invalid_uniform_location, 1 /* count */, double_data);
break;
case UNIFORM_FUNCTION_MATRIX2DV:
gl.uniformMatrix2dv(invalid_uniform_location, 1 /* count */, GL_FALSE /* transpose */, double_data);
break;
case UNIFORM_FUNCTION_MATRIX2X3DV:
gl.uniformMatrix2x3dv(invalid_uniform_location, 1 /* count */, GL_FALSE /* transpose */, double_data);
break;
case UNIFORM_FUNCTION_MATRIX2X4DV:
gl.uniformMatrix2x4dv(invalid_uniform_location, 1 /* count */, GL_FALSE /* transpose */, double_data);
break;
case UNIFORM_FUNCTION_MATRIX3DV:
gl.uniformMatrix3dv(invalid_uniform_location, 1 /* count */, GL_FALSE /* transpose */, double_data);
break;
case UNIFORM_FUNCTION_MATRIX3X2DV:
gl.uniformMatrix3x2dv(invalid_uniform_location, 1 /* count */, GL_FALSE /* transpose */, double_data);
break;
case UNIFORM_FUNCTION_MATRIX3X4DV:
gl.uniformMatrix3x4dv(invalid_uniform_location, 1 /* count */, GL_FALSE /* transpose */, double_data);
break;
case UNIFORM_FUNCTION_MATRIX4DV:
gl.uniformMatrix4dv(invalid_uniform_location, 1 /* count */, GL_FALSE /* transpose */, double_data);
break;
case UNIFORM_FUNCTION_MATRIX4X2DV:
gl.uniformMatrix4x2dv(invalid_uniform_location, 1 /* count */, GL_FALSE /* transpose */, double_data);
break;
case UNIFORM_FUNCTION_MATRIX4X3DV:
gl.uniformMatrix4x3dv(invalid_uniform_location, 1 /* count */, GL_FALSE /* transpose */, double_data);
break;
default:
{
TCU_FAIL("Unrecognized uniform function");
}
}
const glw::GLenum error_code = gl.getError();
if (error_code != GL_INVALID_OPERATION)
{
m_testCtx.getLog() << tcu::TestLog::Message << "Function " << getUniformFunctionString(uniform_function)
<< "() did not generate an error"
" when passed an invalid uniform location different from -1."
<< tcu::TestLog::EndMessage;
result = false;
}
} /* for (all uniform functions) */
return result;
}
/** Verifies GL_INVALID_VALUE is generated if any of the glUniform*dv() or
* glUniformMatrix*dv() functions is used to load a compatible uniform using an
* invalid <count> argument of -1.
*
* @return true if the implementation was found to behave as expected, false otherwise.
**/
bool GPUShaderFP64Test1::verifyErrorGenerationWhenCallingDoubleUniformFunctionsWithNegativeCount()
{
const glw::GLdouble double_values[16] = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0,
9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0 };
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
bool result = true;
const _uniform_function uniform_functions[] = { UNIFORM_FUNCTION_1DV, UNIFORM_FUNCTION_2DV,
UNIFORM_FUNCTION_3DV, UNIFORM_FUNCTION_4DV,
UNIFORM_FUNCTION_MATRIX2DV, UNIFORM_FUNCTION_MATRIX2X3DV,
UNIFORM_FUNCTION_MATRIX2X4DV, UNIFORM_FUNCTION_MATRIX3DV,
UNIFORM_FUNCTION_MATRIX3X2DV, UNIFORM_FUNCTION_MATRIX3X4DV,
UNIFORM_FUNCTION_MATRIX4DV, UNIFORM_FUNCTION_MATRIX4X2DV,
UNIFORM_FUNCTION_MATRIX4X3DV };
const unsigned int n_uniform_functions = sizeof(uniform_functions) / sizeof(uniform_functions[0]);
for (unsigned int n_uniform_function = 0; n_uniform_function < n_uniform_functions; ++n_uniform_function)
{
_uniform_function uniform_function = uniform_functions[n_uniform_function];
switch (uniform_function)
{
case UNIFORM_FUNCTION_1DV:
gl.uniform1dv(m_po_double_arr_uniform_location, -1, double_values);
break;
case UNIFORM_FUNCTION_2DV:
gl.uniform2dv(m_po_dvec2_arr_uniform_location, -1, double_values);
break;
case UNIFORM_FUNCTION_3DV:
gl.uniform3dv(m_po_dvec3_arr_uniform_location, -1, double_values);
break;
case UNIFORM_FUNCTION_4DV:
gl.uniform4dv(m_po_dvec4_arr_uniform_location, -1, double_values);
break;
case UNIFORM_FUNCTION_MATRIX2DV:
gl.uniformMatrix2dv(m_po_dmat2_arr_uniform_location, -1, GL_FALSE, double_values);
break;
case UNIFORM_FUNCTION_MATRIX2X3DV:
gl.uniformMatrix2x3dv(m_po_dmat2x3_arr_uniform_location, -1, GL_FALSE, double_values);
break;
case UNIFORM_FUNCTION_MATRIX2X4DV:
gl.uniformMatrix2x4dv(m_po_dmat2x4_arr_uniform_location, -1, GL_FALSE, double_values);
break;
case UNIFORM_FUNCTION_MATRIX3DV:
gl.uniformMatrix3dv(m_po_dmat3_arr_uniform_location, -1, GL_FALSE, double_values);
break;
case UNIFORM_FUNCTION_MATRIX3X2DV:
gl.uniformMatrix3x2dv(m_po_dmat3x2_arr_uniform_location, -1, GL_FALSE, double_values);
break;
case UNIFORM_FUNCTION_MATRIX3X4DV:
gl.uniformMatrix3x4dv(m_po_dmat3x4_arr_uniform_location, -1, GL_FALSE, double_values);
break;
case UNIFORM_FUNCTION_MATRIX4DV:
gl.uniformMatrix4dv(m_po_dmat4_arr_uniform_location, -1, GL_FALSE, double_values);
break;
case UNIFORM_FUNCTION_MATRIX4X2DV:
gl.uniformMatrix4x2dv(m_po_dmat4x2_arr_uniform_location, -1, GL_FALSE, double_values);
break;
case UNIFORM_FUNCTION_MATRIX4X3DV:
gl.uniformMatrix4x3dv(m_po_dmat4x3_arr_uniform_location, -1, GL_FALSE, double_values);
break;
default:
{
TCU_FAIL("Unrecognized uniform function");
}
} /* switch (uniform_function) */
/* Make sure GL_INVALID_VALUE was generated */
glw::GLenum error_code = gl.getError();
if (error_code != GL_INVALID_VALUE)
{
m_testCtx.getLog() << tcu::TestLog::Message << "Function " << getUniformFunctionString(uniform_function)
<< "() "
"was called with a negative count argument but did not generate a "
"GL_INVALID_VALUE error"
<< tcu::TestLog::EndMessage;
result = false;
}
} /* for (all uniform functions) */
return result;
}
/** Verifies GL_INVALID_OPERATION is generated if any of the glUniform*d(), glUniform*dv() or
* glUniformMatrix*dv() functions is used to load an uniform that's incompatible with the
* function (as per spec).
*
* @return true if the implementation was found to behave as expected, false otherwise.
**/
bool GPUShaderFP64Test1::verifyErrorGenerationWhenCallingMismatchedDoubleUniformFunctions()
{
const double double_data[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
glw::GLenum error_code = GL_NO_ERROR;
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
bool result = true;
const glw::GLint double_uniform_locations[] = { m_po_dmat2_uniform_location, m_po_dmat2x3_uniform_location,
m_po_dmat2x4_uniform_location, m_po_dmat3_uniform_location,
m_po_dmat3x2_uniform_location, m_po_dmat3x4_uniform_location,
m_po_dmat4_uniform_location, m_po_dmat4x2_uniform_location,
m_po_dmat4x3_uniform_location, m_po_double_uniform_location,
m_po_dvec2_uniform_location, m_po_dvec3_uniform_location,
m_po_dvec4_uniform_location };
const unsigned int n_double_uniform_locations =
sizeof(double_uniform_locations) / sizeof(double_uniform_locations[0]);
gl.useProgram(m_po_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
for (unsigned int n_uniform_location = 0; n_uniform_location < n_double_uniform_locations; ++n_uniform_location)
{
glw::GLint uniform_location = double_uniform_locations[n_uniform_location];
for (int function = static_cast<int>(UNIFORM_FUNCTION_FIRST);
function < static_cast<int>(UNIFORM_FUNCTION_COUNT); function++)
{
_uniform_function e_function = static_cast<_uniform_function>(function);
/* Exclude valid combinations */
if (((uniform_location == m_po_dmat2_uniform_location) && (e_function == UNIFORM_FUNCTION_MATRIX2DV)) ||
((uniform_location == m_po_dmat2x3_uniform_location) && (e_function == UNIFORM_FUNCTION_MATRIX2X3DV)) ||
((uniform_location == m_po_dmat2x4_uniform_location) && (e_function == UNIFORM_FUNCTION_MATRIX2X4DV)) ||
((uniform_location == m_po_dmat3_uniform_location) && (e_function == UNIFORM_FUNCTION_MATRIX3DV)) ||
((uniform_location == m_po_dmat3x2_uniform_location) && (e_function == UNIFORM_FUNCTION_MATRIX3X2DV)) ||
((uniform_location == m_po_dmat3x4_uniform_location) && (e_function == UNIFORM_FUNCTION_MATRIX3X4DV)) ||
((uniform_location == m_po_dmat4_uniform_location) && (e_function == UNIFORM_FUNCTION_MATRIX4DV)) ||
((uniform_location == m_po_dmat4x2_uniform_location) && (e_function == UNIFORM_FUNCTION_MATRIX4X2DV)) ||
((uniform_location == m_po_dmat4x3_uniform_location) && (e_function == UNIFORM_FUNCTION_MATRIX4X3DV)) ||
((uniform_location == m_po_double_uniform_location) &&
((e_function == UNIFORM_FUNCTION_1D) || (e_function == UNIFORM_FUNCTION_1DV))) ||
((uniform_location == m_po_dvec2_uniform_location) &&
((e_function == UNIFORM_FUNCTION_2D) || (e_function == UNIFORM_FUNCTION_2DV))) ||
((uniform_location == m_po_dvec3_uniform_location) &&
((e_function == UNIFORM_FUNCTION_3D) || (e_function == UNIFORM_FUNCTION_3DV))) ||
((uniform_location == m_po_dvec4_uniform_location) &&
((e_function == UNIFORM_FUNCTION_4D) || (e_function == UNIFORM_FUNCTION_4DV))))
{
continue;
}
switch (e_function)
{
case UNIFORM_FUNCTION_1D:
{
gl.uniform1d(uniform_location, double_data[0]);
break;
}
case UNIFORM_FUNCTION_2D:
{
gl.uniform2d(uniform_location, double_data[0], double_data[1]);
break;
}
case UNIFORM_FUNCTION_3D:
{
gl.uniform3d(uniform_location, double_data[0], double_data[1], double_data[2]);
break;
}
case UNIFORM_FUNCTION_4D:
{
gl.uniform4d(uniform_location, double_data[0], double_data[1], double_data[2], double_data[3]);
break;
}
case UNIFORM_FUNCTION_1DV:
gl.uniform1dv(uniform_location, 1 /* count */, double_data);
break;
case UNIFORM_FUNCTION_2DV:
gl.uniform2dv(uniform_location, 1 /* count */, double_data);
break;
case UNIFORM_FUNCTION_3DV:
gl.uniform3dv(uniform_location, 1 /* count */, double_data);
break;
case UNIFORM_FUNCTION_4DV:
gl.uniform4dv(uniform_location, 1 /* count */, double_data);
break;
case UNIFORM_FUNCTION_MATRIX2DV:
gl.uniformMatrix2dv(uniform_location, 1 /* count */, GL_FALSE, double_data);
break;
case UNIFORM_FUNCTION_MATRIX2X3DV:
gl.uniformMatrix2x3dv(uniform_location, 1 /* count */, GL_FALSE, double_data);
break;
case UNIFORM_FUNCTION_MATRIX2X4DV:
gl.uniformMatrix2x4dv(uniform_location, 1 /* count */, GL_FALSE, double_data);
break;
case UNIFORM_FUNCTION_MATRIX3DV:
gl.uniformMatrix3dv(uniform_location, 1 /* count */, GL_FALSE, double_data);
break;
case UNIFORM_FUNCTION_MATRIX3X2DV:
gl.uniformMatrix3x2dv(uniform_location, 1 /* count */, GL_FALSE, double_data);
break;
case UNIFORM_FUNCTION_MATRIX3X4DV:
gl.uniformMatrix3x4dv(uniform_location, 1 /* count */, GL_FALSE, double_data);
break;
case UNIFORM_FUNCTION_MATRIX4DV:
gl.uniformMatrix4dv(uniform_location, 1 /* count */, GL_FALSE, double_data);
break;
case UNIFORM_FUNCTION_MATRIX4X2DV:
gl.uniformMatrix4x2dv(uniform_location, 1 /* count */, GL_FALSE, double_data);
break;
case UNIFORM_FUNCTION_MATRIX4X3DV:
gl.uniformMatrix4x3dv(uniform_location, 1 /* count */, GL_FALSE, double_data);
break;
default:
{
TCU_FAIL("Unrecognized function");
}
} /* switch (function) */
/* Make sure GL_INVALID_OPERATION error was generated */
error_code = gl.getError();
if (error_code != GL_INVALID_OPERATION)
{
m_testCtx.getLog() << tcu::TestLog::Message << "Invalid error [" << error_code
<< "] was generated when a mismatched "
"double-precision uniform function "
<< getUniformFunctionString(e_function) << "() was used to configure uniform "
<< getUniformNameForLocation(uniform_location) << "." << tcu::TestLog::EndMessage;
result = false;
}
} /* for (all uniform functions) */
} /* for (all uniform locations) */
return result;
}
/** Verifies GL_INVALID_OPERATION is generated if any of the glUniform*d() or
* glUniform*dv() functions is used to load an uniform, size of which is incompatible
* with the function.
*
* @return true if the implementation was found to behave as expected, false otherwise.
**/
bool GPUShaderFP64Test1::verifyErrorGenerationWhenCallingSizeMismatchedUniformFunctions()
{
const double double_data[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
glw::GLenum error_code = GL_NO_ERROR;
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
bool result = true;
const int data[] = {
/* API function */ /* Uniform location */ /* Count (dv functions only) */
(int)UNIFORM_FUNCTION_2D, m_po_double_uniform_location, 0, (int)UNIFORM_FUNCTION_2DV,
m_po_double_uniform_location, 2, (int)UNIFORM_FUNCTION_3D, m_po_double_uniform_location, 0,
(int)UNIFORM_FUNCTION_3DV, m_po_double_uniform_location, 2, (int)UNIFORM_FUNCTION_4D,
m_po_double_uniform_location, 0, (int)UNIFORM_FUNCTION_4DV, m_po_double_uniform_location, 2,
(int)UNIFORM_FUNCTION_1D, m_po_dvec2_uniform_location, 0, (int)UNIFORM_FUNCTION_1DV,
m_po_dvec2_uniform_location, 2, (int)UNIFORM_FUNCTION_3D, m_po_dvec2_uniform_location, 0,
(int)UNIFORM_FUNCTION_3DV, m_po_dvec2_uniform_location, 2, (int)UNIFORM_FUNCTION_4D,
m_po_dvec2_uniform_location, 0, (int)UNIFORM_FUNCTION_4DV, m_po_dvec2_uniform_location, 2,
(int)UNIFORM_FUNCTION_1D, m_po_dvec3_uniform_location, 0, (int)UNIFORM_FUNCTION_1DV,
m_po_dvec3_uniform_location, 2, (int)UNIFORM_FUNCTION_2D, m_po_dvec3_uniform_location, 0,
(int)UNIFORM_FUNCTION_2DV, m_po_dvec3_uniform_location, 2, (int)UNIFORM_FUNCTION_4D,
m_po_dvec3_uniform_location, 0, (int)UNIFORM_FUNCTION_4DV, m_po_dvec3_uniform_location, 2,
(int)UNIFORM_FUNCTION_1D, m_po_dvec4_uniform_location, 0, (int)UNIFORM_FUNCTION_1DV,
m_po_dvec4_uniform_location, 2, (int)UNIFORM_FUNCTION_2D, m_po_dvec4_uniform_location, 0,
(int)UNIFORM_FUNCTION_2DV, m_po_dvec4_uniform_location, 2, (int)UNIFORM_FUNCTION_3D,
m_po_dvec4_uniform_location, 0, (int)UNIFORM_FUNCTION_3DV, m_po_dvec4_uniform_location, 2,
};
const unsigned int n_checks = sizeof(data) / sizeof(data[0]) / 3 /* entries per row */;
gl.useProgram(m_po_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
for (unsigned int n_check = 0; n_check < n_checks; ++n_check)
{
_uniform_function function = (_uniform_function)data[n_check * 3 + 0];
int uniform_location = data[n_check * 3 + 1];
int uniform_count = data[n_check * 3 + 2];
switch (function)
{
case UNIFORM_FUNCTION_1D:
gl.uniform1d(uniform_location, 0.0);
break;
case UNIFORM_FUNCTION_1DV:
gl.uniform1dv(uniform_location, uniform_count, double_data);
break;
case UNIFORM_FUNCTION_2D:
gl.uniform2d(uniform_location, 0.0, 1.0);
break;
case UNIFORM_FUNCTION_2DV:
gl.uniform2dv(uniform_location, uniform_count, double_data);
break;
case UNIFORM_FUNCTION_3D:
gl.uniform3d(uniform_location, 0.0, 1.0, 2.0);
break;
case UNIFORM_FUNCTION_3DV:
gl.uniform3dv(uniform_location, uniform_count, double_data);
break;
case UNIFORM_FUNCTION_4D:
gl.uniform4d(uniform_location, 0.0, 1.0, 2.0, 3.0);
break;
case UNIFORM_FUNCTION_4DV:
gl.uniform4dv(uniform_location, uniform_count, double_data);
break;
default:
{
DE_ASSERT(false);
}
} /* switch (function) */
error_code = gl.getError();
if (error_code != GL_INVALID_OPERATION)
{
m_testCtx.getLog() << tcu::TestLog::Message << getUniformFunctionString(function)
<< "() function did not generate GL_INVALID_OPERATION error when called for"
" a uniform of incompatible size. (check index: "
<< n_check << ")" << tcu::TestLog::EndMessage;
result = false;
}
} /* for (all checks) */
return result;
}
/** Verifies GL_INVALID_OPERATION is generated if any of the glUniform*d() or
* glUniform*dv() functions is used to load an uniform, type of which is incompatible
* with the function.
*
* @return true if the implementation was found to behave as expected, false otherwise.
**/
bool GPUShaderFP64Test1::verifyErrorGenerationWhenCallingTypeMismatchedUniformFunctions()
{
const double double_data[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
glw::GLenum error_code = GL_NO_ERROR;
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
bool result = true;
const glw::GLint nondouble_uniform_locations[] = { m_po_bool_uniform_location, m_po_bvec2_uniform_location,
m_po_bvec3_uniform_location, m_po_bvec4_uniform_location,
m_po_float_uniform_location, m_po_int_uniform_location,
m_po_ivec2_uniform_location, m_po_ivec3_uniform_location,
m_po_ivec4_uniform_location, m_po_uint_uniform_location,
m_po_uvec2_uniform_location, m_po_uvec3_uniform_location,
m_po_uvec4_uniform_location, m_po_vec2_uniform_location,
m_po_vec3_uniform_location, m_po_vec4_uniform_location };
const unsigned int n_nondouble_uniform_locations =
sizeof(nondouble_uniform_locations) / sizeof(nondouble_uniform_locations[0]);
gl.useProgram(m_po_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
for (unsigned int n_uniform_location = 0; n_uniform_location < n_nondouble_uniform_locations; ++n_uniform_location)
{
glw::GLint uniform_location = nondouble_uniform_locations[n_uniform_location];
for (int function = static_cast<int>(UNIFORM_FUNCTION_FIRST);
function < static_cast<int>(UNIFORM_FUNCTION_COUNT); ++function)
{
switch (static_cast<_uniform_function>(function))
{
case UNIFORM_FUNCTION_1D:
gl.uniform1d(uniform_location, 0.0);
break;
case UNIFORM_FUNCTION_1DV:
gl.uniform1dv(uniform_location, 1, double_data);
break;
case UNIFORM_FUNCTION_2D:
gl.uniform2d(uniform_location, 0.0, 1.0);
break;
case UNIFORM_FUNCTION_2DV:
gl.uniform2dv(uniform_location, 1, double_data);
break;
case UNIFORM_FUNCTION_3D:
gl.uniform3d(uniform_location, 0.0, 1.0, 2.0);
break;
case UNIFORM_FUNCTION_3DV:
gl.uniform3dv(uniform_location, 1, double_data);
break;
case UNIFORM_FUNCTION_4D:
gl.uniform4d(uniform_location, 0.0, 1.0, 2.0, 3.0);
break;
case UNIFORM_FUNCTION_4DV:
gl.uniform4dv(uniform_location, 1, double_data);
break;
case UNIFORM_FUNCTION_MATRIX2DV:
gl.uniformMatrix2dv(uniform_location, 1, GL_FALSE, double_data);
break;
case UNIFORM_FUNCTION_MATRIX2X3DV:
gl.uniformMatrix2x3dv(uniform_location, 1, GL_FALSE, double_data);
break;
case UNIFORM_FUNCTION_MATRIX2X4DV:
gl.uniformMatrix2x4dv(uniform_location, 1, GL_FALSE, double_data);
break;
case UNIFORM_FUNCTION_MATRIX3DV:
gl.uniformMatrix3dv(uniform_location, 1, GL_FALSE, double_data);
break;
case UNIFORM_FUNCTION_MATRIX3X2DV:
gl.uniformMatrix3x2dv(uniform_location, 1, GL_FALSE, double_data);
break;
case UNIFORM_FUNCTION_MATRIX3X4DV:
gl.uniformMatrix3x4dv(uniform_location, 1, GL_FALSE, double_data);
break;
case UNIFORM_FUNCTION_MATRIX4DV:
gl.uniformMatrix4dv(uniform_location, 1, GL_FALSE, double_data);
break;
case UNIFORM_FUNCTION_MATRIX4X2DV:
gl.uniformMatrix4x2dv(uniform_location, 1, GL_FALSE, double_data);
break;
case UNIFORM_FUNCTION_MATRIX4X3DV:
gl.uniformMatrix4x3dv(uniform_location, 1, GL_FALSE, double_data);
break;
default:
{
DE_ASSERT(false);
}
} /* switch (function) */
error_code = gl.getError();
if (error_code != GL_INVALID_OPERATION)
{
m_testCtx.getLog() << tcu::TestLog::Message
<< getUniformFunctionString(static_cast<_uniform_function>(function))
<< "() function did not generate GL_INVALID_OPERATION error when called for"
" a uniform of incompatible type."
<< tcu::TestLog::EndMessage;
result = false;
}
}
} /* for (all checks) */
return result;
}
/** Verifies GL_INVALID_OPERATION is generated if any of the glUniform*d() or
* glUniform*dv() functions are called without a bound program object.
*
* @return true if the implementation was found to behave as expected, false otherwise.
**/
bool GPUShaderFP64Test1::verifyErrorGenerationWhenUniformFunctionsCalledWithoutActivePO()
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
bool result = true;
for (int function = static_cast<int>(UNIFORM_FUNCTION_FIRST); function < static_cast<int>(UNIFORM_FUNCTION_COUNT);
function++)
{
const double data[] = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0 };
switch (static_cast<_uniform_function>(function))
{
case UNIFORM_FUNCTION_1D:
gl.uniform1d(m_po_double_uniform_location, 0.0);
break;
case UNIFORM_FUNCTION_1DV:
gl.uniform1dv(m_po_double_uniform_location, 1, data);
break;
case UNIFORM_FUNCTION_2D:
gl.uniform2d(m_po_dvec2_uniform_location, 0.0, 1.0);
break;
case UNIFORM_FUNCTION_2DV:
gl.uniform2dv(m_po_dvec2_uniform_location, 1, data);
break;
case UNIFORM_FUNCTION_3D:
gl.uniform3d(m_po_dvec3_uniform_location, 0.0, 1.0, 2.0);
break;
case UNIFORM_FUNCTION_3DV:
gl.uniform3dv(m_po_dvec3_uniform_location, 1, data);
break;
case UNIFORM_FUNCTION_4D:
gl.uniform4d(m_po_dvec4_uniform_location, 0.0, 1.0, 2.0, 3.0);
break;
case UNIFORM_FUNCTION_4DV:
gl.uniform4dv(m_po_dvec4_uniform_location, 1, data);
break;
case UNIFORM_FUNCTION_MATRIX2DV:
gl.uniformMatrix2dv(m_po_dmat2_uniform_location, 1, GL_FALSE /* transpose */, data);
break;
case UNIFORM_FUNCTION_MATRIX2X3DV:
gl.uniformMatrix2x3dv(m_po_dmat2x3_uniform_location, 1, GL_FALSE /* transpose */, data);
break;
case UNIFORM_FUNCTION_MATRIX2X4DV:
gl.uniformMatrix2x4dv(m_po_dmat2x4_uniform_location, 1, GL_FALSE /* transpose */, data);
break;
case UNIFORM_FUNCTION_MATRIX3DV:
gl.uniformMatrix3dv(m_po_dmat3_uniform_location, 1, GL_FALSE /* transpose */, data);
break;
case UNIFORM_FUNCTION_MATRIX3X2DV:
gl.uniformMatrix3x2dv(m_po_dmat3x2_uniform_location, 1, GL_FALSE /* transpose */, data);
break;
case UNIFORM_FUNCTION_MATRIX3X4DV:
gl.uniformMatrix3x4dv(m_po_dmat3x4_uniform_location, 1, GL_FALSE /* transpose */, data);
break;
case UNIFORM_FUNCTION_MATRIX4DV:
gl.uniformMatrix4dv(m_po_dmat4_uniform_location, 1, GL_FALSE /* transpose */, data);
break;
case UNIFORM_FUNCTION_MATRIX4X2DV:
gl.uniformMatrix4x2dv(m_po_dmat4x2_uniform_location, 1, GL_FALSE /* transpose */, data);
break;
case UNIFORM_FUNCTION_MATRIX4X3DV:
gl.uniformMatrix4x3dv(m_po_dmat4x3_uniform_location, 1, GL_FALSE /* transpose */, data);
break;
default:
{
TCU_FAIL("Unrecognized uniform function");
}
} /* switch (func) */
/* Query the error code */
glw::GLenum error_code = gl.getError();
if (error_code != GL_INVALID_OPERATION)
{
m_testCtx.getLog() << tcu::TestLog::Message << "Implementation did not return GL_INVALID_OPERATION when "
<< getUniformFunctionString(static_cast<_uniform_function>(function))
<< "() was called without an active program object" << tcu::TestLog::EndMessage;
result = false;
}
} /* for (all uniform functions) */
return result;
}
/* Defeinitions of static const symbols declared in GPUShaderFP64Test2 */
const glw::GLuint GPUShaderFP64Test2::m_n_captured_results = 1024;
const glw::GLint GPUShaderFP64Test2::m_result_failure = 2;
const glw::GLint GPUShaderFP64Test2::m_result_success = 1;
const glw::GLuint GPUShaderFP64Test2::m_texture_width = 32;
const glw::GLuint GPUShaderFP64Test2::m_texture_height = m_n_captured_results / m_texture_width;
const glw::GLuint GPUShaderFP64Test2::m_transform_feedback_buffer_size =
m_n_captured_results * sizeof(captured_varying_type);
const glw::GLchar* GPUShaderFP64Test2::m_uniform_block_name = "UniformBlock";
const glw::GLenum GPUShaderFP64Test2::ARB_MAX_COMPUTE_UNIFORM_COMPONENTS = 0x8263;
/** Constructor
*
* @param context Test context
**/
GPUShaderFP64Test2::GPUShaderFP64Test2(deqp::Context& context)
: TestCase(context, "max_uniform_components",
"Verifies that maximum allowed uniform components can be used as double-precision float types")
, m_pDispatchCompute(0)
, m_framebuffer_id(0)
, m_texture_id(0)
, m_transform_feedback_buffer_id(0)
, m_uniform_buffer_id(0)
, m_vertex_array_object_id(0)
{
/* Nothing to be done */
}
/** Deinitialize test
*
**/
void GPUShaderFP64Test2::deinit()
{
/* GL entry points */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Clean frambuffer */
if (0 != m_framebuffer_id)
{
gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
gl.deleteFramebuffers(1, &m_framebuffer_id);
m_framebuffer_id = 0;
}
/* Clean texture */
if (0 != m_texture_id)
{
gl.bindTexture(GL_TEXTURE_2D, 0);
gl.bindImageTexture(0 /* unit */, 0 /* texture */, 0 /* level */, GL_FALSE /* layered */, 0 /* layer */,
GL_READ_ONLY, GL_RGBA8);
gl.deleteTextures(1, &m_texture_id);
m_texture_id = 0;
}
/* Clean buffers */
if (0 != m_transform_feedback_buffer_id)
{
gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0);
gl.deleteBuffers(1, &m_transform_feedback_buffer_id);
m_transform_feedback_buffer_id = 0;
}
if (0 != m_uniform_buffer_id)
{
gl.bindBuffer(GL_UNIFORM_BUFFER, 0);
gl.deleteBuffers(1, &m_uniform_buffer_id);
m_uniform_buffer_id = 0;
}
/* Clean VAO */
if (0 != m_vertex_array_object_id)
{
gl.bindVertexArray(0);
gl.deleteVertexArrays(1, &m_vertex_array_object_id);
m_vertex_array_object_id = 0;
}
}
/** Execute test
*
* @return tcu::TestNode::STOP
**/
tcu::TestNode::IterateResult GPUShaderFP64Test2::iterate()
{
bool result = true;
/* Check if extension is supported */
if (false == m_context.getContextInfo().isExtensionSupported("GL_ARB_gpu_shader_fp64"))
{
throw tcu::NotSupportedError("GL_ARB_gpu_shader_fp64 is not supported");
}
/* Initialize test */
testInit();
prepareShaderStages();
prepareUniformTypes();
/* For all shaders and uniform type combinations */
for (std::vector<shaderStage>::const_iterator shader_stage = m_shader_stages.begin();
m_shader_stages.end() != shader_stage; ++shader_stage)
{
for (std::vector<uniformTypeDetails>::const_iterator uniform_type = m_uniform_types.begin();
m_uniform_types.end() != uniform_type; ++uniform_type)
{
/* Execute test */
if (false == test(*shader_stage, *uniform_type))
{
result = false;
}
}
}
/* Set result */
if (true == result)
{
m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
}
else
{
m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Fail");
}
/* Done */
return tcu::TestNode::STOP;
}
/** Constructor
*
* @param n_columns Number of columns
* @param n_rows Number of rows
**/
GPUShaderFP64Test2::uniformTypeDetails::uniformTypeDetails(glw::GLuint n_columns, glw::GLuint n_rows)
: m_n_columns(n_columns), m_n_rows(n_rows)
{
Utils::_variable_type type = Utils::getDoubleVariableType(n_columns, n_rows);
m_type_name = Utils::getVariableTypeString(type);
m_type = Utils::getGLDataTypeOfVariableType(type);
}
/** Get primitive type captured with transform feedback
*
* @param shader_stage Tested shader stage id
*
* @return Primitive type
**/
glw::GLenum GPUShaderFP64Test2::getCapturedPrimitiveType(shaderStage shader_stage) const
{
switch (shader_stage)
{
case GEOMETRY_SHADER:
case TESS_CTRL_SHADER:
case TESS_EVAL_SHADER:
case VERTEX_SHADER:
return GL_POINTS;
default:
return GL_NONE;
}
}
/** Get primitive type drawn with DrawArrays
*
* @param shader_stage Tested shader stage id
*
* @return Primitive type
**/
glw::GLenum GPUShaderFP64Test2::getDrawPrimitiveType(shaderStage shader_stage) const
{
switch (shader_stage)
{
case FRAGMENT_SHADER:
return GL_TRIANGLE_FAN;
case GEOMETRY_SHADER:
case VERTEX_SHADER:
return GL_POINTS;
case TESS_CTRL_SHADER:
case TESS_EVAL_SHADER:
return GL_PATCHES;
default:
return GL_NONE;
}
}
/** Get maximum allowed number of uniform components
*
* @param shader_stage Tested shader stage id
*
* @return Maxmimum uniform components
**/
glw::GLuint GPUShaderFP64Test2::getMaxUniformComponents(shaderStage shader_stage) const
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
glw::GLint max_uniform_components = 0;
glw::GLenum pname = 0;
switch (shader_stage)
{
case COMPUTE_SHADER:
pname = ARB_MAX_COMPUTE_UNIFORM_COMPONENTS;
break;
case FRAGMENT_SHADER:
pname = GL_MAX_FRAGMENT_UNIFORM_COMPONENTS;
break;
case GEOMETRY_SHADER:
pname = GL_MAX_GEOMETRY_UNIFORM_COMPONENTS;
break;
case TESS_CTRL_SHADER:
pname = GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS;
break;
case TESS_EVAL_SHADER:
pname = GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS;
break;
case VERTEX_SHADER:
pname = GL_MAX_VERTEX_UNIFORM_COMPONENTS;
break;
}
gl.getIntegerv(pname, &max_uniform_components);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
return max_uniform_components;
}
/** Get maximum size allowed for an uniform block
*
* @return Maxmimum uniform block size
**/
glw::GLuint GPUShaderFP64Test2::getMaxUniformBlockSize() const
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
glw::GLint max_uniform_block_size = 0;
gl.getIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &max_uniform_block_size);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetIntegerv");
return max_uniform_block_size;
}
/** Get number of components required to store single uniform of given type
*
* @param uniform_type Tested uniform type
*
* @return Number of components
**/
glw::GLuint GPUShaderFP64Test2::getRequiredComponentsNumber(const uniformTypeDetails& uniform_type) const
{
static const glw::GLuint type_size = 2; /* double takes 2 N */
const glw::GLuint column_length = uniform_type.m_n_rows;
if (1 == uniform_type.m_n_columns)
{
return type_size * column_length;
}
else
{
const glw::GLuint alignment = type_size * ((3 == column_length) ? 4 : column_length);
return alignment * uniform_type.m_n_columns;
}
}
/** Get size used for each member of a uniform array of a given type in a std140 column-major layout
*
* @param uniform_type Tested uniform type
*
* @return Size of a single member
**/
glw::GLuint GPUShaderFP64Test2::getUniformTypeMemberSize(const uniformTypeDetails& uniform_type) const
{
static const glw::GLuint vec4_size = 4 * Utils::getBaseVariableTypeComponentSize(Utils::VARIABLE_TYPE_FLOAT);
const glw::GLuint column_length = uniform_type.m_n_rows;
/** Size for a layout(std140, column_major) uniform_type uniform[] **/
return vec4_size * ((column_length + 1) / 2) * uniform_type.m_n_columns;
}
/** Get the maximum amount of uniforms to be used in a shader stage for a given type
*
* @param shader_stage Tested shader stage id
* @param uniform_type Tested uniform type
*
* @return Number of components
**/
glw::GLuint GPUShaderFP64Test2::getAmountUniforms(shaderStage shader_stage,
const uniformTypeDetails& uniform_type) const
{
const glw::GLuint max_uniform_components = getMaxUniformComponents(shader_stage);
const glw::GLuint required_components = getRequiredComponentsNumber(uniform_type);
const glw::GLuint n_uniforms = max_uniform_components / required_components;
const glw::GLuint max_uniform_block_size = getMaxUniformBlockSize();
const glw::GLuint uniform_type_member_size = getUniformTypeMemberSize(uniform_type);
const glw::GLuint max_uniforms = max_uniform_block_size / uniform_type_member_size;
return max_uniforms < n_uniforms ? max_uniforms : n_uniforms;
}
/** Get name of shader stage
*
* @param shader_stage Tested shader stage id
*
* @return Name
**/
const glw::GLchar* GPUShaderFP64Test2::getShaderStageName(shaderStage shader_stage) const
{
switch (shader_stage)
{
case COMPUTE_SHADER:
return "compute shader";
case FRAGMENT_SHADER:
return "fragment shader";
case GEOMETRY_SHADER:
return "geometry shader";
case TESS_CTRL_SHADER:
return "tesselation control shader";
case TESS_EVAL_SHADER:
return "tesselation evaluation shader";
case VERTEX_SHADER:
return "vertex shader";
}
return 0;
}
/** Inspect program to get: buffer_size, offset, strides and block index
*
* @param program_id Program id
* @param out_buffer_size Size of uniform buffer
* @param out_uniform_details Uniform offset and strides
* @param uniform_block_index Uniform block index
**/
void GPUShaderFP64Test2::inspectProgram(glw::GLuint program_id, glw::GLint n_uniforms,
const uniformTypeDetails& uniform_type, glw::GLint& out_buffer_size,
uniformDetails& out_uniform_details, glw::GLuint& uniform_block_index) const
{
glw::GLint array_stride = 0;
std::vector<glw::GLchar> extracted_uniform_name;
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
glw::GLuint index = 0;
glw::GLint matrix_stride = 0;
glw::GLint offset = 0;
glw::GLsizei size = 0;
glw::GLenum type = 0;
const glw::GLchar* uniform_name = 0;
std::string uniform_name_str;
std::stringstream uniform_name_stream;
/* Get index of uniform block */
uniform_block_index = gl.getUniformBlockIndex(program_id, m_uniform_block_name);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetUniformBlockIndex");
if (GL_INVALID_INDEX == uniform_block_index)
{
TCU_FAIL("Unifom block is inactive");
}
/* Get size of uniform block */
gl.getActiveUniformBlockiv(program_id, uniform_block_index, GL_UNIFORM_BLOCK_DATA_SIZE, &out_buffer_size);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetActiveUniformBlockiv");
if (0 == out_buffer_size)
{
TCU_FAIL("Unifom block size is 0");
}
/* Prepare uniform name */
uniform_name_stream << "uniform_array";
uniform_name_str = uniform_name_stream.str();
uniform_name = uniform_name_str.c_str();
/* Get index of uniform */
gl.getUniformIndices(program_id, 1 /* count */, &uniform_name, &index);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetUniformIndices");
if (GL_INVALID_INDEX == index)
{
TCU_FAIL("Unifom is inactive");
}
/* Verify getActiveUniform results */
extracted_uniform_name.resize(uniform_name_str.length() * 2);
gl.getActiveUniform(program_id, index, (glw::GLsizei)(uniform_name_str.length() * 2) /* bufSize */, 0, &size, &type,
&extracted_uniform_name[0]);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetActiveUniform");
if ((n_uniforms != size) || (uniform_type.m_type != type))
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Error. Invalid GetActiveUniform results."
<< " Size: " << size << " expected: " << n_uniforms << ". Type: " << type
<< " expected: " << uniform_type.m_type
<< ". Name: " << &extracted_uniform_name[0] << tcu::TestLog::EndMessage;
TCU_FAIL("Invalid GetActiveUniform results");
}
/* Get offset of uniform */
gl.getActiveUniformsiv(program_id, 1 /* count */, &index, GL_UNIFORM_OFFSET, &offset);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetActiveUniformsiv");
if (-1 == offset)
{
TCU_FAIL("Unifom has invalid offset");
}
out_uniform_details.m_offset = offset;
/* Get matrix stride of uniform */
gl.getActiveUniformsiv(program_id, 1 /* count */, &index, GL_UNIFORM_MATRIX_STRIDE, &matrix_stride);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetActiveUniformsiv");
if (-1 == matrix_stride)
{
TCU_FAIL("Unifom has invalid matrix stride");
}
out_uniform_details.m_matrix_stride = matrix_stride;
/* Get array stride of uniform */
gl.getActiveUniformsiv(program_id, 1 /* count */, &index, GL_UNIFORM_ARRAY_STRIDE, &array_stride);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetActiveUniformsiv");
if (-1 == matrix_stride)
{
TCU_FAIL("Unifom has invalid matrix stride");
}
out_uniform_details.m_array_stride = array_stride;
}
/** Prepare source code for "boilerplate" shaders
*
* @param stage_specific_layout String that will replace STAGE_SPECIFIC_LAYOUT token
* @param stage_specific_main_body String that will replace STAGE_SPECIFIC_MAIN_BODY token
* @param out_source_code Source code
**/
void GPUShaderFP64Test2::prepareBoilerplateShader(const glw::GLchar* stage_specific_layout,
const glw::GLchar* stage_specific_main_body,
std::string& out_source_code) const
{
/* Shader template */
static const glw::GLchar* boilerplate_shader_template_code = "#version 400 core\n"
"\n"
"precision highp float;\n"
"\n"
"STAGE_SPECIFIC_LAYOUT"
"void main()\n"
"{\n"
"STAGE_SPECIFIC_MAIN_BODY"
"}\n"
"\n";
std::string string = boilerplate_shader_template_code;
/* Tokens */
static const glw::GLchar* body_token = "STAGE_SPECIFIC_MAIN_BODY";
static const glw::GLchar* layout_token = "STAGE_SPECIFIC_LAYOUT";
size_t search_position = 0;
/* Replace tokens */
Utils::replaceToken(layout_token, search_position, stage_specific_layout, string);
Utils::replaceToken(body_token, search_position, stage_specific_main_body, string);
/* Store resuls */
out_source_code = string;
}
/** Prepare program for given combination of shader stage and uniform type
*
* @param shader_stage Shader stage
* @param uniform_type Uniform type
* @param out_program_info Instance of programInfo
**/
void GPUShaderFP64Test2::prepareProgram(shaderStage shader_stage, const uniformTypeDetails& uniform_type,
Utils::programInfo& out_program_info) const
{
/* Stage specific layouts */
static const glw::GLchar* geometry_shader_layout_code = "layout(points) in;\n"
"layout(points, max_vertices = 1) out;\n"
"\n";
static const glw::GLchar* tess_ctrl_shader_layout_code = "layout(vertices = 1) out;\n"
"\n";
static const glw::GLchar* tess_eval_shader_layout_code = "layout(isolines, point_mode) in;\n"
"\n";
/* Stage specific main body */
static const glw::GLchar* boilerplate_fragment_shader_body_code = " discard;\n";
static const glw::GLchar* boilerplate_tess_ctrl_shader_body_code = " 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 glw::GLchar* boilerplate_vertex_shader_body_code = " gl_Position = vec4(1, 0, 0, 1);\n";
static const glw::GLchar* corner_vertex_shader_body_code = " if (0 == gl_VertexID)\n"
" {\n"
" gl_Position = vec4(-1, -1, 0, 1);\n"
" }\n"
" else if (1 == gl_VertexID)\n"
" {\n"
" gl_Position = vec4(-1, 1, 0, 1);\n"
" }\n"
" else if (2 == gl_VertexID)\n"
" {\n"
" gl_Position = vec4(1, 1, 0, 1);\n"
" }\n"
" else if (3 == gl_VertexID)\n"
" {\n"
" gl_Position = vec4(1, -1, 0, 1);\n"
" }\n";
static const glw::GLchar* passthrough_tess_eval_shader_body_code = " result = tcs_tes_result[0];\n";
static const glw::GLchar* test_shader_body_code = "\n result = verification_result;\n";
static const glw::GLchar* test_geometry_shader_body_code = "\n result = verification_result;\n"
"\n"
" EmitVertex();\n"
" EndPrimitive();\n";
static const glw::GLchar* test_tess_ctrl_shader_body_code =
"\n tcs_tes_result[gl_InvocationID] = verification_result;\n"
"\n"
" gl_TessLevelOuter[0] = 1.0;\n"
" gl_TessLevelOuter[1] = 1.0;\n"
" gl_TessLevelOuter[2] = 1.0;\n"
" gl_TessLevelOuter[3] = 1.0;\n"
" gl_TessLevelInner[0] = 1.0;\n"
" gl_TessLevelInner[1] = 1.0;\n";
/* In variables */
static const glw::GLchar* test_tess_ctrl_shader_in_variable = "in int tcs_tes_result[];\n";
/* Out variables */
static const glw::GLchar* test_fragment_shader_out_variable = "layout(location = 0) out int result;\n";
static const glw::GLchar* test_tess_ctrl_shader_out_variable = "out int tcs_tes_result[];\n";
static const glw::GLchar* test_shader_out_variable = "out int result;\n";
/* Varying name */
static const glw::GLchar* varying_name = "result";
glw::GLuint n_varyings = 1;
/* Storage for ready shaders */
std::string compute_shader_code;
std::string fragment_shader_code;
std::string geometry_shader_code;
std::string tess_ctrl_shader_code;
std::string tess_eval_shader_code;
std::string vertex_shader_code;
/* Storage for uniform definition and verification code */
std::string uniform_definitions;
std::string uniform_verification;
/* Get uniform definition and verification code */
prepareUniformDefinitions(shader_stage, uniform_type, uniform_definitions);
prepareUniformVerification(shader_stage, uniform_type, uniform_verification);
/* Prepare vertex shader */
switch (shader_stage)
{
case FRAGMENT_SHADER:
prepareBoilerplateShader("", corner_vertex_shader_body_code, vertex_shader_code);
break;
case GEOMETRY_SHADER:
case TESS_CTRL_SHADER:
case TESS_EVAL_SHADER:
prepareBoilerplateShader("", boilerplate_vertex_shader_body_code, vertex_shader_code);
break;
case VERTEX_SHADER:
prepareTestShader("" /* layout */, uniform_definitions.c_str() /* uniforms */, "" /* in var */,
test_shader_out_variable /* out var */, uniform_verification.c_str() /* verification */,
test_shader_body_code /* body */, vertex_shader_code);
break;
default:
break;
}
/* Prepare fragment shader */
switch (shader_stage)
{
case FRAGMENT_SHADER:
prepareTestShader("" /* layout */, uniform_definitions.c_str() /* uniforms */, "" /* in var */,
test_fragment_shader_out_variable /* out var */,
uniform_verification.c_str() /* verification */, test_shader_body_code /* body */,
fragment_shader_code);
break;
case GEOMETRY_SHADER:
case TESS_CTRL_SHADER:
case TESS_EVAL_SHADER:
case VERTEX_SHADER:
prepareBoilerplateShader("" /* layout */, boilerplate_fragment_shader_body_code /* body */,
fragment_shader_code);
break;
default:
break;
}
/* Prepare compute, tess_ctrl, tess_eval, geometry shaders */
switch (shader_stage)
{
case COMPUTE_SHADER:
prepareTestComputeShader(uniform_definitions.c_str(), uniform_verification.c_str(), compute_shader_code);
break;
case GEOMETRY_SHADER:
prepareTestShader(geometry_shader_layout_code /* layout */, uniform_definitions.c_str() /* uniforms */,
"" /* in var */, test_shader_out_variable /* out var */,
uniform_verification.c_str() /* verification */, test_geometry_shader_body_code /* body */,
geometry_shader_code);
break;
case TESS_CTRL_SHADER:
prepareTestShader(tess_ctrl_shader_layout_code /* layout */, uniform_definitions.c_str() /* uniforms */,
"" /* in var */, test_tess_ctrl_shader_out_variable /* out var */,
uniform_verification.c_str() /* verification */, test_tess_ctrl_shader_body_code /* body */,
tess_ctrl_shader_code);
prepareTestShader(tess_eval_shader_layout_code /* layout */, "" /* uniforms */,
test_tess_ctrl_shader_in_variable /* in var */, test_shader_out_variable /* out var */,
"" /* verification */, passthrough_tess_eval_shader_body_code /* body */,
tess_eval_shader_code);
break;
case TESS_EVAL_SHADER:
prepareBoilerplateShader(tess_ctrl_shader_layout_code /* layout */,
boilerplate_tess_ctrl_shader_body_code /* body */, tess_ctrl_shader_code);
prepareTestShader(tess_eval_shader_layout_code /* layout */, uniform_definitions.c_str() /* uniforms */,
"" /* in var */, test_shader_out_variable /* out var */,
uniform_verification.c_str() /* verification */, test_shader_body_code /* body */,
tess_eval_shader_code);
break;
default:
break;
}
/* Select shaders that will be used by program */
const glw::GLchar* cs_c_str = 0;
const glw::GLchar* fs_c_str = 0;
const glw::GLchar* gs_c_str = 0;
const glw::GLchar* tcs_c_str = 0;
const glw::GLchar* tes_c_str = 0;
const glw::GLchar* vs_c_str = 0;
if (false == compute_shader_code.empty())
{
cs_c_str = compute_shader_code.c_str();
}
if (false == fragment_shader_code.empty())
{
fs_c_str = fragment_shader_code.c_str();
}
if (false == geometry_shader_code.empty())
{
gs_c_str = geometry_shader_code.c_str();
}
if (false == tess_ctrl_shader_code.empty())
{
tcs_c_str = tess_ctrl_shader_code.c_str();
}
if (false == tess_eval_shader_code.empty())
{
tes_c_str = tess_eval_shader_code.c_str();
}
if (false == vertex_shader_code.empty())
{
vs_c_str = vertex_shader_code.c_str();
}
/* Compute and fragment shader results are stored in texture, do not set varyings for transfrom feedback */
if ((COMPUTE_SHADER == shader_stage) || (FRAGMENT_SHADER == shader_stage))
{
n_varyings = 0;
}
/* Build */
out_program_info.build(cs_c_str, fs_c_str, gs_c_str, tcs_c_str, tes_c_str, vs_c_str, &varying_name, n_varyings);
}
/** Prepare collection of tested shader stages
*
*/
void GPUShaderFP64Test2::prepareShaderStages()
{
/* m_pDispatchCompute is initialized only if compute_shader are supproted and context is at least 4.2 */
if (0 != m_pDispatchCompute)
{
m_shader_stages.push_back(COMPUTE_SHADER);
}
m_shader_stages.push_back(FRAGMENT_SHADER);
m_shader_stages.push_back(GEOMETRY_SHADER);
m_shader_stages.push_back(TESS_CTRL_SHADER);
m_shader_stages.push_back(TESS_EVAL_SHADER);
m_shader_stages.push_back(VERTEX_SHADER);
}
/** Prepare source code for "tested" shader stage
*
* @param stage_specific_layout String that will replace STAGE_SPECIFIC_LAYOUT token
* @param uniform_definitions String that will replace UNIFORM_DEFINITIONS token
* @param in_variable_definitions String that will replace IN_VARIABLE_DEFINITION token
* @param out_variable_definitions String that will replace OUT_VARIABLE_DEFINITION token
* @param uniform_verification String that will replace UNIFORM_VERIFICATION token
* @param stage_specific_main_body String that will replace STAGE_SPECIFIC_MAIN_BODY token
* @param out_source_code Shader source code
**/
void GPUShaderFP64Test2::prepareTestShader(const glw::GLchar* stage_specific_layout,
const glw::GLchar* uniform_definitions,
const glw::GLchar* in_variable_definitions,
const glw::GLchar* out_variable_definitions,
const glw::GLchar* uniform_verification,
const glw::GLchar* stage_specific_main_body,
std::string& out_source_code) const
{
/* Shader template */
static const glw::GLchar* test_shader_template_code = "#version 400 core\n"
"\n"
"precision highp float;\n"
"\n"
"STAGE_SPECIFIC_LAYOUT"
"UNIFORM_DEFINITIONS"
"IN_VARIABLE_DEFINITION"
"OUT_VARIABLE_DEFINITION"
"\n"
"void main()\n"
"{\n"
"UNIFORM_VERIFICATION"
"STAGE_SPECIFIC_MAIN_BODY"
"}\n"
"\n";
std::string string = test_shader_template_code;
/* Tokens */
static const glw::GLchar* body_token = "STAGE_SPECIFIC_MAIN_BODY";
static const glw::GLchar* in_var_token = "IN_VARIABLE_DEFINITION";
static const glw::GLchar* layout_token = "STAGE_SPECIFIC_LAYOUT";
static const glw::GLchar* out_var_token = "OUT_VARIABLE_DEFINITION";
static const glw::GLchar* uni_def_token = "UNIFORM_DEFINITIONS";
static const glw::GLchar* uni_ver_token = "UNIFORM_VERIFICATION";
size_t search_position = 0;
/* Replace tokens */
Utils::replaceToken(layout_token, search_position, stage_specific_layout, string);
Utils::replaceToken(uni_def_token, search_position, uniform_definitions, string);
Utils::replaceToken(in_var_token, search_position, in_variable_definitions, string);
Utils::replaceToken(out_var_token, search_position, out_variable_definitions, string);
Utils::replaceToken(uni_ver_token, search_position, uniform_verification, string);
Utils::replaceToken(body_token, search_position, stage_specific_main_body, string);
/* Store resuls */
out_source_code = string;
}
/** Prepare source code for "tested" compute shaders
*
* @param uniform_definitions String that will replace UNIFORM_DEFINITIONS token
* @param uniform_verification String that will replace UNIFORM_VERIFICATION token
* @param out_source_code Source code
**/
void GPUShaderFP64Test2::prepareTestComputeShader(const glw::GLchar* uniform_definitions,
const glw::GLchar* uniform_verification,
std::string& out_source_code) const
{
/* Shader template */
static const glw::GLchar* test_shader_template_code =
"#version 420 core\n"
"#extension GL_ARB_compute_shader : require\n"
"#extension GL_ARB_shader_image_load_store : require\n"
"\n"
"precision highp float;\n"
"\n"
"layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
"\n"
"UNIFORM_DEFINITIONS"
"layout(r32i) writeonly uniform iimage2D result;\n"
"\n"
"void main()\n"
"{\n"
"UNIFORM_VERIFICATION"
"\n"
" imageStore(result, ivec2(gl_WorkGroupID.xy), ivec4(verification_result, 0, 0, 0));\n"
"}\n"
"\n";
std::string string = test_shader_template_code;
/* Tokens */
static const glw::GLchar* uni_def_token = "UNIFORM_DEFINITIONS";
static const glw::GLchar* uni_ver_token = "UNIFORM_VERIFICATION";
size_t search_position = 0;
/* Replace tokens */
Utils::replaceToken(uni_def_token, search_position, uniform_definitions, string);
Utils::replaceToken(uni_ver_token, search_position, uniform_verification, string);
/* Store resuls */
out_source_code = string;
}
/** Prepare source code which defines uniforms for tested shader stage
*
* @param shader_stage Shader stage id
* @param uniform_type Details of uniform type
* @param out_source_code Source code
**/
void GPUShaderFP64Test2::prepareUniformDefinitions(shaderStage shader_stage, const uniformTypeDetails& uniform_type,
std::string& out_source_code) const
{
const glw::GLuint n_uniforms = getAmountUniforms(shader_stage, uniform_type);
std::stringstream stream;
/*
* layout(std140) uniform M_UNIFORM_BLOCK_NAME
* {
* TYPE_NAME uniform_array[N_UNIFORMS];
* };
*/
stream << "layout(std140) uniform " << m_uniform_block_name << "\n"
"{\n";
stream << " " << uniform_type.m_type_name << " uniform_array[" << n_uniforms << "];\n";
stream << "};\n\n";
out_source_code = stream.str();
}
/** Prepare uniform buffer for test
*
* @param shader_stage Shader stage id
* @param uniform_type Details of uniform type
* @param program_info Program object info
**/
void GPUShaderFP64Test2::prepareUniforms(shaderStage shader_stage, const uniformTypeDetails& uniform_type,
const Utils::programInfo& program_info) const
{
glw::GLint buffer_size = 0;
glw::GLuint element_ordinal = 1;
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
const glw::GLuint n_columns = uniform_type.m_n_columns;
const glw::GLuint n_rows = uniform_type.m_n_rows;
const glw::GLuint n_elements = n_columns * n_rows;
uniformDetails uniform_details;
const glw::GLuint program_id = program_info.m_program_object_id;
const glw::GLint n_uniforms = getAmountUniforms(shader_stage, uniform_type);
std::vector<glw::GLubyte> uniform_buffer_data;
glw::GLuint uniform_block_index = 0;
/* Get uniform details */
inspectProgram(program_id, n_uniforms, uniform_type, buffer_size, uniform_details, uniform_block_index);
/* Uniform offset and strides */
const glw::GLuint array_stride = uniform_details.m_array_stride;
const glw::GLuint matrix_stride = uniform_details.m_matrix_stride;
const glw::GLuint uniform_offset = uniform_details.m_offset;
/* Prepare storage for buffer data */
uniform_buffer_data.resize(buffer_size);
/* Prepare uniform data */
for (glw::GLint i = 0; i < n_uniforms; ++i)
{
const glw::GLuint array_entry_offset = uniform_offset + i * array_stride;
for (glw::GLuint element = 0; element < n_elements; ++element, ++element_ordinal)
{
const glw::GLuint column = element / n_rows;
const glw::GLuint column_elem = element % n_rows;
const glw::GLdouble value = element_ordinal;
const glw::GLuint value_offset = static_cast<glw::GLuint>(array_entry_offset + column * matrix_stride +
column_elem * sizeof(glw::GLdouble));
glw::GLdouble* value_dst = (glw::GLdouble*)&uniform_buffer_data[value_offset];
*value_dst = value;
}
}
/* Update uniform buffer with new set of data */
gl.bindBuffer(GL_UNIFORM_BUFFER, m_uniform_buffer_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindBuffer");
gl.bufferData(GL_UNIFORM_BUFFER, buffer_size, &uniform_buffer_data[0], GL_STATIC_DRAW);
GLU_EXPECT_NO_ERROR(gl.getError(), "BufferData");
/* Bind uniform block to uniform buffer */
gl.bindBufferRange(GL_UNIFORM_BUFFER, 0 /* index */, m_uniform_buffer_id, 0 /* offset */, buffer_size);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindBufferRange");
gl.uniformBlockBinding(program_id, uniform_block_index, 0 /* binding */);
GLU_EXPECT_NO_ERROR(gl.getError(), "UniformBlockBinding");
}
/** Prepare collection of tested uniform types
*
**/
void GPUShaderFP64Test2::prepareUniformTypes()
{
m_uniform_types.push_back(uniformTypeDetails(1 /* n_columns */, 1 /* n_rows */));
m_uniform_types.push_back(uniformTypeDetails(1 /* n_columns */, 2 /* n_rows */));
m_uniform_types.push_back(uniformTypeDetails(1 /* n_columns */, 3 /* n_rows */));
m_uniform_types.push_back(uniformTypeDetails(1 /* n_columns */, 4 /* n_rows */));
m_uniform_types.push_back(uniformTypeDetails(2 /* n_columns */, 2 /* n_rows */));
m_uniform_types.push_back(uniformTypeDetails(2 /* n_columns */, 3 /* n_rows */));
m_uniform_types.push_back(uniformTypeDetails(2 /* n_columns */, 4 /* n_rows */));
m_uniform_types.push_back(uniformTypeDetails(3 /* n_columns */, 2 /* n_rows */));
m_uniform_types.push_back(uniformTypeDetails(3 /* n_columns */, 3 /* n_rows */));
m_uniform_types.push_back(uniformTypeDetails(3 /* n_columns */, 4 /* n_rows */));
m_uniform_types.push_back(uniformTypeDetails(4 /* n_columns */, 2 /* n_rows */));
m_uniform_types.push_back(uniformTypeDetails(4 /* n_columns */, 3 /* n_rows */));
m_uniform_types.push_back(uniformTypeDetails(4 /* n_columns */, 4 /* n_rows */));
}
/** Prepare source code that verifes uniform values
*
* @param shader_stage Shader stage id
* @param uniform_type Details of uniform type
* @param out_source_code Source code
**/
void GPUShaderFP64Test2::prepareUniformVerification(shaderStage shader_stage, const uniformTypeDetails& uniform_type,
std::string& out_source_code) const
{
glw::GLuint element_ordinal = 1;
const glw::GLuint n_columns = uniform_type.m_n_columns;
const glw::GLuint n_rows = uniform_type.m_n_rows;
const glw::GLuint n_elements = n_columns * n_rows;
const glw::GLuint n_uniforms = getAmountUniforms(shader_stage, uniform_type);
std::stringstream stream;
/*
* int verification_result = M_RESULT_SUCCESS;
*
* for (int i = 0; i < N_UNIFORMS; ++i)
* {
* if (TYPE_NAME(i * (N_ELEMENTS) + 1) != uniform_array[i])
* {
* verification_result = M_RESULT_FAILURE
* }
* }
*/
stream << " int verification_result = " << m_result_success << ";\n"
"\n"
" for (int i = 0; i < "
<< n_uniforms << "; ++i)\n"
" {\n"
" if ("
<< uniform_type.m_type_name << "(";
for (glw::GLuint element = 0; element < n_elements; ++element, ++element_ordinal)
{
stream << "i * (" << n_elements << ") + " << element + 1;
if (n_elements != element + 1)
{
stream << ", ";
}
}
stream << ") != uniform_array[i])\n"
" {\n"
" verification_result = "
<< m_result_failure << ";\n"
" }\n"
" }\n";
out_source_code = stream.str();
}
/** Execute test for given combination of "tested" shader stage and uniform type
*
* @param shader_stage Tested shader stage id
* @param uniform_type Tested uniform type
*
* @return true if test passed, false otherwise
**/
bool GPUShaderFP64Test2::test(shaderStage shader_stage, const uniformTypeDetails& uniform_type) const
{
const glw::GLenum draw_primitive = getDrawPrimitiveType(shader_stage);
static const glw::GLint first_vertex = 0;
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
const glw::GLsizei n_vertices = (FRAGMENT_SHADER == shader_stage) ? 4 : m_n_captured_results;
Utils::programInfo program_info(m_context);
bool result = true;
/* Prepare program */
prepareProgram(shader_stage, uniform_type, program_info);
gl.useProgram(program_info.m_program_object_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "UseProgram");
/* Prepare uniform buffer and bind it with uniform block */
prepareUniforms(shader_stage, uniform_type, program_info);
/* Prepare storage for test results */
testBegin(program_info.m_program_object_id, shader_stage);
/* Execute */
if (COMPUTE_SHADER == shader_stage)
{
m_pDispatchCompute(m_texture_width, m_texture_height, 1);
GLU_EXPECT_NO_ERROR(gl.getError(), "DispatchCompute");
}
else
{
gl.drawArrays(draw_primitive, first_vertex, n_vertices);
GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays");
}
/* Clean after test */
testEnd(shader_stage);
/* Check results */
if (false == verifyResults(shader_stage))
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "Shader stage: " << getShaderStageName(shader_stage)
<< ". Uniform type: " << uniform_type.m_type_name << tcu::TestLog::EndMessage;
result = false;
}
return result;
}
/** Prepare transform feedback buffer, framebuffer or image unit for test results
*
* @param program_id Program object id
* @param shader_stage Tested shader stage id
**/
void GPUShaderFP64Test2::testBegin(glw::GLuint program_id, shaderStage shader_stage) const
{
std::vector<glw::GLint> buffer_data;
const glw::GLenum captured_primitive = getCapturedPrimitiveType(shader_stage);
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Prepare buffer filled with m_result_failure */
buffer_data.resize(m_n_captured_results);
for (glw::GLuint i = 0; i < m_n_captured_results; ++i)
{
buffer_data[i] = m_result_failure;
}
/* Prepare buffer for test results */
switch (shader_stage)
{
case GEOMETRY_SHADER:
case TESS_CTRL_SHADER:
case TESS_EVAL_SHADER:
case VERTEX_SHADER:
/* Verify getTransformFeedbackVarying results */
{
glw::GLsizei size = 0;
glw::GLenum type = 0;
glw::GLchar name[16];
gl.getTransformFeedbackVarying(program_id, 0 /* index */, 16 /* bufSize */, 0 /* length */, &size, &type,
name);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetTransformFeedbackVarying");
if ((1 != size) || (GL_INT != type) || (0 != strcmp("result", name)))
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "Error. Invalid GetTransformFeedbackVarying results."
<< " Size: " << size << " expected: " << 1 << ". Type: " << type << " expected: " << GL_INT
<< ". Name: " << name << " expected: result" << tcu::TestLog::EndMessage;
TCU_FAIL("Invalid GetTransformFeedbackVarying results");
}
}
/* Create/clean transform feedback buffer */
gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_transform_feedback_buffer_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindBuffer");
gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, m_transform_feedback_buffer_size, &buffer_data[0], GL_DYNAMIC_COPY);
GLU_EXPECT_NO_ERROR(gl.getError(), "BufferData");
/* Set up transform feedback buffer */
gl.bindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, m_transform_feedback_buffer_id, 0 /* offset */,
m_transform_feedback_buffer_size);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindBufferRange");
gl.beginTransformFeedback(captured_primitive);
GLU_EXPECT_NO_ERROR(gl.getError(), "BeginTransformFeedback");
break;
case FRAGMENT_SHADER:
/* Clean texture */
gl.bindTexture(GL_TEXTURE_2D, m_texture_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture");
gl.texSubImage2D(GL_TEXTURE_2D, 0 /* level */, 0 /* x */, 0 /* y */, m_texture_width, m_texture_height,
GL_RED_INTEGER, GL_INT, &buffer_data[0]);
GLU_EXPECT_NO_ERROR(gl.getError(), "TexSubImage2D");
/* Set up texture as color attachment 0 */
gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, m_framebuffer_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindFramebuffer");
gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texture_id, 0 /* level */);
GLU_EXPECT_NO_ERROR(gl.getError(), "FramebufferTexture2D");
gl.viewport(0 /* x */, 0 /* y */, m_texture_width, m_texture_height);
GLU_EXPECT_NO_ERROR(gl.getError(), "Viewport");
break;
case COMPUTE_SHADER:
/* Clean texture */
gl.bindTexture(GL_TEXTURE_2D, m_texture_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture");
gl.texSubImage2D(GL_TEXTURE_2D, 0 /* level */, 0 /* x */, 0 /* y */, m_texture_width, m_texture_height,
GL_RED_INTEGER, GL_INT, &buffer_data[0]);
GLU_EXPECT_NO_ERROR(gl.getError(), "TexSubImage2D");
glw::GLint location = gl.getUniformLocation(program_id, "result");
GLU_EXPECT_NO_ERROR(gl.getError(), "TexSubImage2D");
if (-1 == location)
{
TCU_FAIL("Inactive uniform \"result\"");
}
gl.uniform1i(location, 0 /* first image unit */);
GLU_EXPECT_NO_ERROR(gl.getError(), "TexSubImage2D");
/* Bind texture to first image unit */
gl.bindImageTexture(0 /* first image unit */, m_texture_id, 0 /* level */, GL_FALSE /* layered */,
0 /* layer */, GL_WRITE_ONLY, GL_R32I);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindImageTexture");
break;
}
}
/** Unbind transform feedback buffer, framebuffer or image unit
*
* @param shader_stage Tested shader stage id
**/
void GPUShaderFP64Test2::testEnd(shaderStage shader_stage) const
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
switch (shader_stage)
{
case GEOMETRY_SHADER:
case TESS_CTRL_SHADER:
case TESS_EVAL_SHADER:
case VERTEX_SHADER:
gl.endTransformFeedback();
gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0);
break;
case FRAGMENT_SHADER:
gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0 /* texture_id */,
0 /* level */);
gl.bindTexture(GL_TEXTURE_2D, 0);
gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
break;
case COMPUTE_SHADER:
gl.bindImageTexture(0 /* first image unit */, 0 /* texture_id */, 0 /* level */, GL_FALSE /* layered */,
0 /* layer */, GL_WRITE_ONLY, GL_R32I);
break;
}
}
/** Initialize OpenGL objects for test
*
**/
void GPUShaderFP64Test2::testInit()
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* The test is in 4.0 group. However:
* - compute_shader is core since 4.3
* - compute_shader require at least version 4.2 of GL */
if ((true == m_context.getContextInfo().isExtensionSupported("GL_ARB_compute_shader")) &&
(true == Utils::isGLVersionAtLeast(gl, 4 /* major */, 2 /* minor */)))
{
m_pDispatchCompute = (arbDispatchComputeFunc)gl.dispatchCompute;
}
/* Tesselation patch set up */
gl.patchParameteri(GL_PATCH_VERTICES, 1);
GLU_EXPECT_NO_ERROR(gl.getError(), "PatchParameteri");
/* Generate FBO */
gl.genFramebuffers(1, &m_framebuffer_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "GenFramebuffers");
/* Prepare texture */
gl.genTextures(1, &m_texture_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "GenTextures");
gl.bindTexture(GL_TEXTURE_2D, m_texture_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture");
gl.texStorage2D(GL_TEXTURE_2D, 1, GL_R32I, m_texture_width, m_texture_height);
GLU_EXPECT_NO_ERROR(gl.getError(), "TexStorage2D");
/* Prepare transform feedback buffer */
gl.genBuffers(1, &m_transform_feedback_buffer_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "GenBuffers");
/* Generate uniform buffer */
gl.genBuffers(1, &m_uniform_buffer_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "GenBuffers");
/* Prepare VAO */
gl.genVertexArrays(1, &m_vertex_array_object_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "GenVertexArrays");
gl.bindVertexArray(m_vertex_array_object_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindVertexArray");
}
/** Result verification, expected result is that whole buffer is filled with m_result_success
*
* @param shader_stage Tested shader stage id
**/
bool GPUShaderFP64Test2::verifyResults(shaderStage shader_stage) const
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
if ((FRAGMENT_SHADER == shader_stage) || (COMPUTE_SHADER == shader_stage))
{
/* Verify contents of texture */
/* Prepare storage for testure data */
std::vector<glw::GLint> image_data;
image_data.resize(m_texture_width * m_texture_height);
/* Get texture contents */
gl.bindTexture(GL_TEXTURE_2D, m_texture_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture");
gl.getTexImage(GL_TEXTURE_2D, 0 /* level */, GL_RED_INTEGER, GL_INT, &image_data[0]);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetTexImage");
for (glw::GLuint y = 0; y < m_texture_width; ++y)
{
for (glw::GLuint x = 0; x < m_texture_height; ++x)
{
const glw::GLuint offset = y * m_texture_width + x;
const glw::GLint value = image_data[offset];
if (m_result_success != value)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "Error. Texture contents are wrong at (" << x << ", " << y << ")"
<< tcu::TestLog::EndMessage;
return false;
}
}
}
return true;
}
else
{
/* Verify contents of transform feedback buffer */
bool result = true;
/* Get transform feedback data */
gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_transform_feedback_buffer_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindBuffer");
glw::GLint* feedback_data = (glw::GLint*)gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
GLU_EXPECT_NO_ERROR(gl.getError(), "MapBuffer");
for (glw::GLuint i = 0; i < m_n_captured_results; ++i)
{
const glw::GLint value = feedback_data[i];
if (m_result_success != value)
{
m_context.getTestContext().getLog() << tcu::TestLog::Message
<< "Error. Transform feedback buffer contents are wrong at " << i
<< tcu::TestLog::EndMessage;
result = false;
break;
}
}
/* Unmap transform feedback buffer */
gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
GLU_EXPECT_NO_ERROR(gl.getError(), "UnmapBuffer");
return result;
}
}
/* Definitions of static const fields declared in GPUShaderFP64Test3 */
const glw::GLuint GPUShaderFP64Test3::m_result_failure = 0;
const glw::GLuint GPUShaderFP64Test3::m_result_success = 1;
const glw::GLchar* GPUShaderFP64Test3::m_uniform_block_name = "UniformBlock";
const glw::GLchar* GPUShaderFP64Test3::m_uniform_block_instance_name = "uniform_block";
const glw::GLchar* GPUShaderFP64Test3::m_varying_name_fs_out_fs_result = "fs_out_fs_result";
const glw::GLchar* GPUShaderFP64Test3::m_varying_name_gs_fs_gs_result = "gs_fs_gs_result";
const glw::GLchar* GPUShaderFP64Test3::m_varying_name_gs_fs_tcs_result = "gs_fs_tcs_result";
const glw::GLchar* GPUShaderFP64Test3::m_varying_name_gs_fs_tes_result = "gs_fs_tes_result";
const glw::GLchar* GPUShaderFP64Test3::m_varying_name_gs_fs_vs_result = "gs_fs_vs_result";
const glw::GLchar* GPUShaderFP64Test3::m_varying_name_tcs_tes_tcs_result = "tcs_tes_tcs_result";
const glw::GLchar* GPUShaderFP64Test3::m_varying_name_tcs_tes_vs_result = "tcs_tes_vs_result";
const glw::GLchar* GPUShaderFP64Test3::m_varying_name_tes_gs_tcs_result = "tes_gs_tcs_result";
const glw::GLchar* GPUShaderFP64Test3::m_varying_name_tes_gs_tes_result = "tes_gs_tes_result";
const glw::GLchar* GPUShaderFP64Test3::m_varying_name_tes_gs_vs_result = "tes_gs_vs_result";
const glw::GLchar* GPUShaderFP64Test3::m_varying_name_vs_tcs_vs_result = "vs_tcs_vs_result";
/* Definitions of static const fields declared in GPUShaderFP64Test3::programInfo */
const glw::GLint GPUShaderFP64Test3::programInfo::m_invalid_uniform_offset = -1;
const glw::GLint GPUShaderFP64Test3::programInfo::m_invalid_uniform_matrix_stride = -1;
const glw::GLint GPUShaderFP64Test3::programInfo::m_non_matrix_uniform_matrix_stride = 0;
/** Constructor
*
* @param context Test context
**/
GPUShaderFP64Test3::GPUShaderFP64Test3(deqp::Context& context)
: TestCase(context, "named_uniform_blocks",
"Verifies usage of \"double precision\" floats in \"named uniform block\"")
{
/* Nothing to be done */
}
/** Deinitialize test
*
**/
void GPUShaderFP64Test3::deinit()
{
/* GL entry points */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Clean programs */
m_packed_program.deinit(m_context);
m_shared_program.deinit(m_context);
m_std140_program.deinit(m_context);
/* Clean frambuffer */
if (0 != m_framebuffer_id)
{
gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
gl.deleteFramebuffers(1, &m_framebuffer_id);
m_framebuffer_id = 0;
}
/* Clean texture */
if (0 != m_color_texture_id)
{
gl.bindTexture(GL_TEXTURE_2D, 0);
gl.deleteTextures(1, &m_color_texture_id);
m_color_texture_id = 0;
}
/* Clean buffers */
if (0 != m_transform_feedback_buffer_id)
{
gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0);
gl.deleteBuffers(1, &m_transform_feedback_buffer_id);
m_transform_feedback_buffer_id = 0;
}
if (0 != m_uniform_buffer_id)
{
gl.bindBuffer(GL_UNIFORM_BUFFER, 0);
gl.deleteBuffers(1, &m_uniform_buffer_id);
m_uniform_buffer_id = 0;
}
/* Clean VAO */
if (0 != m_vertex_array_object_id)
{
gl.bindVertexArray(0);
gl.deleteVertexArrays(1, &m_vertex_array_object_id);
m_vertex_array_object_id = 0;
}
}
/** Execute test
*
* @return tcu::TestNode::STOP
**/
tcu::TestNode::IterateResult GPUShaderFP64Test3::iterate()
{
bool result = true;
/* Check if extension is supported */
if (false == m_context.getContextInfo().isExtensionSupported("GL_ARB_gpu_shader_fp64"))
{
throw tcu::NotSupportedError("GL_ARB_gpu_shader_fp64 is not supported");
}
/* Initialize test */
testInit();
/* Test "packed" uniform buffer layout */
if (false == test(PACKED))
{
result = false;
}
/* Test "shared" uniform buffer layout */
if (false == test(SHARED))
{
result = false;
}
/* Test "std140" uniform buffer layout */
if (false == test(STD140))
{
result = false;
}
/* Set result */
if (true == result)
{
m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
}
else
{
m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Fail");
}
/* Done */
return tcu::TestNode::STOP;
}
/** Constructor
*
**/
GPUShaderFP64Test3::programInfo::programInfo()
: m_fragment_shader_id(0)
, m_geometry_shader_id(0)
, m_program_object_id(0)
, m_tesselation_control_shader_id(0)
, m_tesselation_evaluation_shader_id(0)
, m_vertex_shader_id(0)
, m_buffer_size(0)
, m_uniform_block_index(0)
{
/* Nothing to be done here */
}
/** Compile shader
*
* @param context Test context
* @param shader_id Shader object id
* @param shader_code Shader source code
**/
void GPUShaderFP64Test3::programInfo::compile(deqp::Context& context, glw::GLuint shader_id,
const glw::GLchar* shader_code) const
{
/* GL entry points */
const glw::Functions& gl = context.getRenderContext().getFunctions();
/* Compilation status */
glw::GLint status = GL_FALSE;
/* Set source code */
gl.shaderSource(shader_id, 1 /* count */, &shader_code, 0);
GLU_EXPECT_NO_ERROR(gl.getError(), "ShaderSource");
/* Compile */
gl.compileShader(shader_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "CompileShader");
/* Get compilation status */
gl.getShaderiv(shader_id, GL_COMPILE_STATUS, &status);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetShaderiv");
/* Log compilation error */
if (GL_TRUE != status)
{
glw::GLint length = 0;
std::vector<glw::GLchar> message;
/* Error log length */
gl.getShaderiv(shader_id, GL_INFO_LOG_LENGTH, &length);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetShaderiv");
/* Prepare storage */
message.resize(length);
/* Get error log */
gl.getShaderInfoLog(shader_id, length, 0, &message[0]);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetShaderInfoLog");
/* Log */
context.getTestContext().getLog() << tcu::TestLog::Message << "Failed to compile shader:\n"
<< &message[0] << "\nShader source\n"
<< shader_code << tcu::TestLog::EndMessage;
TCU_FAIL("Failed to compile shader");
}
}
/** Cleans program and attached shaders
*
* @param context Test context
**/
void GPUShaderFP64Test3::programInfo::deinit(deqp::Context& context)
{
/* GL entry points */
const glw::Functions& gl = context.getRenderContext().getFunctions();
/* Restore default program */
gl.useProgram(0);
/* Clean program object */
if (0 != m_program_object_id)
{
gl.deleteProgram(m_program_object_id);
m_program_object_id = 0;
}
/* Clean shaders */
if (0 != m_fragment_shader_id)
{
gl.deleteShader(m_fragment_shader_id);
m_fragment_shader_id = 0;
}
if (0 != m_geometry_shader_id)
{
gl.deleteShader(m_geometry_shader_id);
m_geometry_shader_id = 0;
}
if (0 != m_tesselation_control_shader_id)
{
gl.deleteShader(m_tesselation_control_shader_id);
m_tesselation_control_shader_id = 0;
}
if (0 != m_tesselation_evaluation_shader_id)
{
gl.deleteShader(m_tesselation_evaluation_shader_id);
m_tesselation_evaluation_shader_id = 0;
}
if (0 != m_vertex_shader_id)
{
gl.deleteShader(m_vertex_shader_id);
m_vertex_shader_id = 0;
}
}
/** Build program and query for uniform layout
*
* @param context Test context
* @param uniform_details Collection of uniform details
* @param fragment_shader_code Fragment shader source code
* @param geometry_shader_code Geometry shader source code
* @param tesselation_control_shader_code Tesselation control shader source code
* @param tesselation_evaluation_shader_code Tesselation evaluation shader source code
* @param vertex_shader_code Vertex shader source code
**/
void GPUShaderFP64Test3::programInfo::init(deqp::Context& context, const std::vector<uniformDetails> uniform_details,
const glw::GLchar* fragment_shader_code,
const glw::GLchar* geometry_shader_code,
const glw::GLchar* tesselation_control_shader_code,
const glw::GLchar* tesselation_evaluation_shader_code,
const glw::GLchar* vertex_shader_code)
{
/* GL entry points */
const glw::Functions& gl = context.getRenderContext().getFunctions();
/* Names of varyings to be captured with transform feedback */
static const glw::GLchar* varying_names[] = { m_varying_name_gs_fs_gs_result, m_varying_name_gs_fs_tcs_result,
m_varying_name_gs_fs_tes_result, m_varying_name_gs_fs_vs_result };
static const glw::GLuint n_varying_names = sizeof(varying_names) / sizeof(varying_names[0]);
/* Create shader objects */
m_fragment_shader_id = gl.createShader(GL_FRAGMENT_SHADER);
m_geometry_shader_id = gl.createShader(GL_GEOMETRY_SHADER);
m_tesselation_control_shader_id = gl.createShader(GL_TESS_CONTROL_SHADER);
m_tesselation_evaluation_shader_id = gl.createShader(GL_TESS_EVALUATION_SHADER);
m_vertex_shader_id = gl.createShader(GL_VERTEX_SHADER);
GLU_EXPECT_NO_ERROR(gl.getError(), "CreateShader");
/* Create program object */
m_program_object_id = gl.createProgram();
GLU_EXPECT_NO_ERROR(gl.getError(), "CreateProgram");
/* Set up names of varyings to be captured with transform feedback */
gl.transformFeedbackVaryings(m_program_object_id, n_varying_names, varying_names, GL_INTERLEAVED_ATTRIBS);
GLU_EXPECT_NO_ERROR(gl.getError(), "TransformFeedbackVaryings");
/* Compile shaders */
compile(context, m_fragment_shader_id, fragment_shader_code);
compile(context, m_geometry_shader_id, geometry_shader_code);
compile(context, m_tesselation_control_shader_id, tesselation_control_shader_code);
compile(context, m_tesselation_evaluation_shader_id, tesselation_evaluation_shader_code);
compile(context, m_vertex_shader_id, vertex_shader_code);
/* Link program */
link(context);
/* Inspect program object */
/* Get index of named uniform block */
m_uniform_block_index = gl.getUniformBlockIndex(m_program_object_id, m_uniform_block_name);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetUniformBlockIndex");
if (GL_INVALID_INDEX == m_uniform_block_index)
{
TCU_FAIL("Unifom block is inactive");
}
/* Get size of named uniform block */
gl.getActiveUniformBlockiv(m_program_object_id, m_uniform_block_index, GL_UNIFORM_BLOCK_DATA_SIZE, &m_buffer_size);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetActiveUniformBlockiv");
if (0 == m_buffer_size)
{
TCU_FAIL("Unifom block size is 0");
}
/* Get information about "double precision" uniforms */
for (std::vector<uniformDetails>::const_iterator it = uniform_details.begin(), end = uniform_details.end();
end != it; ++it)
{
const glw::GLchar* uniform_name = 0;
std::string uniform_name_str;
std::stringstream uniform_name_stream;
glw::GLuint index = 0;
glw::GLint offset = 0;
glw::GLint matrix_stride = 0;
/* Uniform name = UNIFORM_BLOCK_NAME.UNIFORM_NAME */
uniform_name_stream << m_uniform_block_name << "." << it->m_name;
uniform_name_str = uniform_name_stream.str();
uniform_name = uniform_name_str.c_str();
/* Get index of uniform */
gl.getUniformIndices(m_program_object_id, 1 /* count */, &uniform_name, &index);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetUniformIndices");
if (GL_INVALID_INDEX == index)
{
TCU_FAIL("Unifom is inactive");
}
/* Get offset of uniform */
gl.getActiveUniformsiv(m_program_object_id, 1 /* count */, &index, GL_UNIFORM_OFFSET, &offset);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetActiveUniformsiv");
if (m_invalid_uniform_offset == offset)
{
TCU_FAIL("Unifom has invalid offset");
}
m_uniform_offsets.push_back(offset);
/* Get matrix stride of uniform */
gl.getActiveUniformsiv(m_program_object_id, 1 /* count */, &index, GL_UNIFORM_MATRIX_STRIDE, &matrix_stride);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetActiveUniformsiv");
if (m_invalid_uniform_matrix_stride == offset)
{
TCU_FAIL("Unifom has invalid matrix stride");
}
m_uniform_matrix_strides.push_back(matrix_stride);
}
}
/** Attach shaders and link program
*
* @param context Test context
**/
void GPUShaderFP64Test3::programInfo::link(deqp::Context& context) const
{
/* GL entry points */
const glw::Functions& gl = context.getRenderContext().getFunctions();
/* Link status */
glw::GLint status = GL_FALSE;
/* Attach shaders */
gl.attachShader(m_program_object_id, m_fragment_shader_id);
gl.attachShader(m_program_object_id, m_geometry_shader_id);
gl.attachShader(m_program_object_id, m_tesselation_control_shader_id);
gl.attachShader(m_program_object_id, m_tesselation_evaluation_shader_id);
gl.attachShader(m_program_object_id, m_vertex_shader_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "AttachShader");
/* Link */
gl.linkProgram(m_program_object_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "LinkProgram");
/* Get link status */
gl.getProgramiv(m_program_object_id, GL_LINK_STATUS, &status);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramiv");
/* Log link error */
if (GL_TRUE != status)
{
glw::GLint length = 0;
std::vector<glw::GLchar> message;
/* Get error log length */
gl.getProgramiv(m_program_object_id, GL_INFO_LOG_LENGTH, &length);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramiv");
message.resize(length);
/* Get error log */
gl.getProgramInfoLog(m_program_object_id, length, 0, &message[0]);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramInfoLog");
/* Log */
context.getTestContext().getLog() << tcu::TestLog::Message << "Failed to link program:\n"
<< &message[0] << tcu::TestLog::EndMessage;
TCU_FAIL("Failed to link program");
}
}
/** Returns "predefined" values that will be used to fill uniform data
*
* @param type_ordinal Ordinal number of "double precision" uniform type
* @param element Index of element in uniform
*
* @return "Predefined" value
**/
glw::GLdouble GPUShaderFP64Test3::getExpectedValue(glw::GLuint type_ordinal, glw::GLuint element) const
{
return m_base_type_ordinal + (13.0 * (glw::GLdouble)type_ordinal) +
((m_base_element - (glw::GLdouble)element) / 4.0);
}
/** Returns a reference of programInfo instance specific for given buffer layout
*
* @param uniform_data_layout Buffer layout
*
* @return Reference to an instance of programInfo
**/
const GPUShaderFP64Test3::programInfo& GPUShaderFP64Test3::getProgramInfo(uniformDataLayout uniform_data_layout) const
{
const programInfo* program_info = 0;
switch (uniform_data_layout)
{
case PACKED:
program_info = &m_packed_program;
break;
case SHARED:
program_info = &m_shared_program;
break;
case STD140:
program_info = &m_std140_program;
break;
}
return *program_info;
}
/** Get "name" of buffer layout
*
* @param uniform_data_layout Buffer layout
*
* @return "Name" of layout
**/
const glw::GLchar* GPUShaderFP64Test3::getUniformLayoutName(uniformDataLayout uniform_data_layout) const
{
const glw::GLchar* layout = "";
switch (uniform_data_layout)
{
case PACKED:
layout = "packed";
break;
case SHARED:
layout = "shared";
break;
case STD140:
layout = "std140";
break;
}
return layout;
}
/** Prepare programInfo instance for specific buffer layout
*
* @param program_info Instance of programInfo
* @param uniform_data_layout Buffer layout
**/
void GPUShaderFP64Test3::prepareProgram(programInfo& program_info, uniformDataLayout uniform_data_layout) const
{
/* Storage for shader source code */
std::stringstream fragment_shader_code;
std::stringstream geometry_shader_code;
std::stringstream tess_control_shader_code;
std::stringstream tess_eval_shader_code;
std::stringstream vertex_shader_code;
/* Write preambles */
writePreamble(fragment_shader_code, FRAGMENT_SHADER);
writePreamble(geometry_shader_code, GEOMETRY_SHADER);
writePreamble(tess_control_shader_code, TESS_CONTROL_SHADER);
writePreamble(tess_eval_shader_code, TESS_EVAL_SHADER);
writePreamble(vertex_shader_code, VERTEX_SHADER);
/* Write definition of named uniform block */
writeUniformBlock(fragment_shader_code, uniform_data_layout);
writeUniformBlock(geometry_shader_code, uniform_data_layout);
writeUniformBlock(tess_control_shader_code, uniform_data_layout);
writeUniformBlock(tess_eval_shader_code, uniform_data_layout);
writeUniformBlock(vertex_shader_code, uniform_data_layout);
/* Write definitions of varyings */
writeVaryingDeclarations(fragment_shader_code, FRAGMENT_SHADER);
writeVaryingDeclarations(geometry_shader_code, GEOMETRY_SHADER);
writeVaryingDeclarations(tess_control_shader_code, TESS_CONTROL_SHADER);
writeVaryingDeclarations(tess_eval_shader_code, TESS_EVAL_SHADER);
writeVaryingDeclarations(vertex_shader_code, VERTEX_SHADER);
/* Write main routine */
writeMainBody(fragment_shader_code, FRAGMENT_SHADER);
writeMainBody(geometry_shader_code, GEOMETRY_SHADER);
writeMainBody(tess_control_shader_code, TESS_CONTROL_SHADER);
writeMainBody(tess_eval_shader_code, TESS_EVAL_SHADER);
writeMainBody(vertex_shader_code, VERTEX_SHADER);
/* Init programInfo instance */
program_info.init(m_context, m_uniform_details, fragment_shader_code.str().c_str(),
geometry_shader_code.str().c_str(), tess_control_shader_code.str().c_str(),
tess_eval_shader_code.str().c_str(), vertex_shader_code.str().c_str());
}
/** Prepare uniform buffer
*
* @param program_info Instance of programInfo
* @param verify_offsets If uniform offsets should be verified against expected values
*
* @return false if uniform offsets verification result is failure, true otherwise
**/
bool GPUShaderFP64Test3::prepareUniformBuffer(const programInfo& program_info, bool verify_offsets) const
{
const glw::GLuint buffer_size = program_info.m_buffer_size;
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
bool offset_verification_result = true;
glw::GLuint type_ordinal = 1;
std::vector<uniformDetails>::const_iterator it_uniform_details = m_uniform_details.begin();
std::vector<glw::GLint>::const_iterator it_uniform_offsets = program_info.m_uniform_offsets.begin();
std::vector<glw::GLint>::const_iterator it_uniform_matrix_strides = program_info.m_uniform_matrix_strides.begin();
/* Prepare storage for uniform buffer data */
std::vector<glw::GLubyte> buffer_data;
buffer_data.resize(buffer_size);
/* For each "double precision" uniform */
for (/* start conditions already set up */; m_uniform_details.end() != it_uniform_details;
++it_uniform_details, ++it_uniform_offsets, ++it_uniform_matrix_strides, ++type_ordinal)
{
const glw::GLint matrix_stride = *it_uniform_matrix_strides;
const glw::GLuint n_columns = it_uniform_details->m_n_columns;
const glw::GLuint n_elements = it_uniform_details->m_n_elements;
const glw::GLuint column_length = n_elements / n_columns;
const glw::GLint uniform_offset = *it_uniform_offsets;
/* For each element of uniform */
for (glw::GLuint element = 0; element < n_elements; ++element)
{
const glw::GLuint column = element / column_length;
const glw::GLuint column_elem = element % column_length;
const glw::GLdouble value = getExpectedValue(type_ordinal, element);
const glw::GLuint value_offset =
static_cast<glw::GLuint>(uniform_offset + column * matrix_stride + column_elem * sizeof(glw::GLdouble));
glw::GLdouble* value_dst = (glw::GLdouble*)&buffer_data[value_offset];
/* Store value */
*value_dst = value;
}
/* Uniform offset verification */
if (true == verify_offsets)
{
const glw::GLint expected_offset = it_uniform_details->m_expected_std140_offset;
if (expected_offset != uniform_offset)
{
if (true == offset_verification_result)
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Error" << tcu::TestLog::EndMessage;
}
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "Uniform: " << it_uniform_details->m_name
<< " has offset: " << uniform_offset << ". Expected offset: " << expected_offset
<< tcu::TestLog::EndMessage;
offset_verification_result = false;
}
}
}
/* Update uniform buffer with prepared data */
gl.bindBuffer(GL_UNIFORM_BUFFER, m_uniform_buffer_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindBuffer");
gl.bufferData(GL_UNIFORM_BUFFER, buffer_size, &buffer_data[0], GL_STATIC_DRAW);
GLU_EXPECT_NO_ERROR(gl.getError(), "BufferData");
/* Bind uniform buffer as data source for named uniform block */
gl.bindBufferRange(GL_UNIFORM_BUFFER, 0 /* index */, m_uniform_buffer_id, 0, buffer_size);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindBufferRange");
gl.uniformBlockBinding(program_info.m_program_object_id, program_info.m_uniform_block_index, 0 /* binding */);
GLU_EXPECT_NO_ERROR(gl.getError(), "UniformBlockBinding");
/* Done */
return offset_verification_result;
}
/** Prepare data, execute draw call and verify results
*
* @param uniform_data_layout
*
* @return true if test pass, false otherwise
**/
bool GPUShaderFP64Test3::test(uniformDataLayout uniform_data_layout) const
{
bool are_offsets_verified = (STD140 == uniform_data_layout);
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
bool offset_verification_result = true;
const programInfo& program_info = getProgramInfo(uniform_data_layout);
bool result = true;
/* Set up program */
gl.useProgram(program_info.m_program_object_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "UseProgram");
/* Prepare uniform buffer */
offset_verification_result = prepareUniformBuffer(program_info, are_offsets_verified);
if (true == are_offsets_verified && false == offset_verification_result)
{
/* Offsets verification failure was already reported, add info about buffer layout */
m_context.getTestContext().getLog() << tcu::TestLog::Message
<< "Uniform buffer layout: " << getUniformLayoutName(uniform_data_layout)
<< tcu::TestLog::EndMessage;
result = false;
}
/* Set up transform feedback buffer */
gl.bindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_transform_feedback_buffer_id, 0, 4 * sizeof(glw::GLint));
GLU_EXPECT_NO_ERROR(gl.getError(), "UseProgram");
/* Begin transform feedback */
gl.beginTransformFeedback(GL_POINTS);
GLU_EXPECT_NO_ERROR(gl.getError(), "BeginTransformFeedback");
/* Execute draw call for singe vertex */
gl.drawArrays(GL_PATCHES, 0 /* first */, 1 /* count */);
GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays");
/* Stop transform feedback */
gl.endTransformFeedback();
GLU_EXPECT_NO_ERROR(gl.getError(), "EndTransformFeedback");
/* Verify results */
if (false == verifyResults())
{
/* Result verificatioon failure was already reported, add info about layout */
m_context.getTestContext().getLog() << tcu::TestLog::Message
<< "Uniform buffer layout: " << getUniformLayoutName(uniform_data_layout)
<< tcu::TestLog::EndMessage;
result = false;
}
/* Done */
return result;
}
void GPUShaderFP64Test3::testInit()
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Uniform block declaration with std140 offsets calculated
* | align | loc_req | begins | ends | offset in bytes | imp |
* ivec3 dummy1[3] | 4 | 12 | 0 | 12 | 0 | |
* double double_value | 2 | 2 | 12 | 14 | 48 | XXX |
* bool dummy2 | 1 | 1 | 14 | 15 | 56 | |
* dvec2 dvec2_value | 4 | 4 | 16 | 20 | 64 | XXX |
* bvec3 dummy3 | 4 | 4 | 20 | 24 | 80 | |
* dvec3 dvec3_value | 8 | 8 | 24 | 32 | 96 | XXX |
* int dummy4[3] | 4 | 12 | 32 | 44 | 128 | |
* dvec4 dvec4_value | 8 | 8 | 48 | 56 | 192 | XXX |
* bool dummy5 | 1 | 1 | 56 | 57 | 224 | |
* bool dummy6[2] | 4 | 8 | 60 | 68 | 240 | |
* dmat2 dmat2_value | 4 | 8 | 68 | 76 | 272 | XXX |
* dmat3 dmat3_value | 8 | 24 | 80 | 104 | 320 | XXX |
* bool dummy7 | 1 | 1 | 104 | 105 | 416 | |
* dmat4 dmat4_value | 8 | 32 | 112 | 144 | 448 | XXX |
* dmat2x3 dmat2x3_value | 8 | 16 | 144 | 160 | 576 | XXX |
* uvec3 dummy8 | 4 | 4 | 160 | 164 | 640 | |
* dmat2x4 dmat2x4_value | 8 | 16 | 168 | 184 | 672 | XXX |
* dmat3x2 dmat3x2_value | 4 | 12 | 184 | 196 | 736 | XXX |
* bool dummy9 | 1 | 1 | 196 | 197 | 784 | |
* dmat3x4 dmat3x4_value | 8 | 24 | 200 | 224 | 800 | XXX |
* int dummy10 | 1 | 1 | 224 | 225 | 896 | |
* dmat4x2 dmat4x2_value | 4 | 16 | 228 | 244 | 912 | XXX |
* dmat4x3 dmat4x3_value | 8 | 32 | 248 | 280 | 992 | XXX |
*/
/* Prepare "double precision" unfiorms' details */
m_uniform_details.push_back(uniformDetails(48 /* off */, "double_value" /* name */, 1 /* n_columns */,
1 /* n_elements */, "double" /* type_name */));
m_uniform_details.push_back(uniformDetails(64 /* off */, "dvec2_value" /* name */, 1 /* n_columns */,
2 /* n_elements */, "dvec2" /* type_name */));
m_uniform_details.push_back(uniformDetails(96 /* off */, "dvec3_value" /* name */, 1 /* n_columns */,
3 /* n_elements */, "dvec3" /* type_name */));
m_uniform_details.push_back(uniformDetails(192 /* off */, "dvec4_value" /* name */, 1 /* n_columns */,
4 /* n_elements */, "dvec4" /* type_name */));
m_uniform_details.push_back(uniformDetails(272 /* off */, "dmat2_value" /* name */, 2 /* n_columns */,
4 /* n_elements */, "dmat2" /* type_name */));
m_uniform_details.push_back(uniformDetails(320 /* off */, "dmat3_value" /* name */, 3 /* n_columns */,
9 /* n_elements */, "dmat3" /* type_name */));
m_uniform_details.push_back(uniformDetails(448 /* off */, "dmat4_value" /* name */, 4 /* n_columns */,
16 /* n_elements */, "dmat4" /* type_name */));
m_uniform_details.push_back(uniformDetails(576 /* off */, "dmat2x3_value" /* name */, 2 /* n_columns */,
6 /* n_elements */, "dmat2x3" /* type_name */));
m_uniform_details.push_back(uniformDetails(672 /* off */, "dmat2x4_value" /* name */, 2 /* n_columns */,
8 /* n_elements */, "dmat2x4" /* type_name */));
m_uniform_details.push_back(uniformDetails(736 /* off */, "dmat3x2_value" /* name */, 3 /* n_columns */,
6 /* n_elements */, "dmat3x2" /* type_name */));
m_uniform_details.push_back(uniformDetails(800 /* off */, "dmat3x4_value" /* name */, 3 /* n_columns */,
12 /* n_elements */, "dmat3x4" /* type_name */));
m_uniform_details.push_back(uniformDetails(912 /* off */, "dmat4x2_value" /* name */, 4 /* n_columns */,
8 /* n_elements */, "dmat4x2" /* type_name */));
m_uniform_details.push_back(uniformDetails(992 /* off */, "dmat4x3_value" /* name */, 4 /* n_columns */,
12 /* n_elements */, "dmat4x3" /* type_name */));
/* Get random values for getExpectedValue */
m_base_element = (glw::GLdouble)(rand() % 13);
m_base_type_ordinal = (glw::GLdouble)(rand() % 213);
/* Prepare programInfos for all buffer layouts */
prepareProgram(m_packed_program, PACKED);
prepareProgram(m_shared_program, SHARED);
prepareProgram(m_std140_program, STD140);
/* Generate buffers */
gl.genBuffers(1, &m_transform_feedback_buffer_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "GenBuffers");
gl.genBuffers(1, &m_uniform_buffer_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "GenBuffers");
/* Prepare transform feedback buffer */
gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_transform_feedback_buffer_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindBuffer");
gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 4 * sizeof(glw::GLint), 0 /* data */, GL_DYNAMIC_COPY);
GLU_EXPECT_NO_ERROR(gl.getError(), "BufferData");
/* Prepare texture for color attachment 0 */
gl.genTextures(1, &m_color_texture_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "GenTextures");
gl.bindTexture(GL_TEXTURE_2D, m_color_texture_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture");
gl.texStorage2D(GL_TEXTURE_2D, 1 /* levels */, GL_R32I, 1 /* width */, 1 /* height */);
GLU_EXPECT_NO_ERROR(gl.getError(), "TexStorage2D");
/* Prepare FBO with color attachment 0 */
gl.genFramebuffers(1, &m_framebuffer_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "GenFramebuffers");
gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, m_framebuffer_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindFramebuffer");
gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_color_texture_id,
0 /* level */);
GLU_EXPECT_NO_ERROR(gl.getError(), "FramebufferTexture2D");
gl.viewport(0 /* x */, 0 /* y */, 1 /* width */, 1 /* height */);
GLU_EXPECT_NO_ERROR(gl.getError(), "Viewport");
/* Prepare VAO */
gl.genVertexArrays(1, &m_vertex_array_object_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "GenVertexArrays");
gl.bindVertexArray(m_vertex_array_object_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindVertexArray");
/* Tesselation patch set up */
gl.patchParameteri(GL_PATCH_VERTICES, 1);
GLU_EXPECT_NO_ERROR(gl.getError(), "PatchParameteri");
}
/** Verify contents of transform feedback buffer and framebuffer's color attachment 0
*
* @return true if all values are as expected, false otherwise
**/
bool GPUShaderFP64Test3::verifyResults() const
{
glw::GLint* feedback_data = 0;
bool fragment_shader_result = false;
bool geometry_shader_result = false;
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
bool tess_ctrl_shader_result = false;
bool tess_eval_shader_result = false;
bool vertex_shader_result = false;
/* Prepare storage for testure data */
std::vector<glw::GLint> image_data;
image_data.resize(1);
/* Get texture contents */
gl.bindTexture(GL_TEXTURE_2D, m_color_texture_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture");
gl.getTexImage(GL_TEXTURE_2D, 0 /* level */, GL_RED_INTEGER, GL_INT, &image_data[0]);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetTexImage");
/* Get transform feedback data */
feedback_data = (glw::GLint*)gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
GLU_EXPECT_NO_ERROR(gl.getError(), "MapBuffer");
/* Verify results */
fragment_shader_result = (m_result_success == image_data[0]);
geometry_shader_result = (m_result_success == feedback_data[0]);
tess_ctrl_shader_result = (m_result_success == feedback_data[1]);
tess_eval_shader_result = (m_result_success == feedback_data[2]);
vertex_shader_result = (m_result_success == feedback_data[3]);
/* Unmap transform feedback buffer */
gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
GLU_EXPECT_NO_ERROR(gl.getError(), "UnmapBuffer");
/* Set result */
if (true != (fragment_shader_result && geometry_shader_result && tess_ctrl_shader_result &&
tess_eval_shader_result && vertex_shader_result))
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Error" << tcu::TestLog::EndMessage;
m_context.getTestContext().getLog() << tcu::TestLog::Message
<< "Vertex shader stage result: " << vertex_shader_result
<< tcu::TestLog::EndMessage;
m_context.getTestContext().getLog() << tcu::TestLog::Message
<< "Tesselation control shader stage result: " << tess_ctrl_shader_result
<< tcu::TestLog::EndMessage;
m_context.getTestContext().getLog() << tcu::TestLog::Message
<< "Tesselation evaluation shader stage result: " << tess_eval_shader_result
<< tcu::TestLog::EndMessage;
m_context.getTestContext().getLog() << tcu::TestLog::Message
<< "Geometry shader stage result: " << geometry_shader_result
<< tcu::TestLog::EndMessage;
m_context.getTestContext().getLog() << tcu::TestLog::Message
<< "Fragment shader stage result: " << fragment_shader_result
<< tcu::TestLog::EndMessage;
return false;
}
else
{
return true;
}
}
/** Write main routine of <shader_stage> shader to stream
*
* @param stream Output stream with source code of shader
* @param shader_stage Shader stage
**/
void GPUShaderFP64Test3::writeMainBody(std::ostream& stream, shaderStage shader_stage) const
{
glw::GLuint type_ordinal = 1;
const glw::GLchar* varying_name = "";
/* Select name for varying that will hold result of "that" shader_stage */
switch (shader_stage)
{
case FRAGMENT_SHADER:
varying_name = m_varying_name_fs_out_fs_result;
break;
case GEOMETRY_SHADER:
varying_name = m_varying_name_gs_fs_gs_result;
break;
case TESS_CONTROL_SHADER:
varying_name = m_varying_name_tcs_tes_tcs_result;
break;
case TESS_EVAL_SHADER:
varying_name = m_varying_name_tes_gs_tes_result;
break;
case VERTEX_SHADER:
varying_name = m_varying_name_vs_tcs_vs_result;
break;
}
/* void main() */
stream << "void main()\n"
"{\n";
/* Tesselation levels output */
if (TESS_CONTROL_SHADER == shader_stage)
{
stream << "gl_TessLevelOuter[0] = 1.0;\n"
"gl_TessLevelOuter[1] = 1.0;\n"
"gl_TessLevelOuter[2] = 1.0;\n"
"gl_TessLevelOuter[3] = 1.0;\n"
"gl_TessLevelInner[0] = 1.0;\n"
"gl_TessLevelInner[1] = 1.0;\n"
"\n";
}
/* For each "double precision" uniform
*
* [else] if (TYPE_NAME(PREDIFINED_VALUES) != NAMED_UNIFORM_BLOCK_NAME.UNIFORM_NAME)
* {
* VARYING_NAME = m_result_failure;
* }
*/
for (std::vector<uniformDetails>::const_iterator it = m_uniform_details.begin(), end = m_uniform_details.end();
end != it; ++it, ++type_ordinal)
{
stream << " ";
/* First comparison is done with if, next with else if */
if (1 != type_ordinal)
{
stream << "else ";
}
/* if (TYPE_NAME( */
stream << "if (" << it->m_type_name << "(";
/* PREDIFINED_VALUES */
for (glw::GLuint element = 0; element < it->m_n_elements; ++element)
{
stream << getExpectedValue(type_ordinal, element);
/* Separate with comma */
if (it->m_n_elements != element + 1)
{
stream << ", ";
}
}
/*
* ) != NAMED_UNIFORM_BLOCK_NAME.UNIFORM_NAME)
* {
* VARYING_NAME
*/
stream << ") != " << m_uniform_block_instance_name << "." << it->m_name << ")\n"
" {\n"
" "
<< varying_name;
/* Tesselation control outputs have to be arrays indexed with gl_InvocationID */
if (TESS_CONTROL_SHADER == shader_stage)
{
stream << "[gl_InvocationID]";
}
/*
* = m_result_failure;
* }
*/
stream << " = " << m_result_failure << ";\n"
<< " }\n";
}
/* If all comparisons are ok
*
* else
* {
* VARYING_NAME = m_result_success;
* }
*/
/*
* else
* {
* VARYING_NAME
*/
stream << " else\n"
" {\n"
" "
<< varying_name;
/* Tesselation control outputs have to be arrays indexed with gl_InvocationID */
if (TESS_CONTROL_SHADER == shader_stage)
{
stream << "[gl_InvocationID]";
}
/*
* = m_result_success;
* }
*
*/
stream << " = " << m_result_success << ";\n"
<< " }\n"
<< "\n";
/* For each pair of "input/output" varyings
*
* OUTPUT_VARYING_NAME = INPUT_VARYING_NAME;
**/
writeVaryingPassthrough(stream, shader_stage);
/* Geometry shader have to emit vertex */
if (GEOMETRY_SHADER == shader_stage)
{
stream << "\n"
"gl_Position = vec4(0.0f, 0.0f, 0.0f, 1.0f);"
"EmitVertex();\n"
"EndPrimitive();\n";
}
/* Close scope of main */
stream << "}\n\n";
}
/** Write shader preamble to stream
*
* @param stream Output stream with source code of shader
* @param shader_stage Shader stage
**/
void GPUShaderFP64Test3::writePreamble(std::ostream& stream, shaderStage shader_stage) const
{
stream << "#version 400 core\n"
"\n"
"precision highp float;\n"
"\n";
switch (shader_stage)
{
case FRAGMENT_SHADER:
break;
case GEOMETRY_SHADER:
stream << "layout(points) in;\n"
"layout(points, max_vertices = 1) out;\n"
"\n";
break;
case TESS_CONTROL_SHADER:
stream << "layout(vertices = 1) out;\n"
"\n";
break;
case TESS_EVAL_SHADER:
stream << "layout(isolines, point_mode) in;\n"
"\n";
break;
case VERTEX_SHADER:
break;
}
}
/** Write name uniform blcok definition with specific layout to stream
*
* @param stream Output stream with source code of shader
* @param uniform_data_layout Buffer layout
**/
void GPUShaderFP64Test3::writeUniformBlock(std::ostream& stream, uniformDataLayout uniform_data_layout) const
{
const glw::GLchar* layout = getUniformLayoutName(uniform_data_layout);
stream << "layout(" << layout << ") uniform " << m_uniform_block_name << "\n"
"{\n"
" ivec3 dummy1[3];\n"
" double double_value;\n"
" bool dummy2;\n"
" dvec2 dvec2_value;\n"
" bvec3 dummy3;\n"
" dvec3 dvec3_value;\n"
" int dummy4[3];\n"
" dvec4 dvec4_value;\n"
" bool dummy5;\n"
" bool dummy6[2];\n"
" dmat2 dmat2_value;\n"
" dmat3 dmat3_value;\n"
" bool dummy7;\n"
" dmat4 dmat4_value;\n"
" dmat2x3 dmat2x3_value;\n"
" uvec3 dummy8;\n"
" dmat2x4 dmat2x4_value;\n"
" dmat3x2 dmat3x2_value;\n"
" bool dummy9;\n"
" dmat3x4 dmat3x4_value;\n"
" int dummy10;\n"
" dmat4x2 dmat4x2_value;\n"
" dmat4x3 dmat4x3_value;\n"
"} "
<< m_uniform_block_instance_name << ";\n";
stream << "\n";
}
/** Write definitions of varyings specific for given <shader_stage> to stream
*
* @param stream Output stream with source code of shader
* @param shader_stage Shader stage
**/
void GPUShaderFP64Test3::writeVaryingDeclarations(std::ostream& stream, shaderStage shader_stage) const
{
static const glw::GLchar* const varying_type = "int";
switch (shader_stage)
{
case FRAGMENT_SHADER:
/* In */
stream << "flat in " << varying_type << " " << m_varying_name_gs_fs_gs_result << ";\n";
stream << "flat in " << varying_type << " " << m_varying_name_gs_fs_tcs_result << ";\n";
stream << "flat in " << varying_type << " " << m_varying_name_gs_fs_tes_result << ";\n";
stream << "flat in " << varying_type << " " << m_varying_name_gs_fs_vs_result << ";\n";
stream << "\n";
/* Out */
stream << "layout (location = 0) out " << varying_type << " " << m_varying_name_fs_out_fs_result << ";\n";
break;
case GEOMETRY_SHADER:
/* In */
stream << "in " << varying_type << " " << m_varying_name_tes_gs_tcs_result << "[];\n";
stream << "in " << varying_type << " " << m_varying_name_tes_gs_tes_result << "[];\n";
stream << "in " << varying_type << " " << m_varying_name_tes_gs_vs_result << "[];\n";
stream << "\n";
/* Out */
stream << "flat out " << varying_type << " " << m_varying_name_gs_fs_gs_result << ";\n";
stream << "flat out " << varying_type << " " << m_varying_name_gs_fs_tcs_result << ";\n";
stream << "flat out " << varying_type << " " << m_varying_name_gs_fs_tes_result << ";\n";
stream << "flat out " << varying_type << " " << m_varying_name_gs_fs_vs_result << ";\n";
break;
case TESS_CONTROL_SHADER:
/* In */
stream << "in " << varying_type << " " << m_varying_name_vs_tcs_vs_result << "[];\n";
stream << "\n";
/* Out */
stream << "out " << varying_type << " " << m_varying_name_tcs_tes_tcs_result << "[];\n";
stream << "out " << varying_type << " " << m_varying_name_tcs_tes_vs_result << "[];\n";
break;
case TESS_EVAL_SHADER:
/* In */
stream << "in " << varying_type << " " << m_varying_name_tcs_tes_tcs_result << "[];\n";
stream << "in " << varying_type << " " << m_varying_name_tcs_tes_vs_result << "[];\n";
stream << "\n";
/* Out */
stream << "out " << varying_type << " " << m_varying_name_tes_gs_tcs_result << ";\n";
stream << "out " << varying_type << " " << m_varying_name_tes_gs_tes_result << ";\n";
stream << "out " << varying_type << " " << m_varying_name_tes_gs_vs_result << ";\n";
break;
case VERTEX_SHADER:
/* Out */
stream << "out " << varying_type << " " << m_varying_name_vs_tcs_vs_result << ";\n";
break;
}
stream << "\n";
}
/** Write passthrough code of "input/output" varying pairs to stream
*
* @param stream Output stream with source code of shader
* @param shader_stage Shader stage
**/
void GPUShaderFP64Test3::writeVaryingPassthrough(std::ostream& stream, shaderStage shader_stage) const
{
switch (shader_stage)
{
case FRAGMENT_SHADER:
break;
case GEOMETRY_SHADER:
stream << " " << m_varying_name_gs_fs_tcs_result << " = " << m_varying_name_tes_gs_tcs_result << "[0];\n";
stream << " " << m_varying_name_gs_fs_tes_result << " = " << m_varying_name_tes_gs_tes_result << "[0];\n";
stream << " " << m_varying_name_gs_fs_vs_result << " = " << m_varying_name_tes_gs_vs_result << "[0];\n";
break;
case TESS_CONTROL_SHADER:
stream << " " << m_varying_name_tcs_tes_vs_result
<< "[gl_InvocationID] = " << m_varying_name_vs_tcs_vs_result << "[0];\n";
break;
case TESS_EVAL_SHADER:
stream << " " << m_varying_name_tes_gs_tcs_result << " = " << m_varying_name_tcs_tes_tcs_result << "[0];\n";
stream << " " << m_varying_name_tes_gs_vs_result << " = " << m_varying_name_tcs_tes_vs_result << "[0];\n";
break;
case VERTEX_SHADER:
break;
}
}
/** Constructor. Sets all uniform locations to -1 and sets all
* values to 0.
*/
GPUShaderFP64Test4::_data::_data()
{
memset(&uniform_double, 0, sizeof(uniform_double));
memset(uniform_dvec2, 0, sizeof(uniform_dvec2));
memset(uniform_dvec2_arr, 0, sizeof(uniform_dvec2_arr));
memset(uniform_dvec3, 0, sizeof(uniform_dvec3));
memset(uniform_dvec3_arr, 0, sizeof(uniform_dvec3_arr));
memset(uniform_dvec4, 0, sizeof(uniform_dvec4));
memset(uniform_dvec4_arr, 0, sizeof(uniform_dvec4_arr));
uniform_location_double = -1;
uniform_location_double_arr[0] = -1;
uniform_location_double_arr[1] = -1;
uniform_location_dvec2 = -1;
uniform_location_dvec2_arr[0] = -1;
uniform_location_dvec2_arr[1] = -1;
uniform_location_dvec3 = -1;
uniform_location_dvec3_arr[0] = -1;
uniform_location_dvec3_arr[1] = -1;
uniform_location_dvec4 = -1;
uniform_location_dvec4_arr[0] = -1;
uniform_location_dvec4_arr[1] = -1;
}
/** Constructor
*
* @param context Rendering context.
*/
GPUShaderFP64Test4::GPUShaderFP64Test4(deqp::Context& context)
: TestCase(context, "state_query", "Verifies glGet*() calls, as well as \"program interface query\"-specific tools"
" report correct properties of & values assigned to double-precision uniforms.")
, m_has_test_passed(true)
, m_uniform_name_buffer(0)
, m_cs_id(0)
, m_fs_id(0)
, m_gs_id(0)
, m_po_cs_id(0)
, m_po_noncs_id(0)
, m_tc_id(0)
, m_te_id(0)
, m_vs_id(0)
{
/* Left blank intentionally */
}
/** Deinitializes all GL objects, as well as releases all bufers, that may
* have beenallocated or created during test execution.
**/
void GPUShaderFP64Test4::deinit()
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
if (m_cs_id != 0)
{
gl.deleteShader(m_cs_id);
m_cs_id = 0;
}
if (m_fs_id != 0)
{
gl.deleteShader(m_fs_id);
m_fs_id = 0;
}
if (m_gs_id != 0)
{
gl.deleteShader(m_gs_id);
m_gs_id = 0;
}
if (m_po_cs_id != 0)
{
gl.deleteProgram(m_po_cs_id);
m_po_cs_id = 0;
}
if (m_po_noncs_id != 0)
{
gl.deleteProgram(m_po_noncs_id);
m_po_noncs_id = 0;
}
if (m_tc_id != 0)
{
gl.deleteShader(m_tc_id);
m_tc_id = 0;
}
if (m_te_id != 0)
{
gl.deleteShader(m_te_id);
m_te_id = 0;
}
if (m_uniform_name_buffer != DE_NULL)
{
delete[] m_uniform_name_buffer;
m_uniform_name_buffer = DE_NULL;
}
if (m_vs_id != 0)
{
gl.deleteShader(m_vs_id);
m_vs_id = 0;
}
}
/** Generates double-precision values for all uniforms defined for all program objects
* used by the test.
*
* This function DOES NOT use any GL API. It only calculates & stores the values
* in internal storage for further usage.
*/
void GPUShaderFP64Test4::generateUniformValues()
{
_stage_data* stages[] = { &m_data_cs, &m_data_fs, &m_data_gs, &m_data_tc, &m_data_te, &m_data_vs };
const unsigned int n_stages = sizeof(stages) / sizeof(stages[0]);
for (unsigned int n_stage = 0; n_stage < n_stages; ++n_stage)
{
_stage_data* stage_ptr = stages[n_stage];
/* Iterate through all uniform components and assign them double values */
double* double_ptrs[] = {
&stage_ptr->uniform_structure_arrays[0].uniform_double,
stage_ptr->uniform_structure_arrays[0].uniform_double_arr + 0,
stage_ptr->uniform_structure_arrays[0].uniform_double_arr + 1,
stage_ptr->uniform_structure_arrays[0].uniform_dvec2 + 0,
stage_ptr->uniform_structure_arrays[0].uniform_dvec2 + 1,
stage_ptr->uniform_structure_arrays[0].uniform_dvec3 + 0,
stage_ptr->uniform_structure_arrays[0].uniform_dvec3 + 1,
stage_ptr->uniform_structure_arrays[0].uniform_dvec3 + 2,
stage_ptr->uniform_structure_arrays[0].uniform_dvec4 + 0,
stage_ptr->uniform_structure_arrays[0].uniform_dvec4 + 1,
stage_ptr->uniform_structure_arrays[0].uniform_dvec4 + 2,
stage_ptr->uniform_structure_arrays[0].uniform_dvec4 + 3,
&stage_ptr->uniform_structure_arrays[1].uniform_double,
stage_ptr->uniform_structure_arrays[1].uniform_double_arr + 0,
stage_ptr->uniform_structure_arrays[1].uniform_double_arr + 1,
stage_ptr->uniform_structure_arrays[1].uniform_dvec2 + 0,
stage_ptr->uniform_structure_arrays[1].uniform_dvec2 + 1,
stage_ptr->uniform_structure_arrays[1].uniform_dvec3 + 0,
stage_ptr->uniform_structure_arrays[1].uniform_dvec3 + 1,
stage_ptr->uniform_structure_arrays[1].uniform_dvec3 + 2,
stage_ptr->uniform_structure_arrays[1].uniform_dvec4 + 0,
stage_ptr->uniform_structure_arrays[1].uniform_dvec4 + 1,
stage_ptr->uniform_structure_arrays[1].uniform_dvec4 + 2,
stage_ptr->uniform_structure_arrays[1].uniform_dvec4 + 3,
&stage_ptr->uniforms.uniform_double,
stage_ptr->uniforms.uniform_double_arr + 0,
stage_ptr->uniforms.uniform_double_arr + 1,
stage_ptr->uniforms.uniform_dvec2 + 0,
stage_ptr->uniforms.uniform_dvec2 + 1,
stage_ptr->uniforms.uniform_dvec2_arr + 0,
stage_ptr->uniforms.uniform_dvec2_arr + 1,
stage_ptr->uniforms.uniform_dvec2_arr + 2,
stage_ptr->uniforms.uniform_dvec2_arr + 3,
stage_ptr->uniforms.uniform_dvec3 + 0,
stage_ptr->uniforms.uniform_dvec3 + 1,
stage_ptr->uniforms.uniform_dvec3 + 2,
stage_ptr->uniforms.uniform_dvec3_arr + 0,
stage_ptr->uniforms.uniform_dvec3_arr + 1,
stage_ptr->uniforms.uniform_dvec3_arr + 2,
stage_ptr->uniforms.uniform_dvec3_arr + 3,
stage_ptr->uniforms.uniform_dvec3_arr + 4,
stage_ptr->uniforms.uniform_dvec3_arr + 5,
stage_ptr->uniforms.uniform_dvec4 + 0,
stage_ptr->uniforms.uniform_dvec4 + 1,
stage_ptr->uniforms.uniform_dvec4 + 2,
stage_ptr->uniforms.uniform_dvec4 + 3,
stage_ptr->uniforms.uniform_dvec4_arr + 0,
stage_ptr->uniforms.uniform_dvec4_arr + 1,
stage_ptr->uniforms.uniform_dvec4_arr + 2,
stage_ptr->uniforms.uniform_dvec4_arr + 3,
stage_ptr->uniforms.uniform_dvec4_arr + 4,
stage_ptr->uniforms.uniform_dvec4_arr + 5,
stage_ptr->uniforms.uniform_dvec4_arr + 6,
stage_ptr->uniforms.uniform_dvec4_arr + 7,
};
const unsigned int n_double_ptrs = sizeof(double_ptrs) / sizeof(double_ptrs[0]);
for (unsigned int n_double_ptr = 0; n_double_ptr < n_double_ptrs; ++n_double_ptr)
{
double* double_ptr = double_ptrs[n_double_ptr];
/* Generate the value. Use magic numbers to generate a set of double-precision
* floating-point numbers.
*/
static int seed = 16762362;
*double_ptr = ((double)(seed % 1732)) / 125.7 * (((seed % 2) == 0) ? 1 : -1);
seed += 751;
} /* for (all pointers to double variables) */
} /* for (all stages) */
}
/** Initializes all program & shader objects required to run the test. The function also
* retrieves locations of all uniforms defined by both program objects.
**/
void GPUShaderFP64Test4::initProgramObjects()
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Create program & shader objects */
/* Compute shader support and GL 4.2 required */
if ((true == m_context.getContextInfo().isExtensionSupported("GL_ARB_compute_shader")) &&
(true == Utils::isGLVersionAtLeast(gl, 4 /* major */, 2 /* minor */)))
{
m_cs_id = gl.createShader(GL_COMPUTE_SHADER);
}
m_fs_id = gl.createShader(GL_FRAGMENT_SHADER);
m_gs_id = gl.createShader(GL_GEOMETRY_SHADER);
m_tc_id = gl.createShader(GL_TESS_CONTROL_SHADER);
m_te_id = gl.createShader(GL_TESS_EVALUATION_SHADER);
m_vs_id = gl.createShader(GL_VERTEX_SHADER);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call(s) failed.");
/* m_cs_id is initialized only if compute shaders are supported */
if (0 != m_cs_id)
{
m_po_cs_id = gl.createProgram();
}
m_po_noncs_id = gl.createProgram();
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call(s) failed.");
/* Configure compute shader body */
const char* cs_body = "#version 420\n"
"#extension GL_ARB_compute_shader : require\n"
"\n"
"layout(local_size_x = 2, local_size_y = 2, local_size_z = 2) in;\n"
"\n"
"layout(rgba32f) uniform image2D testImage;\n"
"\n"
"uniform double cs_double;\n"
"uniform dvec2 cs_dvec2;\n"
"uniform dvec3 cs_dvec3;\n"
"uniform dvec4 cs_dvec4;\n"
"uniform double cs_double_arr[2];\n"
"uniform dvec2 cs_dvec2_arr [2];\n"
"uniform dvec3 cs_dvec3_arr [2];\n"
"uniform dvec4 cs_dvec4_arr [2];\n"
"\n"
"uniform struct cs_struct\n"
"{\n"
" double struct_double;\n"
" dvec2 struct_dvec2;\n"
" dvec3 struct_dvec3;\n"
" dvec4 struct_dvec4;\n"
"} cs_array[2];\n"
"\n"
"void main()\n"
"{\n"
" double tmp = cs_double * cs_dvec2.x * cs_dvec3.y "
" * cs_dvec4.z *\n"
" cs_double_arr[0] * cs_dvec2_arr[0].x * "
"cs_dvec3_arr[0].z * cs_dvec4_arr[0].w *\n"
" cs_double_arr[1] * cs_dvec2_arr[1].x * "
"cs_dvec3_arr[1].z * cs_dvec4_arr[1].w *\n"
" cs_array[0].struct_double * cs_array[0].struct_dvec2.y * "
"cs_array[0].struct_dvec3.z * cs_array[0].struct_dvec4.w *\n"
" cs_array[1].struct_double * cs_array[1].struct_dvec2.y * "
"cs_array[1].struct_dvec3.z * cs_array[1].struct_dvec4.w;\n"
"\n"
" imageStore(testImage, ivec2(0, 0), (tmp > 1.0) ? vec4(1.0) : vec4(0.0) );\n"
"}\n";
/* m_cs_id is initialized only if compute shaders are supported */
if (0 != m_cs_id)
{
gl.shaderSource(m_cs_id, 1 /* count */, &cs_body, DE_NULL /* length */);
GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed.");
}
/* Configure vertex shader body */
const char* vs_body = "#version 400\n"
"\n"
"uniform double vs_double;\n"
"uniform dvec2 vs_dvec2;\n"
"uniform dvec3 vs_dvec3;\n"
"uniform dvec4 vs_dvec4;\n"
"uniform double vs_double_arr[2];\n"
"uniform dvec2 vs_dvec2_arr [2];\n"
"uniform dvec3 vs_dvec3_arr [2];\n"
"uniform dvec4 vs_dvec4_arr [2];\n"
"\n"
"uniform struct vs_struct\n"
"{\n"
" double struct_double;\n"
" dvec2 struct_dvec2;\n"
" dvec3 struct_dvec3;\n"
" dvec4 struct_dvec4;\n"
"} vs_array[2];\n"
"\n"
"void main()\n"
"{\n"
" if (vs_double * vs_dvec2.x * vs_dvec3.x "
"* vs_dvec4.x *\n"
" vs_double_arr[0] * vs_dvec2_arr[0].x * vs_dvec3_arr[0].x "
"* vs_dvec4_arr[0].x *\n"
" vs_double_arr[1] * vs_dvec2_arr[1].x * vs_dvec3_arr[1].x "
"* vs_dvec4_arr[1].x *\n"
" vs_array[0].struct_double * vs_array[0].struct_dvec2.x * vs_array[0].struct_dvec3.x "
"* vs_array[0].struct_dvec4.x *\n"
" vs_array[1].struct_double * vs_array[1].struct_dvec2.x * vs_array[1].struct_dvec3.x "
"* vs_array[1].struct_dvec4.x > 1.0)\n"
" {\n"
" gl_Position = vec4(0);\n"
" }\n"
" else\n"
" {\n"
" gl_Position = vec4(1);\n"
" }\n"
"}\n";
gl.shaderSource(m_vs_id, 1 /* count */, &vs_body, DE_NULL /* length */);
GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed.");
/* Configure tessellation control shader body */
const char* tc_body = "#version 400\n"
"\n"
"uniform double tc_double;\n"
"uniform dvec2 tc_dvec2;\n"
"uniform dvec3 tc_dvec3;\n"
"uniform dvec4 tc_dvec4;\n"
"uniform double tc_double_arr[2];\n"
"uniform dvec2 tc_dvec2_arr [2];\n"
"uniform dvec3 tc_dvec3_arr [2];\n"
"uniform dvec4 tc_dvec4_arr [2];\n"
"\n"
"uniform struct tc_struct\n"
"{\n"
" double struct_double;\n"
" dvec2 struct_dvec2;\n"
" dvec3 struct_dvec3;\n"
" dvec4 struct_dvec4;\n"
"} tc_array[2];\n"
"\n"
"layout(vertices = 4) out;\n"
"\n"
"void main()\n"
"{\n"
" gl_TessLevelOuter[0] = (tc_double > 1.0) ? 2.0 : 3.0;\n"
" gl_TessLevelOuter[1] = (tc_dvec2.x > 1.0) ? 3.0 : 4.0;\n"
" gl_TessLevelOuter[2] = (tc_dvec3.x > 1.0) ? 4.0 : 5.0;\n"
" gl_TessLevelOuter[3] = (tc_dvec4.x > 1.0) ? 5.0 : 6.0;\n"
" gl_TessLevelInner[0] = (tc_double_arr[0] > 1.0) ? 6.0 : 7.0;\n"
" gl_TessLevelInner[1] = (tc_double_arr[1] > 1.0) ? 7.0 : 8.0;\n"
"\n"
" if (tc_dvec2_arr[0].y * tc_dvec2_arr[1].y *\n"
" tc_dvec3_arr[0].z * tc_dvec3_arr[1].z *\n"
" tc_dvec4_arr[0].z * tc_dvec4_arr[1].z *\n"
" tc_array[0].struct_double * tc_array[0].struct_dvec2.x * \n"
" tc_array[0].struct_dvec3.y * tc_array[0].struct_dvec4.z * \n"
" tc_array[1].struct_double * tc_array[1].struct_dvec2.x * \n"
" tc_array[1].struct_dvec3.y * tc_array[1].struct_dvec4.z > 0.0)\n"
" {\n"
" gl_TessLevelInner[1] = 3.0;\n"
" }\n"
"}\n";
gl.shaderSource(m_tc_id, 1 /* count */, &tc_body, DE_NULL /* length */);
GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed.");
/* Configure tessellation evaluation shader body */
const char* te_body = "#version 400\n"
"\n"
"uniform double te_double;\n"
"uniform dvec2 te_dvec2;\n"
"uniform dvec3 te_dvec3;\n"
"uniform dvec4 te_dvec4;\n"
"uniform double te_double_arr[2];\n"
"uniform dvec2 te_dvec2_arr [2];\n"
"uniform dvec3 te_dvec3_arr [2];\n"
"uniform dvec4 te_dvec4_arr [2];\n"
"\n"
"uniform struct te_struct\n"
"{\n"
" double struct_double;\n"
" dvec2 struct_dvec2;\n"
" dvec3 struct_dvec3;\n"
" dvec4 struct_dvec4;\n"
"} te_array[2];\n"
"\n"
"layout(triangles) in;\n"
"\n"
"void main()\n"
"{\n"
" if (te_double * te_dvec2.x * te_dvec3.x "
"* te_dvec4.x *\n"
" te_double_arr[0] * te_dvec2_arr[0].x * te_dvec3_arr[0].x "
"* te_dvec4_arr[0].x *\n"
" te_double_arr[1] * te_dvec2_arr[1].x * te_dvec3_arr[1].x "
"* te_dvec4_arr[1].x *\n"
" te_array[0].struct_double * te_array[0].struct_dvec2.x * te_array[0].struct_dvec3.x "
"* te_array[0].struct_dvec4.x *\n"
" te_array[1].struct_double * te_array[1].struct_dvec2.x * te_array[1].struct_dvec3.x "
"* te_array[1].struct_dvec4.x > 1.0)\n"
" {\n"
" gl_Position = gl_in[0].gl_Position;\n"
" }\n"
" else\n"
" {\n"
" gl_Position = gl_in[0].gl_Position + vec4(1);\n"
" }\n"
"}\n";
gl.shaderSource(m_te_id, 1 /* count */, &te_body, DE_NULL /* length */);
GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed.");
/* Configure geometry shader body */
const char* gs_body = "#version 400\n"
"\n"
"uniform double gs_double;\n"
"uniform dvec2 gs_dvec2;\n"
"uniform dvec3 gs_dvec3;\n"
"uniform dvec4 gs_dvec4;\n"
"uniform double gs_double_arr[2];\n"
"uniform dvec2 gs_dvec2_arr [2];\n"
"uniform dvec3 gs_dvec3_arr [2];\n"
"uniform dvec4 gs_dvec4_arr [2];\n"
"\n"
"uniform struct gs_struct\n"
"{\n"
" double struct_double;\n"
" dvec2 struct_dvec2;\n"
" dvec3 struct_dvec3;\n"
" dvec4 struct_dvec4;\n"
"} gs_array[2];\n"
"\n"
"layout (points) in;\n"
"layout (points, max_vertices = 1) out;\n"
"\n"
"void main()\n"
"{\n"
" if (gs_double * gs_dvec2.x * gs_dvec3.x "
"* gs_dvec4.x *\n"
" gs_double_arr[0] * gs_dvec2_arr[0].x * gs_dvec3_arr[0].x "
"* gs_dvec4_arr[0].x *\n"
" gs_double_arr[1] * gs_dvec2_arr[1].x * gs_dvec3_arr[1].x "
"* gs_dvec4_arr[1].x *\n"
" gs_array[0].struct_double * gs_array[0].struct_dvec2.x * gs_array[0].struct_dvec3.x "
"* gs_array[0].struct_dvec4.x *\n"
" gs_array[1].struct_double * gs_array[1].struct_dvec2.x * gs_array[1].struct_dvec3.x "
"* gs_array[1].struct_dvec4.x > 1.0)\n"
" {\n"
" gl_Position = gl_in[0].gl_Position;\n"
" }\n"
" else\n"
" {\n"
" gl_Position = gl_in[0].gl_Position + vec4(1);\n"
" }\n"
"\n"
" EmitVertex();\n"
"}\n";
gl.shaderSource(m_gs_id, 1 /* count */, &gs_body, DE_NULL /* length */);
GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed.");
/* Configure fragment shader body */
const char* fs_body = "#version 400\n"
"\n"
"uniform double fs_double;\n"
"uniform dvec2 fs_dvec2;\n"
"uniform dvec3 fs_dvec3;\n"
"uniform dvec4 fs_dvec4;\n"
"uniform double fs_double_arr[2];\n"
"uniform dvec2 fs_dvec2_arr [2];\n"
"uniform dvec3 fs_dvec3_arr [2];\n"
"uniform dvec4 fs_dvec4_arr [2];\n"
"\n"
"uniform struct fs_struct\n"
"{\n"
" double struct_double;\n"
" dvec2 struct_dvec2;\n"
" dvec3 struct_dvec3;\n"
" dvec4 struct_dvec4;\n"
"} fs_array[2];\n"
"\n"
"out vec4 result;\n"
"\n"
"void main()\n"
"{\n"
" if (fs_double * fs_dvec2.x * fs_dvec3.x "
"* fs_dvec4.x *\n"
" fs_double_arr[0] * fs_dvec2_arr[0].x * fs_dvec3_arr[0].x "
"* fs_dvec4_arr[0].x *\n"
" fs_double_arr[1] * fs_dvec2_arr[1].x * fs_dvec3_arr[1].x "
"* fs_dvec4_arr[1].x *\n"
" fs_array[0].struct_double * fs_array[0].struct_dvec2.x * fs_array[0].struct_dvec3.x "
"* fs_array[0].struct_dvec4.x *\n"
" fs_array[1].struct_double * fs_array[1].struct_dvec2.x * fs_array[1].struct_dvec3.x "
"* fs_array[1].struct_dvec4.x > 1.0)\n"
" {\n"
" result = vec4(0.0);\n"
" }\n"
" else\n"
" {\n"
" result = vec4(1.0);\n"
" }\n"
"}\n";
gl.shaderSource(m_fs_id, 1 /* count */, &fs_body, DE_NULL /* length */);
GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed");
/* Compile the shaders */
const glw::GLuint shaders[] = { m_cs_id, m_fs_id, m_gs_id, m_tc_id, m_te_id, m_vs_id };
const unsigned int n_shaders = sizeof(shaders) / sizeof(shaders[0]);
for (unsigned int n_shader = 0; n_shader < n_shaders; ++n_shader)
{
glw::GLint compile_status = GL_FALSE;
glw::GLuint so_id = shaders[n_shader];
/* Skip compute shader if not supported */
if (0 == so_id)
{
continue;
}
gl.compileShader(so_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed");
gl.getShaderiv(so_id, GL_COMPILE_STATUS, &compile_status);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed");
if (compile_status != GL_TRUE)
{
TCU_FAIL("Shader compilation failed");
}
if (so_id == m_cs_id)
{
gl.attachShader(m_po_cs_id, so_id);
}
else
{
gl.attachShader(m_po_noncs_id, so_id);
}
GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call failed.");
} /* for (all shaders) */
/* Link the program */
const glw::GLuint programs[] = { m_po_cs_id, m_po_noncs_id };
const unsigned int n_programs = sizeof(programs) / sizeof(programs[0]);
glw::GLint link_status = GL_FALSE;
for (unsigned int n_program = 0; n_program < n_programs; ++n_program)
{
glw::GLuint po_id = programs[n_program];
/* Skip compute shader program if not supported */
if (0 == po_id)
{
continue;
}
gl.linkProgram(po_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed.");
gl.getProgramiv(po_id, GL_LINK_STATUS, &link_status);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed");
if (link_status != GL_TRUE)
{
TCU_FAIL("Program linking failed");
}
} /* for (both program objects) */
/* Retrieve uniform locations */
_stage_data* cs_stage_data[] = { &m_data_cs };
static const char* cs_uniform_prefixes[] = { "cs_" };
static const unsigned int n_cs_uniform_prefixes = sizeof(cs_uniform_prefixes) / sizeof(cs_uniform_prefixes[0]);
_stage_data* noncs_stage_data[] = { &m_data_fs, &m_data_gs, &m_data_tc, &m_data_te, &m_data_vs };
static const char* noncs_uniform_prefixes[] = { "fs_", "gs_", "tc_", "te_", "vs_" };
static const unsigned int n_noncs_uniform_prefixes =
sizeof(noncs_uniform_prefixes) / sizeof(noncs_uniform_prefixes[0]);
for (unsigned int n_program = 0; n_program < n_programs; ++n_program)
{
unsigned int n_uniform_prefixes = DE_NULL;
glw::GLuint po_id = programs[n_program];
_stage_data** stages_data = DE_NULL;
const char** uniform_prefixes = DE_NULL;
if (n_program == 0)
{
stages_data = cs_stage_data;
uniform_prefixes = cs_uniform_prefixes;
n_uniform_prefixes = n_cs_uniform_prefixes;
}
else
{
stages_data = noncs_stage_data;
uniform_prefixes = noncs_uniform_prefixes;
n_uniform_prefixes = n_noncs_uniform_prefixes;
}
/* Skip compute shader program if not supported */
if (0 == po_id)
{
continue;
}
/* Uniform names used by the test program consist of a prefix (different for each
* shader stage) and a common part.
*/
for (unsigned int n_uniform_prefix = 0; n_uniform_prefix < n_uniform_prefixes; ++n_uniform_prefix)
{
_stage_data* stage_data = stages_data[n_uniform_prefix];
std::string uniform_prefix = std::string(uniform_prefixes[n_uniform_prefix]);
std::string uniform_double_name = uniform_prefix + "double";
std::string uniform_double_arr0_name = uniform_prefix + "double_arr[0]";
std::string uniform_double_arr1_name = uniform_prefix + "double_arr[1]";
std::string uniform_dvec2_name = uniform_prefix + "dvec2";
std::string uniform_dvec2_arr0_name = uniform_prefix + "dvec2_arr[0]";
std::string uniform_dvec2_arr1_name = uniform_prefix + "dvec2_arr[1]";
std::string uniform_dvec3_name = uniform_prefix + "dvec3";
std::string uniform_dvec3_arr0_name = uniform_prefix + "dvec3_arr[0]";
std::string uniform_dvec3_arr1_name = uniform_prefix + "dvec3_arr[1]";
std::string uniform_dvec4_name = uniform_prefix + "dvec4";
std::string uniform_dvec4_arr0_name = uniform_prefix + "dvec4_arr[0]";
std::string uniform_dvec4_arr1_name = uniform_prefix + "dvec4_arr[1]";
std::string uniform_arr0_double_name = uniform_prefix + "array[0].struct_double";
std::string uniform_arr0_dvec2_name = uniform_prefix + "array[0].struct_dvec2";
std::string uniform_arr0_dvec3_name = uniform_prefix + "array[0].struct_dvec3";
std::string uniform_arr0_dvec4_name = uniform_prefix + "array[0].struct_dvec4";
std::string uniform_arr1_double_name = uniform_prefix + "array[1].struct_double";
std::string uniform_arr1_dvec2_name = uniform_prefix + "array[1].struct_dvec2";
std::string uniform_arr1_dvec3_name = uniform_prefix + "array[1].struct_dvec3";
std::string uniform_arr1_dvec4_name = uniform_prefix + "array[1].struct_dvec4";
/* Retrieve uniform locations */
stage_data->uniforms.uniform_location_double = gl.getUniformLocation(po_id, uniform_double_name.c_str());
stage_data->uniforms.uniform_location_double_arr[0] =
gl.getUniformLocation(po_id, uniform_double_arr0_name.c_str());
stage_data->uniforms.uniform_location_double_arr[1] =
gl.getUniformLocation(po_id, uniform_double_arr1_name.c_str());
stage_data->uniforms.uniform_location_dvec2 = gl.getUniformLocation(po_id, uniform_dvec2_name.c_str());
stage_data->uniforms.uniform_location_dvec2_arr[0] =
gl.getUniformLocation(po_id, uniform_dvec2_arr0_name.c_str());
stage_data->uniforms.uniform_location_dvec2_arr[1] =
gl.getUniformLocation(po_id, uniform_dvec2_arr1_name.c_str());
stage_data->uniforms.uniform_location_dvec3 = gl.getUniformLocation(po_id, uniform_dvec3_name.c_str());
stage_data->uniforms.uniform_location_dvec3_arr[0] =
gl.getUniformLocation(po_id, uniform_dvec3_arr0_name.c_str());
stage_data->uniforms.uniform_location_dvec3_arr[1] =
gl.getUniformLocation(po_id, uniform_dvec3_arr1_name.c_str());
stage_data->uniforms.uniform_location_dvec4 = gl.getUniformLocation(po_id, uniform_dvec4_name.c_str());
stage_data->uniforms.uniform_location_dvec4_arr[0] =
gl.getUniformLocation(po_id, uniform_dvec4_arr0_name.c_str());
stage_data->uniforms.uniform_location_dvec4_arr[1] =
gl.getUniformLocation(po_id, uniform_dvec4_arr1_name.c_str());
stage_data->uniform_structure_arrays[0].uniform_location_double =
gl.getUniformLocation(po_id, uniform_arr0_double_name.c_str());
stage_data->uniform_structure_arrays[0].uniform_location_dvec2 =
gl.getUniformLocation(po_id, uniform_arr0_dvec2_name.c_str());
stage_data->uniform_structure_arrays[0].uniform_location_dvec3 =
gl.getUniformLocation(po_id, uniform_arr0_dvec3_name.c_str());
stage_data->uniform_structure_arrays[0].uniform_location_dvec4 =
gl.getUniformLocation(po_id, uniform_arr0_dvec4_name.c_str());
stage_data->uniform_structure_arrays[1].uniform_location_double =
gl.getUniformLocation(po_id, uniform_arr1_double_name.c_str());
stage_data->uniform_structure_arrays[1].uniform_location_dvec2 =
gl.getUniformLocation(po_id, uniform_arr1_dvec2_name.c_str());
stage_data->uniform_structure_arrays[1].uniform_location_dvec3 =
gl.getUniformLocation(po_id, uniform_arr1_dvec3_name.c_str());
stage_data->uniform_structure_arrays[1].uniform_location_dvec4 =
gl.getUniformLocation(po_id, uniform_arr1_dvec4_name.c_str());
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetUniformLocation() call(s) failed.");
if (stage_data->uniforms.uniform_location_double == -1 ||
stage_data->uniforms.uniform_location_double_arr[0] == -1 ||
stage_data->uniforms.uniform_location_double_arr[1] == -1 ||
stage_data->uniforms.uniform_location_dvec2 == -1 ||
stage_data->uniforms.uniform_location_dvec2_arr[0] == -1 ||
stage_data->uniforms.uniform_location_dvec2_arr[1] == -1 ||
stage_data->uniforms.uniform_location_dvec3 == -1 ||
stage_data->uniforms.uniform_location_dvec3_arr[0] == -1 ||
stage_data->uniforms.uniform_location_dvec3_arr[1] == -1 ||
stage_data->uniforms.uniform_location_dvec4 == -1 ||
stage_data->uniforms.uniform_location_dvec4_arr[0] == -1 ||
stage_data->uniforms.uniform_location_dvec4_arr[1] == -1 ||
stage_data->uniform_structure_arrays[0].uniform_location_double == -1 ||
stage_data->uniform_structure_arrays[0].uniform_location_dvec2 == -1 ||
stage_data->uniform_structure_arrays[0].uniform_location_dvec3 == -1 ||
stage_data->uniform_structure_arrays[0].uniform_location_dvec4 == -1 ||
stage_data->uniform_structure_arrays[1].uniform_location_double == -1 ||
stage_data->uniform_structure_arrays[1].uniform_location_dvec2 == -1 ||
stage_data->uniform_structure_arrays[1].uniform_location_dvec3 == -1 ||
stage_data->uniform_structure_arrays[1].uniform_location_dvec4 == -1)
{
TCU_FAIL("At least one uniform is considered inactive which is invalid.");
}
/* Make sure locations of subsequent items in array uniforms are correct */
if (stage_data->uniforms.uniform_location_double_arr[1] !=
(stage_data->uniforms.uniform_location_double_arr[0] + 1) ||
stage_data->uniforms.uniform_location_dvec2_arr[1] !=
(stage_data->uniforms.uniform_location_dvec2_arr[0] + 1) ||
stage_data->uniforms.uniform_location_dvec3_arr[1] !=
(stage_data->uniforms.uniform_location_dvec3_arr[0] + 1) ||
stage_data->uniforms.uniform_location_dvec4_arr[1] !=
(stage_data->uniforms.uniform_location_dvec4_arr[0] + 1))
{
m_testCtx.getLog() << tcu::TestLog::Message << "Uniform locations:"
" double_arr[0]:"
<< stage_data->uniforms.uniform_location_double_arr[0]
<< " double_arr[1]:" << stage_data->uniforms.uniform_location_double_arr[1]
<< " dvec2_arr[0]:" << stage_data->uniforms.uniform_location_dvec2_arr[0]
<< " dvec2_arr[1]:" << stage_data->uniforms.uniform_location_dvec2_arr[1]
<< " dvec3_arr[0]:" << stage_data->uniforms.uniform_location_dvec3_arr[0]
<< " dvec3_arr[1]:" << stage_data->uniforms.uniform_location_dvec3_arr[1]
<< " dvec4_arr[0]:" << stage_data->uniforms.uniform_location_dvec4_arr[0]
<< " dvec4_arr[1]:" << stage_data->uniforms.uniform_location_dvec4_arr[1]
<< tcu::TestLog::EndMessage;
TCU_FAIL("Double-precision uniform array item locations are invalid.");
}
} /* for (all uniform prefixes) */
} /* for (both program objects) */
}
/** Initializes all objects required to run the test. */
void GPUShaderFP64Test4::initTest()
{
initProgramObjects();
generateUniformValues();
initUniformValues();
}
/** Assigns values generated by generateUniformValues() to uniforms defined by
* both program objects.
**/
void GPUShaderFP64Test4::initUniformValues()
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Iterate through all programs */
_stage_data* cs_stages[] = { &m_data_cs };
_stage_data* noncs_stages[] = { &m_data_fs, &m_data_gs, &m_data_tc, &m_data_te, &m_data_vs };
const unsigned int n_cs_stages = sizeof(cs_stages) / sizeof(cs_stages[0]);
const unsigned int n_noncs_stages = sizeof(noncs_stages) / sizeof(noncs_stages[0]);
const glw::GLuint programs[] = { m_po_cs_id, m_po_noncs_id };
const unsigned int n_programs = sizeof(programs) / sizeof(programs[0]);
for (unsigned int n_program = 0; n_program < n_programs; ++n_program)
{
glw::GLuint po_id = programs[n_program];
unsigned int n_stages = 0;
_stage_data** stage_data = DE_NULL;
if (po_id == m_po_cs_id)
{
n_stages = n_cs_stages;
stage_data = cs_stages;
}
else
{
n_stages = n_noncs_stages;
stage_data = noncs_stages;
}
/* Skip compute shader program if not supported */
if (0 == po_id)
{
continue;
}
gl.useProgram(po_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "UseProgram");
for (unsigned int n_stage = 0; n_stage < n_stages; ++n_stage)
{
/* Iterate through all uniforms */
_stage_data* stage_ptr = stage_data[n_stage];
gl.uniform1d(stage_ptr->uniforms.uniform_location_double, stage_ptr->uniforms.uniform_double);
gl.uniform1d(stage_ptr->uniforms.uniform_location_double_arr[0], stage_ptr->uniforms.uniform_double_arr[0]);
gl.uniform1d(stage_ptr->uniforms.uniform_location_double_arr[1], stage_ptr->uniforms.uniform_double_arr[1]);
gl.uniform1d(stage_ptr->uniform_structure_arrays[0].uniform_location_double,
stage_ptr->uniform_structure_arrays[0].uniform_double);
gl.uniform1d(stage_ptr->uniform_structure_arrays[1].uniform_location_double,
stage_ptr->uniform_structure_arrays[1].uniform_double);
GLU_EXPECT_NO_ERROR(gl.getError(), "gluniform1d() call(s) failed.");
gl.uniform2dv(stage_ptr->uniforms.uniform_location_dvec2, 1 /* count */, stage_ptr->uniforms.uniform_dvec2);
gl.uniform2dv(stage_ptr->uniforms.uniform_location_dvec2_arr[0], 1 /* count */,
stage_ptr->uniforms.uniform_dvec2_arr + 0);
gl.uniform2dv(stage_ptr->uniforms.uniform_location_dvec2_arr[1], 1 /* count */,
stage_ptr->uniforms.uniform_dvec2_arr + 2);
gl.uniform2dv(stage_ptr->uniform_structure_arrays[0].uniform_location_dvec2, 1 /* count */,
stage_ptr->uniform_structure_arrays[0].uniform_dvec2);
gl.uniform2dv(stage_ptr->uniform_structure_arrays[1].uniform_location_dvec2, 1 /* count */,
stage_ptr->uniform_structure_arrays[1].uniform_dvec2);
GLU_EXPECT_NO_ERROR(gl.getError(), "gluniform2dv() call(s) failed.");
gl.uniform3dv(stage_ptr->uniforms.uniform_location_dvec3, 1 /* count */, stage_ptr->uniforms.uniform_dvec3);
gl.uniform3dv(stage_ptr->uniforms.uniform_location_dvec3_arr[0], 1 /* count */,
stage_ptr->uniforms.uniform_dvec3_arr + 0);
gl.uniform3dv(stage_ptr->uniforms.uniform_location_dvec3_arr[1], 1 /* count */,
stage_ptr->uniforms.uniform_dvec3_arr + 3);
gl.uniform3dv(stage_ptr->uniform_structure_arrays[0].uniform_location_dvec3, 1 /* count */,
stage_ptr->uniform_structure_arrays[0].uniform_dvec3);
gl.uniform3dv(stage_ptr->uniform_structure_arrays[1].uniform_location_dvec3, 1 /* count */,
stage_ptr->uniform_structure_arrays[1].uniform_dvec3);
GLU_EXPECT_NO_ERROR(gl.getError(), "gluniform3dv() call(s) failed.");
gl.uniform4dv(stage_ptr->uniforms.uniform_location_dvec4, 1 /* count */, stage_ptr->uniforms.uniform_dvec4);
gl.uniform4dv(stage_ptr->uniforms.uniform_location_dvec4_arr[0], 1 /* count */,
stage_ptr->uniforms.uniform_dvec4_arr + 0);
gl.uniform4dv(stage_ptr->uniforms.uniform_location_dvec4_arr[1], 1 /* count */,
stage_ptr->uniforms.uniform_dvec4_arr + 4);
gl.uniform4dv(stage_ptr->uniform_structure_arrays[0].uniform_location_dvec4, 1 /* count */,
stage_ptr->uniform_structure_arrays[0].uniform_dvec4);
gl.uniform4dv(stage_ptr->uniform_structure_arrays[1].uniform_location_dvec4, 1 /* count */,
stage_ptr->uniform_structure_arrays[1].uniform_dvec4);
GLU_EXPECT_NO_ERROR(gl.getError(), "gluniform4dv() call(s) failed.");
} /* for (all shader stages) */
} /* for (both program objects) */
}
/** Executes test iteration.
*
* @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
*/
tcu::TestNode::IterateResult GPUShaderFP64Test4::iterate()
{
/* This test does not verify GL_ARB_gpu_shader_fp64 support on purpose */
/* Initialize all objects required to run the test */
initTest();
/* Verify the implementation reports correct values for all stages we've configured */
m_has_test_passed &= verifyUniformValues();
/* Is this also the case when "program interface query" mechanism is used? */
if (m_context.getContextInfo().isExtensionSupported("GL_ARB_program_interface_query"))
{
m_has_test_passed &= verifyProgramInterfaceQuerySupport();
}
/* We're done */
if (m_has_test_passed)
{
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
}
else
{
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
}
return STOP;
}
/** Verifies that:
*
* a) glGetProgramResourceIndex()
* b) glGetProgramResourceiv()
* c) glGetProgramResourceName()
*
* functions return correct values for double-precision uniforms.
*
* @return true if the verification was passed, false otherwise.
*/
bool GPUShaderFP64Test4::verifyProgramInterfaceQuerySupport()
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
bool result = true;
/* Iterate through all programs */
const char* cs_prefixes[] = { "cs_" };
_stage_data* cs_stages[] = { &m_data_cs };
const char* noncs_prefixes[] = { "fs_", "gs_", "tc_", "te_", "vs_" };
_stage_data* noncs_stages[] = { &m_data_fs, &m_data_gs, &m_data_tc, &m_data_te, &m_data_vs };
const unsigned int n_cs_stages = sizeof(cs_stages) / sizeof(cs_stages[0]);
const unsigned int n_noncs_stages = sizeof(noncs_stages) / sizeof(noncs_stages[0]);
const glw::GLuint programs[] = { m_po_cs_id, m_po_noncs_id };
const unsigned int n_programs = sizeof(programs) / sizeof(programs[0]);
for (unsigned int n_program = 0; n_program < n_programs; ++n_program)
{
glw::GLuint po_id = programs[n_program];
unsigned int n_stages = 0;
const char** stage_prefixes = DE_NULL;
_stage_data** stage_data = DE_NULL;
if (po_id == m_po_cs_id)
{
n_stages = n_cs_stages;
stage_data = cs_stages;
stage_prefixes = cs_prefixes;
}
else
{
n_stages = n_noncs_stages;
stage_data = noncs_stages;
stage_prefixes = noncs_prefixes;
}
/* Skip compute shader program if not supported */
if (0 == po_id)
{
continue;
}
/* Determine maximum uniform name length */
glw::GLint max_uniform_name_length = 0;
gl.getProgramInterfaceiv(po_id, GL_UNIFORM, GL_MAX_NAME_LENGTH, &max_uniform_name_length);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramInterfaceiv() call failed.");
/* Allocate a buffer we will use to hold uniform names */
m_uniform_name_buffer = new char[max_uniform_name_length];
for (unsigned int n_stage = 0; n_stage < n_stages; ++n_stage)
{
/* Iterate through all uniforms */
_stage_data* stage_ptr = stage_data[n_stage];
const char* stage_prefix = stage_prefixes[n_stage];
/* Construct an array that will be used to run the test in an automated manner */
_program_interface_query_test_item uniforms[] = {
/* array size */ /* name */ /* type */ /* location */
{ 1, "double", GL_DOUBLE, stage_ptr->uniforms.uniform_location_double },
{ 2, "double_arr[0]", GL_DOUBLE, stage_ptr->uniforms.uniform_location_double_arr[0] },
{ 1, "dvec2", GL_DOUBLE_VEC2, stage_ptr->uniforms.uniform_location_dvec2 },
{ 2, "dvec2_arr[0]", GL_DOUBLE_VEC2, stage_ptr->uniforms.uniform_location_dvec2_arr[0] },
{ 1, "dvec3", GL_DOUBLE_VEC3, stage_ptr->uniforms.uniform_location_dvec3 },
{ 2, "dvec3_arr[0]", GL_DOUBLE_VEC3, stage_ptr->uniforms.uniform_location_dvec3_arr[0] },
{ 1, "dvec4", GL_DOUBLE_VEC4, stage_ptr->uniforms.uniform_location_dvec4 },
{ 2, "dvec4_arr[0]", GL_DOUBLE_VEC4, stage_ptr->uniforms.uniform_location_dvec4_arr[0] },
{ 1, "array[0].struct_double", GL_DOUBLE,
stage_ptr->uniform_structure_arrays->uniform_location_double },
{ 1, "array[0].struct_dvec2", GL_DOUBLE_VEC2,
stage_ptr->uniform_structure_arrays->uniform_location_dvec2 },
{ 1, "array[0].struct_dvec3", GL_DOUBLE_VEC3,
stage_ptr->uniform_structure_arrays->uniform_location_dvec3 },
{ 1, "array[0].struct_dvec4", GL_DOUBLE_VEC4,
stage_ptr->uniform_structure_arrays->uniform_location_dvec4 },
{ 1, "array[1].struct_double", GL_DOUBLE,
stage_ptr->uniform_structure_arrays->uniform_location_double },
{ 1, "array[1].struct_dvec2", GL_DOUBLE_VEC2,
stage_ptr->uniform_structure_arrays->uniform_location_dvec2 },
{ 1, "array[1].struct_dvec3", GL_DOUBLE_VEC3,
stage_ptr->uniform_structure_arrays->uniform_location_dvec3 },
{ 1, "array[1].struct_dvec4", GL_DOUBLE_VEC4,
stage_ptr->uniform_structure_arrays->uniform_location_dvec4 },
};
const unsigned int n_uniforms = sizeof(uniforms) / sizeof(uniforms[0]);
/* Prefix the names with stage-specific string */
for (unsigned int n_uniform = 0; n_uniform < n_uniforms; ++n_uniform)
{
_program_interface_query_test_item& current_item = uniforms[n_uniform];
current_item.name = std::string(stage_prefix) + current_item.name;
} /* for (all uniform descriptors) */
const glw::GLenum properties[] = { GL_ARRAY_SIZE, GL_TYPE };
const unsigned int n_properties = sizeof(properties) / sizeof(properties[0]);
for (unsigned int n_uniform = 0; n_uniform < n_uniforms; ++n_uniform)
{
_program_interface_query_test_item& current_item = uniforms[n_uniform];
glw::GLint n_written_items = 0;
glw::GLint retrieved_array_size = 0;
glw::GLint retrieved_name_length = 0;
glw::GLenum retrieved_type = GL_NONE;
glw::GLint temp_buffer[2] = { 0, GL_NONE };
/* Retrieve index of the iteration-specific uniform */
glw::GLuint resource_index = gl.getProgramResourceIndex(po_id, GL_UNIFORM, current_item.name.c_str());
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramResourceIndex() call failed.");
/* Make sure glGetProgramResourceName() returns correct values */
memset(m_uniform_name_buffer, 0, max_uniform_name_length);
gl.getProgramResourceName(po_id, GL_UNIFORM, /* interface */
resource_index, max_uniform_name_length, &retrieved_name_length,
m_uniform_name_buffer);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramResourceName() call failed.");
if (current_item.name.length() != (glw::GLuint)retrieved_name_length ||
memcmp(m_uniform_name_buffer, current_item.name.c_str(), retrieved_name_length) != 0)
{
m_testCtx.getLog() << tcu::TestLog::Message << "Invalid uniform name was reported at index ["
<< resource_index << "]"
": expected:["
<< current_item.name << "]"
", reported:["
<< m_uniform_name_buffer << "]" << tcu::TestLog::EndMessage;
result = false;
continue;
}
/* Make sure glGetProgramResourceiv() returns correct values for GL_TYPE and GL_ARRAY_SIZE queries */
gl.getProgramResourceiv(po_id, GL_UNIFORM, /* interface */
resource_index, n_properties, properties,
sizeof(temp_buffer) / sizeof(temp_buffer[0]), &n_written_items, temp_buffer);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramResourceiv() call failed.");
if (n_written_items != n_properties)
{
TCU_FAIL("Invalid amount of items were reported by glGetProgramResourceiv() call.");
}
/* For clarity, copy the retrieved values to separate variables */
retrieved_array_size = temp_buffer[0];
retrieved_type = temp_buffer[1];
/* Verify the values */
if (retrieved_array_size != current_item.expected_array_size)
{
m_testCtx.getLog() << tcu::TestLog::Message << "Invalid array size reported for uniform ["
<< current_item.name << "]"
<< ": expected:[" << current_item.expected_array_size << "]"
", reported:["
<< retrieved_array_size << "]" << tcu::TestLog::EndMessage;
result = false;
}
if (retrieved_type != current_item.expected_type)
{
m_testCtx.getLog() << tcu::TestLog::Message << "Invalid type reported for uniform ["
<< current_item.name << "]"
<< ": expected:[" << current_item.expected_type << "]"
", reported:["
<< retrieved_type << "]" << tcu::TestLog::EndMessage;
result = false;
}
} /* for (all uniforms) */
} /* for (all shader stages) */
/* We're now OK to release the buffer we used to hold uniform names for
* the program */
if (m_uniform_name_buffer != DE_NULL)
{
delete[] m_uniform_name_buffer;
m_uniform_name_buffer = DE_NULL;
}
} /* for (both program objects) */
return result;
}
/** Verifies glGetUniform*() calls return correct values assigned to
* double-precision uniforms.
*
* @return true if all values reported by OpenGL were found to be correct,
* false otherwise.
**/
bool GPUShaderFP64Test4::verifyUniformValues()
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
bool result = true;
/* Iterate through all programs */
_stage_data* cs_stages[] = { &m_data_cs };
_stage_data* noncs_stages[] = { &m_data_fs, &m_data_gs, &m_data_tc, &m_data_te, &m_data_vs };
const unsigned int n_cs_stages = sizeof(cs_stages) / sizeof(cs_stages[0]);
const unsigned int n_noncs_stages = sizeof(noncs_stages) / sizeof(noncs_stages[0]);
const glw::GLuint programs[] = {
m_po_noncs_id, m_po_cs_id,
};
const unsigned int n_programs = sizeof(programs) / sizeof(programs[0]);
/* Set up rounding for the tests */
deSetRoundingMode(DE_ROUNDINGMODE_TO_NEAREST_EVEN);
for (unsigned int n_program = 0; n_program < n_programs; ++n_program)
{
glw::GLuint po_id = programs[n_program];
unsigned int n_stages = 0;
_stage_data** stage_data = DE_NULL;
if (po_id == m_po_cs_id)
{
n_stages = n_cs_stages;
stage_data = cs_stages;
}
else
{
n_stages = n_noncs_stages;
stage_data = noncs_stages;
}
/* Skip compute shader program if not supported */
if (0 == po_id)
{
continue;
}
for (unsigned int n_stage = 0; n_stage < n_stages; ++n_stage)
{
/* Iterate through all uniforms */
_stage_data* stage_ptr = stage_data[n_stage];
/* Set up arrays that we will guide the automated testing */
const uniform_value_pair double_uniforms[] = {
uniform_value_pair(stage_ptr->uniforms.uniform_location_double, &stage_ptr->uniforms.uniform_double),
uniform_value_pair(stage_ptr->uniforms.uniform_location_double_arr[0],
stage_ptr->uniforms.uniform_double_arr + 0),
uniform_value_pair(stage_ptr->uniforms.uniform_location_double_arr[1],
stage_ptr->uniforms.uniform_double_arr + 1),
uniform_value_pair(stage_ptr->uniform_structure_arrays[0].uniform_location_double,
&stage_ptr->uniform_structure_arrays[0].uniform_double),
uniform_value_pair(stage_ptr->uniform_structure_arrays[1].uniform_location_double,
&stage_ptr->uniform_structure_arrays[1].uniform_double)
};
const uniform_value_pair dvec2_uniforms[] = {
uniform_value_pair(stage_ptr->uniforms.uniform_location_dvec2, stage_ptr->uniforms.uniform_dvec2),
uniform_value_pair(stage_ptr->uniforms.uniform_location_dvec2_arr[0],
stage_ptr->uniforms.uniform_dvec2_arr + 0),
uniform_value_pair(stage_ptr->uniforms.uniform_location_dvec2_arr[1],
stage_ptr->uniforms.uniform_dvec2_arr + 2),
uniform_value_pair(stage_ptr->uniform_structure_arrays[0].uniform_location_dvec2,
stage_ptr->uniform_structure_arrays[0].uniform_dvec2),
uniform_value_pair(stage_ptr->uniform_structure_arrays[1].uniform_location_dvec2,
stage_ptr->uniform_structure_arrays[1].uniform_dvec2)
};
const uniform_value_pair dvec3_uniforms[] = {
uniform_value_pair(stage_ptr->uniforms.uniform_location_dvec3, stage_ptr->uniforms.uniform_dvec3),
uniform_value_pair(stage_ptr->uniforms.uniform_location_dvec3_arr[0],
stage_ptr->uniforms.uniform_dvec3_arr + 0),
uniform_value_pair(stage_ptr->uniforms.uniform_location_dvec3_arr[1],
stage_ptr->uniforms.uniform_dvec3_arr + 3),
uniform_value_pair(stage_ptr->uniform_structure_arrays[0].uniform_location_dvec3,
stage_ptr->uniform_structure_arrays[0].uniform_dvec3),
uniform_value_pair(stage_ptr->uniform_structure_arrays[1].uniform_location_dvec3,
stage_ptr->uniform_structure_arrays[1].uniform_dvec3)
};
const uniform_value_pair dvec4_uniforms[] = {
uniform_value_pair(stage_ptr->uniforms.uniform_location_dvec4, stage_ptr->uniforms.uniform_dvec4),
uniform_value_pair(stage_ptr->uniforms.uniform_location_dvec4_arr[0],
stage_ptr->uniforms.uniform_dvec4_arr + 0),
uniform_value_pair(stage_ptr->uniforms.uniform_location_dvec4_arr[1],
stage_ptr->uniforms.uniform_dvec4_arr + 4),
uniform_value_pair(stage_ptr->uniform_structure_arrays[0].uniform_location_dvec4,
stage_ptr->uniform_structure_arrays[0].uniform_dvec4),
uniform_value_pair(stage_ptr->uniform_structure_arrays[1].uniform_location_dvec4,
stage_ptr->uniform_structure_arrays[1].uniform_dvec4)
};
/* Iterate over all uniforms and verify the values reported by the API */
double returned_double_data[4];
float returned_float_data[4];
int returned_int_data[4];
unsigned int returned_uint_data[4];
for (unsigned int n_type = 0; n_type < 4 /* double/dvec2/dvec3/dvec4 */; ++n_type)
{
const uniform_value_pair* current_uv_pairs = NULL;
const unsigned int n_components_used = n_type + 1; /* n_type=0: double, n_type=1: dvec2, etc.. */
unsigned int n_pairs = 0;
switch (n_type)
{
case 0: /* double */
{
current_uv_pairs = double_uniforms;
n_pairs = sizeof(double_uniforms) / sizeof(double_uniforms[0]);
break;
}
case 1: /* dvec2 */
{
current_uv_pairs = dvec2_uniforms;
n_pairs = sizeof(dvec2_uniforms) / sizeof(dvec2_uniforms[0]);
break;
}
case 2: /* dvec3 */
{
current_uv_pairs = dvec3_uniforms;
n_pairs = sizeof(dvec3_uniforms) / sizeof(dvec3_uniforms[0]);
break;
}
case 3: /* dvec4 */
{
current_uv_pairs = dvec4_uniforms;
n_pairs = sizeof(dvec4_uniforms) / sizeof(dvec4_uniforms[0]);
break;
}
default:
{
TCU_FAIL("Invalid type index requested");
}
} /* switch (n_type) */
for (unsigned int n_pair = 0; n_pair < n_pairs; ++n_pair)
{
const uniform_value_pair& current_uv_pair = current_uv_pairs[n_pair];
glw::GLint uniform_location = current_uv_pair.first;
const double* uniform_value = current_uv_pair.second;
/* Retrieve the values from the GL implementation*/
gl.getUniformdv(po_id, uniform_location, returned_double_data);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetUniformdv() call failed.");
gl.getUniformfv(po_id, uniform_location, returned_float_data);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetUniformfv() call failed.");
gl.getUniformiv(po_id, uniform_location, returned_int_data);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetUniformiv() call failed.");
gl.getUniformuiv(po_id, uniform_location, returned_uint_data);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetUniformuiv() call failed.");
/* Make sure the values reported match the reference values */
bool can_continue = true;
const float epsilon = 1e-5f;
for (unsigned int n_component = 0; n_component < n_components_used && can_continue; ++n_component)
{
if (de::abs(returned_double_data[n_component] - uniform_value[n_component]) > epsilon)
{
m_testCtx.getLog()
<< tcu::TestLog::Message
<< "Invalid uniform value reported by glGetUniformdv() for uniform location ["
<< uniform_location << "]"
" and component ["
<< n_component << "]"
": retrieved:["
<< returned_double_data[n_component] << "]"
", expected:["
<< uniform_value[n_component] << "]" << tcu::TestLog::EndMessage;
result = false;
}
if (de::abs(returned_float_data[n_component] - uniform_value[n_component]) > epsilon)
{
m_testCtx.getLog()
<< tcu::TestLog::Message
<< "Invalid uniform value reported by glGetUniformfv() for uniform location ["
<< uniform_location << "]"
" and component ["
<< n_component << "]"
": retrieved:["
<< returned_float_data[n_component] << "]"
", expected:["
<< uniform_value[n_component] << "]" << tcu::TestLog::EndMessage;
result = false;
}
/* ints */
int rounded_uniform_value_sint = (int)(deFloatRound((float)uniform_value[n_component]));
unsigned int rounded_uniform_value_uint =
(unsigned int)(uniform_value[n_component] > 0.0) ?
((unsigned int)deFloatRound((float)uniform_value[n_component])) :
0;
if (returned_int_data[n_component] != rounded_uniform_value_sint)
{
m_testCtx.getLog()
<< tcu::TestLog::Message
<< "Invalid uniform value reported by glGetUniformiv() for uniform location ["
<< uniform_location << "]"
" and component ["
<< n_component << "]"
": retrieved:["
<< returned_int_data[n_component] << "]"
", expected:["
<< rounded_uniform_value_sint << "]" << tcu::TestLog::EndMessage;
result = false;
}
if (returned_uint_data[n_component] != rounded_uniform_value_uint)
{
m_testCtx.getLog()
<< tcu::TestLog::Message
<< "Invalid uniform value reported by glGetUniformuiv() for uniform location ["
<< uniform_location << "]"
" and component ["
<< n_component << "]"
": retrieved:["
<< returned_uint_data[n_component] << "]"
", expected:["
<< rounded_uniform_value_uint << "]" << tcu::TestLog::EndMessage;
result = false;
}
} /* for (all components) */
} /* for (all uniform+value pairs) */
} /* for (all 4 uniform types) */
} /* for (all shader stages) */
} /* for (both program objects) */
/* All done! */
return result;
}
/** Constructor
*
* @param context Rendering context.
*/
GPUShaderFP64Test5::GPUShaderFP64Test5(deqp::Context& context)
: TestCase(context, "conversions", "Verifies explicit and implicit casts involving double-precision"
" floating-point variables work correctly")
, m_base_value_bo_data(DE_NULL)
, m_base_value_bo_id(0)
, m_has_test_passed(true)
, m_po_base_value_attribute_location(-1)
, m_po_id(0)
, m_vao_id(0)
, m_vs_id(0)
, m_xfb_bo_id(0)
, m_xfb_bo_size(0)
{
/* Set up base value array (as per test spec) */
m_base_values[0] = -25.12065f;
m_base_values[1] = 0.0f;
m_base_values[2] = 0.001f;
m_base_values[3] = 1.0f;
m_base_values[4] = 256.78901f;
/* Set up swizzle matrix */
m_swizzle_matrix[0][0] = SWIZZLE_TYPE_NONE;
m_swizzle_matrix[0][1] = SWIZZLE_TYPE_Y;
m_swizzle_matrix[0][2] = SWIZZLE_TYPE_Z;
m_swizzle_matrix[0][3] = SWIZZLE_TYPE_W;
m_swizzle_matrix[1][0] = SWIZZLE_TYPE_NONE;
m_swizzle_matrix[1][1] = SWIZZLE_TYPE_YX;
m_swizzle_matrix[1][2] = SWIZZLE_TYPE_ZY;
m_swizzle_matrix[1][3] = SWIZZLE_TYPE_WX;
m_swizzle_matrix[2][0] = SWIZZLE_TYPE_NONE;
m_swizzle_matrix[2][1] = SWIZZLE_TYPE_YXX;
m_swizzle_matrix[2][2] = SWIZZLE_TYPE_XZY;
m_swizzle_matrix[2][3] = SWIZZLE_TYPE_XWZY;
m_swizzle_matrix[3][0] = SWIZZLE_TYPE_NONE;
m_swizzle_matrix[3][1] = SWIZZLE_TYPE_YXXY;
m_swizzle_matrix[3][2] = SWIZZLE_TYPE_XZXY;
m_swizzle_matrix[3][3] = SWIZZLE_TYPE_XZYW;
}
void GPUShaderFP64Test5::deinit()
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
if (m_base_value_bo_data != DE_NULL)
{
delete[] m_base_value_bo_data;
m_base_value_bo_data = DE_NULL;
}
if (m_base_value_bo_id != 0)
{
gl.deleteBuffers(1, &m_base_value_bo_id);
m_base_value_bo_id = 0;
}
if (m_vao_id != 0)
{
gl.deleteVertexArrays(1, &m_vao_id);
m_vao_id = 0;
}
if (m_xfb_bo_id != 0)
{
gl.deleteBuffers(1, &m_xfb_bo_id);
m_xfb_bo_id = 0;
}
/* TCU_FAIL will skip the per sub test iteration de-initialization, we need to
* take care of it here
*/
deinitInteration();
}
/** Deinitializes all buffers and GL objects that may have been generated
* during test execution.
**/
void GPUShaderFP64Test5::deinitInteration()
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
if (m_po_id != 0)
{
gl.deleteProgram(m_po_id);
m_po_id = 0;
}
if (m_vs_id != 0)
{
gl.deleteShader(m_vs_id);
m_vs_id = 0;
}
}
/** Executes a single test case iteration using user-provided test case descriptor.
*
* This function may throw a TestError exception if GL implementation misbehaves.
*
* @param test_case Test case descriptor to use.
*
* @return true if the values returned by GL implementation were found to be valid,
* false otherwise.
**/
bool GPUShaderFP64Test5::executeIteration(const _test_case& test_case)
{
bool result = true;
/* Convert the base values array to the type of input attribute we'll be using
* for the iteration.
*/
Utils::_variable_type base_value_type = Utils::getBaseVariableType(test_case.src_type);
if (base_value_type == Utils::VARIABLE_TYPE_BOOL)
{
/* bools are actually represented by ints, since bool varyings are not allowed */
base_value_type = Utils::VARIABLE_TYPE_INT;
}
const unsigned int base_value_component_size = Utils::getBaseVariableTypeComponentSize(base_value_type);
const unsigned int n_base_values = sizeof(m_base_values) / sizeof(m_base_values[0]);
m_base_value_bo_data = new unsigned char[base_value_component_size * n_base_values];
unsigned char* base_value_traveller_ptr = m_base_value_bo_data;
for (unsigned int n_base_value = 0; n_base_value < n_base_values; ++n_base_value)
{
switch (base_value_type)
{
case Utils::VARIABLE_TYPE_DOUBLE:
*((double*)base_value_traveller_ptr) = (double)m_base_values[n_base_value];
break;
case Utils::VARIABLE_TYPE_FLOAT:
*((float*)base_value_traveller_ptr) = (float)m_base_values[n_base_value];
break;
case Utils::VARIABLE_TYPE_INT:
*((int*)base_value_traveller_ptr) = (int)m_base_values[n_base_value];
break;
case Utils::VARIABLE_TYPE_UINT:
*((unsigned int*)base_value_traveller_ptr) = (unsigned int)m_base_values[n_base_value];
break;
default:
{
TCU_FAIL("Unrecognized base value type");
}
}
base_value_traveller_ptr += base_value_component_size;
} /* for (all base values) */
/* Update buffer object storage with the data we've just finished preparing. */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.bindBuffer(GL_ARRAY_BUFFER, m_base_value_bo_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed.");
gl.bufferSubData(GL_ARRAY_BUFFER, 0 /* offset */, base_value_component_size * n_base_values, m_base_value_bo_data);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferSubData() call failed.");
/* Configure vertex attribute array corresponding to 'base_value' attribute, so that the
* new data is interpreted correctly.
*/
if (base_value_type == Utils::VARIABLE_TYPE_FLOAT)
{
gl.vertexAttribPointer(m_po_base_value_attribute_location, 1, /* size */
Utils::getGLDataTypeOfBaseVariableType(base_value_type), GL_FALSE, /* normalized */
0, /* stride */
DE_NULL); /* pointer */
GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribPointer() call failed.");
}
else if (base_value_type == Utils::VARIABLE_TYPE_INT || base_value_type == Utils::VARIABLE_TYPE_UINT)
{
gl.vertexAttribIPointer(m_po_base_value_attribute_location, 1, /* size */
Utils::getGLDataTypeOfBaseVariableType(base_value_type), 0, /* stride */
DE_NULL); /* pointer */
GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribIPointer() call failed.");
}
else
{
DE_ASSERT(base_value_type == Utils::VARIABLE_TYPE_DOUBLE);
gl.vertexAttribLPointer(m_po_base_value_attribute_location, 1, /* size */
GL_DOUBLE, 0, /* stride */
DE_NULL); /* pointer */
GLU_EXPECT_NO_ERROR(gl.getError(), "glVertxAttribLPointer() call failed.");
}
gl.enableVertexAttribArray(m_po_base_value_attribute_location);
GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray() call failed.");
/* Execute the draw call */
gl.useProgram(m_po_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
gl.beginTransformFeedback(GL_POINTS);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() call failed.");
{
gl.drawArrays(GL_POINTS, 0 /* first */, n_base_values);
GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed.");
}
gl.endTransformFeedback();
GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() call failed.");
/* Map the XFB buffer object into process space */
void* xfb_data_ptr = gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBuffer() call failed.");
DE_ASSERT(xfb_data_ptr != NULL);
/* Verify the data */
result &= verifyXFBData((const unsigned char*)xfb_data_ptr, test_case);
/* Unmap the XFB BO */
gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed.");
/** Good to release the data buffer at this point */
if (m_base_value_bo_data != DE_NULL)
{
delete[] m_base_value_bo_data;
m_base_value_bo_data = DE_NULL;
}
/* All done */
return result;
}
/** Returns properties of a swizzle operator described by @param type swizzle type.
*
* @param out_swizzle_string Deref will be used to store a GLSL literal
* corresponding to the specific swizzle operator.
* Must not be NULL.
* @param out_n_components Deref will be used to store the amount of components
* used by the operator. Must not be NULL.
* @param out_component_order Deref will be used to store up to 4 integer values,
* corresponding to component indices described by the
* operator for a particular position. Must not be NULL.
**/
void GPUShaderFP64Test5::getSwizzleTypeProperties(_swizzle_type type, std::string* out_swizzle_string,
unsigned int* out_n_components, unsigned int* out_component_order)
{
unsigned int result_component_order[4] = { 0 };
unsigned int result_n_components = 0;
std::string result_swizzle_string;
switch (type)
{
case SWIZZLE_TYPE_NONE:
{
result_swizzle_string = "";
result_n_components = 0;
break;
}
case SWIZZLE_TYPE_XWZY:
{
result_swizzle_string = "xwzy";
result_n_components = 4;
result_component_order[0] = 0;
result_component_order[1] = 3;
result_component_order[2] = 2;
result_component_order[3] = 1;
break;
}
case SWIZZLE_TYPE_XZXY:
{
result_swizzle_string = "xzxy";
result_n_components = 4;
result_component_order[0] = 0;
result_component_order[1] = 2;
result_component_order[2] = 0;
result_component_order[3] = 1;
break;
}
case SWIZZLE_TYPE_XZY:
{
result_swizzle_string = "xzy";
result_n_components = 3;
result_component_order[0] = 0;
result_component_order[1] = 2;
result_component_order[2] = 1;
break;
}
case SWIZZLE_TYPE_XZYW:
{
result_swizzle_string = "xzyw";
result_n_components = 4;
result_component_order[0] = 0;
result_component_order[1] = 2;
result_component_order[2] = 1;
result_component_order[3] = 3;
break;
}
case SWIZZLE_TYPE_Y:
{
result_swizzle_string = "y";
result_n_components = 1;
result_component_order[0] = 1;
break;
}
case SWIZZLE_TYPE_YX:
{
result_swizzle_string = "yx";
result_n_components = 2;
result_component_order[0] = 1;
result_component_order[1] = 0;
break;
}
case SWIZZLE_TYPE_YXX:
{
result_swizzle_string = "yxx";
result_n_components = 3;
result_component_order[0] = 1;
result_component_order[1] = 0;
result_component_order[2] = 0;
break;
}
case SWIZZLE_TYPE_YXXY:
{
result_swizzle_string = "yxxy";
result_n_components = 4;
result_component_order[0] = 1;
result_component_order[1] = 0;
result_component_order[2] = 0;
result_component_order[3] = 1;
break;
}
case SWIZZLE_TYPE_Z:
{
result_swizzle_string = "z";
result_n_components = 1;
result_component_order[0] = 2;
break;
}
case SWIZZLE_TYPE_ZY:
{
result_swizzle_string = "zy";
result_n_components = 2;
result_component_order[0] = 2;
result_component_order[1] = 1;
break;
}
case SWIZZLE_TYPE_W:
{
result_swizzle_string = "w";
result_n_components = 1;
result_component_order[0] = 3;
break;
}
case SWIZZLE_TYPE_WX:
{
result_swizzle_string = "wx";
result_n_components = 2;
result_component_order[0] = 3;
result_component_order[1] = 0;
break;
}
default:
{
TCU_FAIL("Unrecognized swizzle type");
}
} /* switch (type) */
if (out_swizzle_string != DE_NULL)
{
*out_swizzle_string = result_swizzle_string;
}
if (out_n_components != DE_NULL)
{
*out_n_components = result_n_components;
}
if (out_component_order != DE_NULL)
{
memcpy(out_component_order, result_component_order, sizeof(unsigned int) * result_n_components);
}
}
/** Returns body of a vertex shader that should be used for particular test case,
* given user-specified test case descriptor.
*
* @param test_case Descriptor to use for the query.
*
* @return Requested data.
**/
std::string GPUShaderFP64Test5::getVertexShaderBody(const _test_case& test_case)
{
std::stringstream result;
const std::string base_type_string = Utils::getVariableTypeString(Utils::getBaseVariableType(test_case.src_type));
const std::string dst_type_string = Utils::getVariableTypeString(test_case.dst_type);
const unsigned int n_dst_components = Utils::getNumberOfComponentsForVariableType(test_case.dst_type);
const unsigned int n_src_components = Utils::getNumberOfComponentsForVariableType(test_case.src_type);
const std::string src_type_string = Utils::getVariableTypeString(test_case.src_type);
/* Add version preamble */
result << "#version 420\n"
"\n";
/* Declare output variables. Note that boolean output variables are not supported, so we need
* to handle that special case correctly */
if (test_case.dst_type == Utils::VARIABLE_TYPE_BOOL)
{
result << "out int result;\n";
}
else
{
result << "out " << dst_type_string << " result;\n";
}
/* Declare input variables. Handle the bool case exclusively. */
if (test_case.src_type == Utils::VARIABLE_TYPE_BOOL)
{
/* Use ints for bools. We will cast them to bool in the code later. */
result << "in int base_value;\n";
}
else
{
result << "in " << base_type_string << " base_value;\n";
}
/* Declare main() and construct the value we will be casting from.
*
* Note: Addition operations on bool values cause an implicit conversion to int
* which is not allowed. Hence, we skip these operations for this special
* case.
*/
result << "void main()\n"
"{\n"
<< src_type_string << " lside_value = ";
if (test_case.src_type == Utils::VARIABLE_TYPE_BOOL)
{
result << src_type_string << "(0 != ";
}
else
{
result << src_type_string << "(";
}
if (test_case.src_type != Utils::VARIABLE_TYPE_BOOL)
{
for (unsigned int n_component = 0; n_component < n_src_components; ++n_component)
{
result << "base_value + " << n_component;
if (n_component != (n_src_components - 1))
{
result << ", ";
}
} /* for (all components) */
}
else
{
DE_ASSERT(n_src_components == 1);
result << "base_value";
}
result << ");\n";
/* Perform the casting operation. Add swizzle operator if possible. */
if (test_case.dst_type == Utils::VARIABLE_TYPE_BOOL)
{
/* Handle the bool case exclusively */
if (test_case.type == TEST_CASE_TYPE_EXPLICIT)
{
result << "result = (bool(lside_value) == false) ? 0 : 1";
}
else
{
result << "result = (lside_value == false) ? 0 : 1";
}
}
else
{
if (test_case.type == TEST_CASE_TYPE_EXPLICIT)
{
result << "result = " << dst_type_string << "(lside_value)";
}
else
{
result << "result = lside_value";
}
}
if (n_src_components > 1 && !Utils::isMatrixVariableType(test_case.src_type))
{
/* Add a swizzle operator */
DE_ASSERT(n_dst_components > 0 && n_dst_components <= 4);
DE_ASSERT(n_src_components > 0 && n_src_components <= 4);
unsigned int swizzle_component_order[4] = { 0 };
unsigned int swizzle_n_components = 0;
_swizzle_type swizzle_operator = m_swizzle_matrix[n_dst_components - 1][n_src_components - 1];
std::string swizzle_string;
getSwizzleTypeProperties(swizzle_operator, &swizzle_string, &swizzle_n_components, swizzle_component_order);
if (swizzle_n_components > 0)
{
result << "." << swizzle_string;
}
}
/* Close the shader implementation. */
result << ";\n"
"}\n";
return result.str();
}
/** Initializes program & shader objects needed to run the iteration, given
* user-specified test case descriptor.
*
* This function can throw a TestError exception if a GL error is detected
* during execution.
*
* @param test_case Descriptor to use for the iteration.
**/
void GPUShaderFP64Test5::initIteration(_test_case& test_case)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Create program & shader objects */
m_po_id = gl.createProgram();
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed.");
m_vs_id = gl.createShader(GL_VERTEX_SHADER);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed.");
/* Configure shader body */
std::string body = getVertexShaderBody(test_case);
const char* body_raw_ptr = body.c_str();
gl.shaderSource(m_vs_id, 1 /* count */, &body_raw_ptr, DE_NULL /* length */);
GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed.");
/* Store it in the test case descriptor for logging purposes */
test_case.shader_body = body;
/* Compile the shader */
glw::GLint compile_status = GL_FALSE;
gl.compileShader(m_vs_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed.");
gl.getShaderiv(m_vs_id, GL_COMPILE_STATUS, &compile_status);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed.");
if (compile_status != GL_TRUE)
{
TCU_FAIL("Shader compilation failed");
}
/* Attach the shader to the program obejct */
gl.attachShader(m_po_id, m_vs_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call failed.");
/* Configure XFB for the program object */
const char* xfb_varying_name = "result";
gl.transformFeedbackVaryings(m_po_id, 1 /* count */, &xfb_varying_name, GL_INTERLEAVED_ATTRIBS);
GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() call failed.");
/* Link the program object */
glw::GLint link_status = GL_FALSE;
gl.linkProgram(m_po_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed.");
gl.getProgramiv(m_po_id, GL_LINK_STATUS, &link_status);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed.");
if (link_status != GL_TRUE)
{
TCU_FAIL("Program linking failed");
}
/* Retrieve attribute locations */
m_po_base_value_attribute_location = gl.getAttribLocation(m_po_id, "base_value");
GLU_EXPECT_NO_ERROR(gl.getError(), "getAttribLocation() call failed.");
if (m_po_base_value_attribute_location == -1)
{
TCU_FAIL("'base_value' is considered an inactive attribute which is invalid.");
}
}
/** Initializes GL objects used by all test cases.
*
* This function may throw a TestError exception if GL implementation reports
* an error at any point.
**/
void GPUShaderFP64Test5::initTest()
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Generate buffer object IDs */
gl.genBuffers(1, &m_base_value_bo_id);
gl.genBuffers(1, &m_xfb_bo_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call(s) failed.");
/* Allocate buffer object storage for 'base_value' input attribute data. All iterations
* will never eat up more than 1 double (as per test spec) and we will be drawing
* as many points in a single draw call as there are defined in m_base_values array.
*/
const unsigned int n_base_values = sizeof(m_base_values) / sizeof(m_base_values[0]);
gl.bindBuffer(GL_ARRAY_BUFFER, m_base_value_bo_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed.");
gl.bufferData(GL_ARRAY_BUFFER, sizeof(double) * n_base_values, DE_NULL /* data */, GL_STATIC_DRAW);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call failed.");
/* Allocate buffer object storage for XFB data. For each iteratiom we will be using
* five base values. Each XFBed value can take up to 16 components (eg. mat4) and be
* of double type (eg. dmat4), so make sure a sufficient amount of space is requested.
*/
const unsigned int xfb_bo_size = sizeof(double) * 16 /* components */ * n_base_values;
gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_xfb_bo_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed.");
gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, m_xfb_bo_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() call failed.");
gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_bo_size, DE_NULL /* data */, GL_STATIC_DRAW);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call failed.");
/* Allocate a client-side buffer to hold the data we will be mapping from XFB BO */
m_xfb_bo_size = xfb_bo_size;
/* Generate a vertex array object we will need to use for the draw calls */
gl.genVertexArrays(1, &m_vao_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call failed.");
gl.bindVertexArray(m_vao_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed.");
}
/** Executes test iteration.
*
* @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
*/
tcu::TestNode::IterateResult GPUShaderFP64Test5::iterate()
{
/* Do not execute the test if GL_ARB_texture_view is not supported */
if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_gpu_shader_fp64"))
{
throw tcu::NotSupportedError("GL_ARB_gpu_shader_fp64 is not supported.");
}
if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_vertex_attrib_64bit"))
{
throw tcu::NotSupportedError("GL_ARB_vertex_attrib_64bit is not supported.");
}
/* Initialize GL objects needed to run the tests */
initTest();
/* Build iteration array to run the tests in an automated manner */
_test_case test_cases[] = {
/* test case type */ /* source type */ /* destination type */
{ TEST_CASE_TYPE_IMPLICIT, Utils::VARIABLE_TYPE_INT, Utils::VARIABLE_TYPE_DOUBLE, "" },
{ TEST_CASE_TYPE_IMPLICIT, Utils::VARIABLE_TYPE_IVEC2, Utils::VARIABLE_TYPE_DVEC2, "" },
{ TEST_CASE_TYPE_IMPLICIT, Utils::VARIABLE_TYPE_IVEC3, Utils::VARIABLE_TYPE_DVEC3, "" },
{ TEST_CASE_TYPE_IMPLICIT, Utils::VARIABLE_TYPE_IVEC4, Utils::VARIABLE_TYPE_DVEC4, "" },
{ TEST_CASE_TYPE_IMPLICIT, Utils::VARIABLE_TYPE_UINT, Utils::VARIABLE_TYPE_DOUBLE, "" },
{ TEST_CASE_TYPE_IMPLICIT, Utils::VARIABLE_TYPE_UVEC2, Utils::VARIABLE_TYPE_DVEC2, "" },
{ TEST_CASE_TYPE_IMPLICIT, Utils::VARIABLE_TYPE_UVEC3, Utils::VARIABLE_TYPE_DVEC3, "" },
{ TEST_CASE_TYPE_IMPLICIT, Utils::VARIABLE_TYPE_UVEC4, Utils::VARIABLE_TYPE_DVEC4, "" },
{ TEST_CASE_TYPE_IMPLICIT, Utils::VARIABLE_TYPE_FLOAT, Utils::VARIABLE_TYPE_DOUBLE, "" },
{ TEST_CASE_TYPE_IMPLICIT, Utils::VARIABLE_TYPE_VEC2, Utils::VARIABLE_TYPE_DVEC2, "" },
{ TEST_CASE_TYPE_IMPLICIT, Utils::VARIABLE_TYPE_VEC3, Utils::VARIABLE_TYPE_DVEC3, "" },
{ TEST_CASE_TYPE_IMPLICIT, Utils::VARIABLE_TYPE_VEC4, Utils::VARIABLE_TYPE_DVEC4, "" },
{ TEST_CASE_TYPE_IMPLICIT, Utils::VARIABLE_TYPE_MAT2, Utils::VARIABLE_TYPE_DMAT2, "" },
{ TEST_CASE_TYPE_IMPLICIT, Utils::VARIABLE_TYPE_MAT3, Utils::VARIABLE_TYPE_DMAT3, "" },
{ TEST_CASE_TYPE_IMPLICIT, Utils::VARIABLE_TYPE_MAT4, Utils::VARIABLE_TYPE_DMAT4, "" },
{ TEST_CASE_TYPE_IMPLICIT, Utils::VARIABLE_TYPE_MAT2X3, Utils::VARIABLE_TYPE_DMAT2X3, "" },
{ TEST_CASE_TYPE_IMPLICIT, Utils::VARIABLE_TYPE_MAT2X4, Utils::VARIABLE_TYPE_DMAT2X4, "" },
{ TEST_CASE_TYPE_IMPLICIT, Utils::VARIABLE_TYPE_MAT3X2, Utils::VARIABLE_TYPE_DMAT3X2, "" },
{ TEST_CASE_TYPE_IMPLICIT, Utils::VARIABLE_TYPE_MAT3X4, Utils::VARIABLE_TYPE_DMAT3X4, "" },
{ TEST_CASE_TYPE_IMPLICIT, Utils::VARIABLE_TYPE_MAT4X2, Utils::VARIABLE_TYPE_DMAT4X2, "" },
{ TEST_CASE_TYPE_IMPLICIT, Utils::VARIABLE_TYPE_MAT4X3, Utils::VARIABLE_TYPE_DMAT4X3, "" },
{ TEST_CASE_TYPE_EXPLICIT, Utils::VARIABLE_TYPE_INT, Utils::VARIABLE_TYPE_DOUBLE, "" },
{ TEST_CASE_TYPE_EXPLICIT, Utils::VARIABLE_TYPE_UINT, Utils::VARIABLE_TYPE_DOUBLE, "" },
{ TEST_CASE_TYPE_EXPLICIT, Utils::VARIABLE_TYPE_FLOAT, Utils::VARIABLE_TYPE_DOUBLE, "" },
{ TEST_CASE_TYPE_EXPLICIT, Utils::VARIABLE_TYPE_DOUBLE, Utils::VARIABLE_TYPE_INT, "" },
{ TEST_CASE_TYPE_EXPLICIT, Utils::VARIABLE_TYPE_DOUBLE, Utils::VARIABLE_TYPE_UINT, "" },
{ TEST_CASE_TYPE_EXPLICIT, Utils::VARIABLE_TYPE_DOUBLE, Utils::VARIABLE_TYPE_FLOAT, "" },
{ TEST_CASE_TYPE_EXPLICIT, Utils::VARIABLE_TYPE_DOUBLE, Utils::VARIABLE_TYPE_BOOL, "" },
{ TEST_CASE_TYPE_EXPLICIT, Utils::VARIABLE_TYPE_BOOL, Utils::VARIABLE_TYPE_DOUBLE, "" }
};
const unsigned int n_test_cases = sizeof(test_cases) / sizeof(test_cases[0]);
/* Execute all iterations */
for (unsigned int n_test_case = 0; n_test_case < n_test_cases; ++n_test_case)
{
_test_case& test_case = test_cases[n_test_case];
/* Initialize a program object we will use to perform the casting */
initIteration(test_case);
/* Use the program object to XFB the results */
m_has_test_passed &= executeIteration(test_case);
/* Release the GL Resource for this sub test */
deinitInteration();
} /* for (all test cases) */
/* We're done */
if (m_has_test_passed)
{
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
}
else
{
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
}
return STOP;
}
/** Verifies if data XFBed out by the vertex shader are valid, given test case descriptor,
* for which the data have been generated.
*
* @param data_ptr Buffer holding the data XFBed out by the shader.
* @param test_case Descriptor of the test case, for which the vertex shader was
* generated.
*
* @return true if the data were found to be valid, false otherwise.
**/
bool GPUShaderFP64Test5::verifyXFBData(const unsigned char* data_ptr, const _test_case& test_case)
{
const Utils::_variable_type base_dst_type = Utils::getBaseVariableType(test_case.dst_type);
const Utils::_variable_type base_src_type = Utils::getBaseVariableType(test_case.src_type);
const float epsilon = 1e-5f;
const unsigned int n_base_values = sizeof(m_base_values) / sizeof(m_base_values[0]);
const unsigned int n_result_components = Utils::getNumberOfComponentsForVariableType(test_case.dst_type);
const unsigned int n_src_components = Utils::getNumberOfComponentsForVariableType(test_case.src_type);
bool result = true;
_swizzle_type swizzle_operator = SWIZZLE_TYPE_NONE;
unsigned int swizzle_order[4] = { 0 };
const unsigned char* traveller_ptr = data_ptr;
if (!Utils::isMatrixVariableType(test_case.src_type))
{
DE_ASSERT(n_result_components >= 1 && n_result_components <= 4);
DE_ASSERT(n_src_components >= 1 && n_src_components <= 4);
swizzle_operator = m_swizzle_matrix[n_result_components - 1][n_src_components - 1];
getSwizzleTypeProperties(swizzle_operator, DE_NULL, /* out_swizzle_string */
DE_NULL, /* out_n_components */
swizzle_order);
}
for (unsigned int n_base_value = 0; n_base_value < n_base_values; ++n_base_value)
{
for (unsigned int n_result_component = 0; n_result_component < n_result_components; ++n_result_component)
{
unsigned int n_swizzled_component = n_result_component;
if (swizzle_operator != SWIZZLE_TYPE_NONE)
{
n_swizzled_component =
(n_result_component / n_result_components) * n_result_component + swizzle_order[n_result_component];
}
switch (base_dst_type)
{
case Utils::VARIABLE_TYPE_BOOL:
case Utils::VARIABLE_TYPE_INT:
{
double ref_expected_value = (m_base_values[n_base_value]) + static_cast<float>(n_swizzled_component);
double expected_value = ref_expected_value;
int result_value = *((int*)traveller_ptr);
if (base_dst_type == Utils::VARIABLE_TYPE_BOOL)
{
if (expected_value != 0.0)
{
expected_value = 1.0;
}
}
if (result_value != (int)expected_value)
{
m_testCtx.getLog() << tcu::TestLog::Message
<< "Invalid boolean/integer value obtained when doing an "
<< ((test_case.type == TEST_CASE_TYPE_EXPLICIT) ? "explicit" : "implicit")
<< " cast from GLSL type [" << Utils::getVariableTypeString(test_case.src_type)
<< "]"
", component index: ["
<< n_swizzled_component << "]"
", value: ["
<< ref_expected_value << "]"
" to GLSL type ["
<< Utils::getVariableTypeString(test_case.dst_type) << "]"
", retrieved value: ["
<< result_value << "]"
", expected value: ["
<< (int)expected_value << "]"
", shader used:\n"
<< test_case.shader_body.c_str() << tcu::TestLog::EndMessage;
result = false;
}
traveller_ptr += sizeof(int);
break;
} /* VARIABLE_TYPE_BOOL or VARIABLE_TYPE_INT cases */
case Utils::VARIABLE_TYPE_DOUBLE:
{
double ref_expected_value = m_base_values[n_base_value] + (double)n_swizzled_component;
double expected_value = ref_expected_value;
double result_value = *((double*)traveller_ptr);
if (base_src_type == Utils::VARIABLE_TYPE_BOOL)
{
expected_value = ((int)expected_value != 0.0) ? 1.0 : 0.0;
}
else if (base_src_type == Utils::VARIABLE_TYPE_INT)
{
expected_value = (int)expected_value;
}
else if (base_src_type == Utils::VARIABLE_TYPE_UINT)
{
// Negative values in base values array when converted to unsigned int will be ZERO
// Addition operations done inside the shader in such cases will operate on ZERO rather
// than the negative value being passed.
// Replicate the sequence of conversion and addition operations done on the
// shader input, to calculate the expected values in XFB data in the
// problematic cases.
if (expected_value < 0)
{
expected_value = (unsigned int)m_base_values[n_base_value] + n_swizzled_component;
}
expected_value = (unsigned int)expected_value;
}
traveller_ptr += sizeof(double);
if (de::abs(result_value - expected_value) > epsilon)
{
m_testCtx.getLog() << tcu::TestLog::Message
<< "Invalid double-precision floating-point value obtained when doing an "
<< ((test_case.type == TEST_CASE_TYPE_EXPLICIT) ? "explicit" : "implicit")
<< " cast from GLSL type [" << Utils::getVariableTypeString(test_case.src_type)
<< "]"
", component index: ["
<< n_swizzled_component << "]"
", value: ["
<< ref_expected_value << "]"
" to GLSL type ["
<< Utils::getVariableTypeString(test_case.dst_type) << "]"
", retrieved value: ["
<< std::setprecision(16) << result_value << "]"
", expected value: ["
<< std::setprecision(16) << expected_value << "]"
", shader used:\n"
<< test_case.shader_body.c_str() << tcu::TestLog::EndMessage;
result = false;
}
break;
} /* VARIABLE_TYPE_DOUBLE case */
case Utils::VARIABLE_TYPE_FLOAT:
{
float ref_expected_value = (float)m_base_values[n_base_value] + (float)n_swizzled_component;
float expected_value = ref_expected_value;
float result_value = *((float*)traveller_ptr);
if (base_src_type == Utils::VARIABLE_TYPE_BOOL)
{
expected_value = (expected_value != 0.0f) ? 1.0f : 0.0f;
}
else if (base_src_type == Utils::VARIABLE_TYPE_INT)
{
expected_value = (float)((int)expected_value);
}
else if (base_src_type == Utils::VARIABLE_TYPE_UINT)
{
expected_value = (float)((unsigned int)expected_value);
}
traveller_ptr += sizeof(float);
if (de::abs(result_value - expected_value) > epsilon)
{
m_testCtx.getLog() << tcu::TestLog::Message
<< "Invalid single-precision floating-point value obtained when doing an "
<< ((test_case.type == TEST_CASE_TYPE_EXPLICIT) ? "explicit" : "implicit")
<< " cast from GLSL type [" << Utils::getVariableTypeString(test_case.src_type)
<< "]"
", component index: ["
<< n_swizzled_component << "]"
", value: ["
<< ref_expected_value << "]"
" to GLSL type ["
<< Utils::getVariableTypeString(test_case.dst_type) << "]"
", retrieved value: ["
<< std::setprecision(16) << result_value << "]"
", expected value: ["
<< std::setprecision(16) << expected_value << "]"
", shader used:\n"
<< test_case.shader_body.c_str() << tcu::TestLog::EndMessage;
result = false;
}
break;
} /* VARIABLE_TYPE_FLOAT case */
case Utils::VARIABLE_TYPE_UINT:
{
double ref_expected_value = (m_base_values[n_base_value]) + static_cast<float>(n_swizzled_component);
double expected_value = ref_expected_value;
unsigned int result_value = *((unsigned int*)traveller_ptr);
traveller_ptr += sizeof(unsigned int);
if (result_value != (unsigned int)expected_value)
{
if (expected_value < 0.0)
{
// It is undefined to convert a negative floating-point value to an uint.
break;
}
m_testCtx.getLog() << tcu::TestLog::Message
<< "Invalid unsigned integer value obtained when doing an "
<< ((test_case.type == TEST_CASE_TYPE_EXPLICIT) ? "explicit" : "implicit")
<< " cast from GLSL type [" << Utils::getVariableTypeString(test_case.src_type)
<< "]"
", component index: ["
<< n_swizzled_component << "]"
", value: ["
<< ref_expected_value << "]"
" to GLSL type ["
<< Utils::getVariableTypeString(test_case.dst_type) << "]"
", retrieved value: ["
<< result_value << "]"
", expected value: ["
<< (unsigned int)expected_value << "]"
", shader used:\n"
<< test_case.shader_body.c_str() << tcu::TestLog::EndMessage;
result = false;
}
break;
} /* VARIABLE_TYPE_UINT case */
default:
{
TCU_FAIL("Unrecognized variable type");
}
} /* switch (test_case.dst_type) */
} /* for (all result components) */
} /* for (all base values) */
return result;
}
/** Constructor
*
* @param context Rendering context.
*/
GPUShaderFP64Test6::GPUShaderFP64Test6(deqp::Context& context)
: TestCase(context, "illegal_conversions", "Verifies that invalid casts to double-precision variables are detected "
"during compilation time.")
, m_cs_id(0)
, m_fs_id(0)
, m_gs_id(0)
, m_tc_id(0)
, m_te_id(0)
, m_vs_id(0)
, m_has_test_passed(true)
{
}
/** Deinitializes all buffers and GL objects that may have been generated
* during test execution.
**/
void GPUShaderFP64Test6::deinit()
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
if (m_cs_id != 0)
{
gl.deleteShader(m_cs_id);
m_cs_id = 0;
}
if (m_fs_id != 0)
{
gl.deleteShader(m_fs_id);
m_fs_id = 0;
}
if (m_gs_id != 0)
{
gl.deleteShader(m_gs_id);
m_gs_id = 0;
}
if (m_tc_id != 0)
{
gl.deleteShader(m_tc_id);
m_tc_id = 0;
}
if (m_te_id != 0)
{
gl.deleteShader(m_te_id);
m_te_id = 0;
}
if (m_vs_id != 0)
{
gl.deleteShader(m_vs_id);
m_vs_id = 0;
}
}
/** Executes a single test case.
*
* This function can throw TestError exceptions if GL implementation reports
* an error.
*
* @param test_case Test case descriptor.
*
* @return true if test case passed, false otherwise.
**/
bool GPUShaderFP64Test6::executeIteration(const _test_case& test_case)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
const glw::GLuint so_ids[] = { m_cs_id, m_fs_id, m_gs_id, m_tc_id, m_te_id, m_vs_id };
const unsigned int n_so_ids = sizeof(so_ids) / sizeof(so_ids[0]);
bool result = true;
const char* stage_body = NULL;
const char* stage_name = NULL;
for (unsigned int n_so_id = 0; n_so_id < n_so_ids; ++n_so_id)
{
const glw::GLuint so_id = so_ids[n_so_id];
/* Skip compute shader if it is not supported */
if (0 == so_id)
{
continue;
}
/* Compile the shader */
gl.compileShader(so_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed.");
/* Has the compilation failed as expected? */
glw::GLint compile_status = GL_TRUE;
gl.getShaderiv(so_id, GL_COMPILE_STATUS, &compile_status);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed.");
if (compile_status == GL_TRUE)
{
/* What is the current stage's name? */
if (so_id == m_cs_id)
{
stage_body = test_case.cs_shader_body.c_str();
stage_name = "Compute shader";
}
else if (so_id == m_fs_id)
{
stage_body = test_case.fs_shader_body.c_str();
stage_name = "Fragment shader";
}
else if (so_id == m_gs_id)
{
stage_body = test_case.gs_shader_body.c_str();
stage_name = "Geometry shader";
}
else if (so_id == m_tc_id)
{
stage_body = test_case.tc_shader_body.c_str();
stage_name = "Tessellation control shader";
}
else if (so_id == m_te_id)
{
stage_body = test_case.te_shader_body.c_str();
stage_name = "Tessellation evaluation shader";
}
else if (so_id == m_vs_id)
{
stage_body = test_case.vs_shader_body.c_str();
stage_name = "Vertex shader";
}
else
{
/* Doesn't make much sense to throw exceptions here so.. */
stage_body = "";
stage_name = "[?]";
}
/* This shader should have never compiled successfully! */
m_testCtx.getLog() << tcu::TestLog::Message << stage_name
<< " has been compiled successfully, even though the shader was malformed."
" Following is shader body:\n"
<< stage_body << tcu::TestLog::EndMessage;
result = false;
}
} /* for (all shader objects) */
return result;
}
/** Retrieves body of a compute shader that should be used for the purpose of
* user-specified test case.
*
* @param test_case Test case descriptor to use.
*
* @return Requested string.
**/
std::string GPUShaderFP64Test6::getComputeShaderBody(const _test_case& test_case)
{
std::stringstream result_sstream;
/* Add pre-amble */
result_sstream << "#version 420\n"
"#extension GL_ARB_compute_shader : require\n"
"\n"
"layout(local_size_x = 6) in;\n"
"\n"
"void main()\n"
"{\n";
/* Add local variable declarations */
result_sstream << Utils::getVariableTypeString(test_case.src_type) << " src";
if (test_case.src_array_size > 1)
{
result_sstream << "[" << test_case.src_array_size << "]";
}
result_sstream << ";\n";
if (test_case.wrap_dst_type_in_structure)
{
result_sstream << "struct\n"
"{\n"
<< Utils::getVariableTypeString(test_case.dst_type) << " member";
}
else
{
result_sstream << Utils::getVariableTypeString(test_case.dst_type) << " dst";
}
result_sstream << ";\n";
if (test_case.wrap_dst_type_in_structure)
{
result_sstream << "\n} dst;\n";
}
/* Add actual body */
result_sstream << "dst = src;\n"
"}\n";
/* Return the body */
return result_sstream.str();
}
/** Retrieves body of a fragment shader that should be used for the purpose of
* user-specified test case.
*
* @param test_case Test case descriptor to use.
*
* @return Requested string.
**/
std::string GPUShaderFP64Test6::getFragmentShaderBody(const _test_case& test_case)
{
std::stringstream result_sstream;
/* Add pre-amble */
result_sstream << "#version 420\n"
"\n"
"void main()\n"
"{\n";
/* Add local variable declarations */
result_sstream << Utils::getVariableTypeString(test_case.src_type) << " src";
if (test_case.src_array_size > 1)
{
result_sstream << "[" << test_case.src_array_size << "]";
}
result_sstream << ";\n";
if (test_case.wrap_dst_type_in_structure)
{
result_sstream << "struct\n"
"{\n"
<< Utils::getVariableTypeString(test_case.dst_type) << " member";
}
else
{
result_sstream << Utils::getVariableTypeString(test_case.dst_type) << " dst";
}
result_sstream << ";\n";
if (test_case.wrap_dst_type_in_structure)
{
result_sstream << "\n} dst;\n";
}
/* Add actual body */
result_sstream << "dst = src;\n"
"}\n";
/* Return the body */
return result_sstream.str();
}
/** Retrieves body of a geometry shader that should be used for the purpose of
* user-specified test case.
*
* @param test_case Test case descriptor to use.
*
* @return Requested string.
**/
std::string GPUShaderFP64Test6::getGeometryShaderBody(const _test_case& test_case)
{
std::stringstream result_sstream;
/* Add preamble */
result_sstream << "#version 420\n"
"\n"
"layout(points) in;\n"
"layout(max_vertices=1, points) out;\n"
"\n"
"void main()\n"
"{\n";
/* Add local variable declarations */
result_sstream << Utils::getVariableTypeString(test_case.src_type) << " src";
if (test_case.src_array_size > 1)
{
result_sstream << "[" << test_case.src_array_size << "]";
}
result_sstream << ";\n";
if (test_case.wrap_dst_type_in_structure)
{
result_sstream << "struct\n"
"{\n"
<< Utils::getVariableTypeString(test_case.dst_type) << " member";
}
else
{
result_sstream << Utils::getVariableTypeString(test_case.dst_type) << " dst";
}
result_sstream << ";\n"
"\n";
if (test_case.wrap_dst_type_in_structure)
{
result_sstream << "} dst;\n";
}
/* Add actual body */
result_sstream << "dst = src;\n"
"}\n";
/* We're done! */
return result_sstream.str();
}
/** Retrieves body of a tesellation control shader that should be used for the purpose of
* user-specified test case.
*
* @param test_case Test case descriptor to use.
*
* @return Requested string.
**/
std::string GPUShaderFP64Test6::getTessellationControlShaderBody(const _test_case& test_case)
{
std::stringstream result_sstream;
/* Add preamble */
result_sstream << "#version 420\n"
"\n"
"layout(vertices=4) out;\n"
"\n"
"void main()\n"
"{\n";
/* Add local variable declarations. */
result_sstream << Utils::getVariableTypeString(test_case.src_type) << " src";
if (test_case.src_array_size > 1)
{
result_sstream << "[" << test_case.src_array_size << "]";
}
result_sstream << ";\n";
if (test_case.wrap_dst_type_in_structure)
{
result_sstream << "struct\n"
"{\n"
<< Utils::getVariableTypeString(test_case.dst_type) << " member";
}
else
{
result_sstream << Utils::getVariableTypeString(test_case.dst_type) << " dst";
}
if (test_case.wrap_dst_type_in_structure)
{
result_sstream << ";\n"
"} dst;\n";
}
else
{
result_sstream << ";\n";
}
/* Continue with the actual body. */
result_sstream << "gl_TessLevelOuter[0] = 1.0;\n"
"gl_TessLevelOuter[1] = 1.0;\n"
"dst = src;\n"
"}\n";
/* Return the body */
return result_sstream.str();
}
/** Retrieves body of a tessellation evaluation shader that should be used for the purpose of
* user-specified test case.
*
* @param test_case Test case descriptor to use.
*
* @return Requested string.
**/
std::string GPUShaderFP64Test6::getTessellationEvaluationShaderBody(const _test_case& test_case)
{
std::stringstream result_sstream;
/* Add preamble */
result_sstream << "#version 420\n"
"\n"
"layout(isolines) in;\n"
"\n"
"void main()\n"
"{\n";
/* Add local variable declarations */
result_sstream << Utils::getVariableTypeString(test_case.src_type) << " src";
if (test_case.src_array_size > 1)
{
result_sstream << "[" << test_case.src_array_size << "]";
}
result_sstream << ";\n";
if (test_case.wrap_dst_type_in_structure)
{
result_sstream << "struct\n"
"{\n"
<< Utils::getVariableTypeString(test_case.dst_type) << " member";
}
else
{
result_sstream << Utils::getVariableTypeString(test_case.dst_type) << " dst";
}
if (test_case.wrap_dst_type_in_structure)
{
result_sstream << ";\n"
"} dst;\n";
}
else
{
result_sstream << ";\n";
}
/* Continue with the actual body. */
result_sstream << "dst = src;\n";
/* Complete the body */
result_sstream << "}\n";
/* Return the body */
return result_sstream.str();
}
/** Retrieves body of a vertex shader that should be used for the purpose of
* user-specified test case.
*
* @param test_case Test case descriptor to use.
*
* @return Requested string.
**/
std::string GPUShaderFP64Test6::getVertexShaderBody(const _test_case& test_case)
{
std::stringstream result_sstream;
/* Add preamble */
result_sstream << "#version 420\n"
"\n"
"void main()\n"
"{\n";
/* Add local variables */
result_sstream << Utils::getVariableTypeString(test_case.src_type) << " src";
if (test_case.src_array_size > 1)
{
result_sstream << "[" << test_case.src_array_size << "]";
}
result_sstream << ";\n";
if (test_case.wrap_dst_type_in_structure)
{
result_sstream << "struct\n"
"{\n"
<< Utils::getVariableTypeString(test_case.dst_type) << " member";
}
else
{
result_sstream << Utils::getVariableTypeString(test_case.dst_type) << " dst";
}
if (test_case.wrap_dst_type_in_structure)
{
result_sstream << ";\n"
"} dst;\n";
}
else
{
result_sstream << ";\n";
}
/* Start actual body */
result_sstream << "dst = src;\n"
"gl_Position = vec4(1.0);\n"
"}";
return result_sstream.str();
}
/** Initializes shader objects required to run the test. */
void GPUShaderFP64Test6::initTest()
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Generate shader objects */
/* Compute shader support and GL 4.2 required */
if ((true == m_context.getContextInfo().isExtensionSupported("GL_ARB_compute_shader")) &&
(true == Utils::isGLVersionAtLeast(gl, 4 /* major */, 2 /* minor */)))
{
m_cs_id = gl.createShader(GL_COMPUTE_SHADER);
}
m_fs_id = gl.createShader(GL_FRAGMENT_SHADER);
m_gs_id = gl.createShader(GL_GEOMETRY_SHADER);
m_tc_id = gl.createShader(GL_TESS_CONTROL_SHADER);
m_te_id = gl.createShader(GL_TESS_EVALUATION_SHADER);
m_vs_id = gl.createShader(GL_VERTEX_SHADER);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call(s) failed.");
}
/** Assigns shader bodies to all shader objects that will be used for a single iteration.
*
* @param test_case Test case descriptor to generate the shader bodies for.
**/
void GPUShaderFP64Test6::initIteration(_test_case& test_case)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
test_case.cs_shader_body = getComputeShaderBody(test_case);
test_case.fs_shader_body = getFragmentShaderBody(test_case);
test_case.gs_shader_body = getGeometryShaderBody(test_case);
test_case.tc_shader_body = getTessellationControlShaderBody(test_case);
test_case.te_shader_body = getTessellationEvaluationShaderBody(test_case);
test_case.vs_shader_body = getVertexShaderBody(test_case);
/* Assign the bodies to relevant shaders */
const char* cs_body_raw_ptr = test_case.cs_shader_body.c_str();
const char* fs_body_raw_ptr = test_case.fs_shader_body.c_str();
const char* gs_body_raw_ptr = test_case.gs_shader_body.c_str();
const char* tc_body_raw_ptr = test_case.tc_shader_body.c_str();
const char* te_body_raw_ptr = test_case.te_shader_body.c_str();
const char* vs_body_raw_ptr = test_case.vs_shader_body.c_str();
/* m_cs_id is initialized only if compute_shader is supported */
if (0 != m_cs_id)
{
gl.shaderSource(m_cs_id, 1 /* count */, &cs_body_raw_ptr, DE_NULL /* length */);
}
gl.shaderSource(m_fs_id, 1 /* count */, &fs_body_raw_ptr, DE_NULL /* length */);
gl.shaderSource(m_gs_id, 1 /* count */, &gs_body_raw_ptr, DE_NULL /* length */);
gl.shaderSource(m_tc_id, 1 /* count */, &tc_body_raw_ptr, DE_NULL /* length */);
gl.shaderSource(m_te_id, 1 /* count */, &te_body_raw_ptr, DE_NULL /* length */);
gl.shaderSource(m_vs_id, 1 /* count */, &vs_body_raw_ptr, DE_NULL /* length */);
GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call(s) failed.");
}
/** Executes test iteration.
*
* @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
*/
tcu::TestNode::IterateResult GPUShaderFP64Test6::iterate()
{
/* Do not execute the test if GL_ARB_texture_view is not supported */
if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_gpu_shader_fp64"))
{
throw tcu::NotSupportedError("GL_ARB_gpu_shader_fp64 is not supported.");
}
/* Initialize GL objects needed to run the tests */
initTest();
/* Build iteration array to run the tests in an automated manner */
_test_case test_cases[] = {
/* Src array size */ /* Src type */ /* Dst type */ /* wrap_dst_type_in_structure */
{ 2, Utils::VARIABLE_TYPE_INT, Utils::VARIABLE_TYPE_DOUBLE, false, "", "", "", "", "", "" },
{ 2, Utils::VARIABLE_TYPE_INT, Utils::VARIABLE_TYPE_DOUBLE, true, "", "", "", "", "", "" },
{ 2, Utils::VARIABLE_TYPE_IVEC2, Utils::VARIABLE_TYPE_DVEC2, false, "", "", "", "", "", "" },
{ 2, Utils::VARIABLE_TYPE_IVEC2, Utils::VARIABLE_TYPE_DVEC2, true, "", "", "", "", "", "" },
{ 2, Utils::VARIABLE_TYPE_IVEC3, Utils::VARIABLE_TYPE_DVEC3, false, "", "", "", "", "", "" },
{ 2, Utils::VARIABLE_TYPE_IVEC3, Utils::VARIABLE_TYPE_DVEC3, true, "", "", "", "", "", "" },
{ 2, Utils::VARIABLE_TYPE_IVEC4, Utils::VARIABLE_TYPE_DVEC4, false, "", "", "", "", "", "" },
{ 2, Utils::VARIABLE_TYPE_IVEC4, Utils::VARIABLE_TYPE_DVEC4, true, "", "", "", "", "", "" },
{ 2, Utils::VARIABLE_TYPE_UINT, Utils::VARIABLE_TYPE_DOUBLE, false, "", "", "", "", "", "" },
{ 2, Utils::VARIABLE_TYPE_UINT, Utils::VARIABLE_TYPE_DOUBLE, true, "", "", "", "", "", "" },
{ 2, Utils::VARIABLE_TYPE_UVEC2, Utils::VARIABLE_TYPE_DVEC2, false, "", "", "", "", "", "" },
{ 2, Utils::VARIABLE_TYPE_UVEC2, Utils::VARIABLE_TYPE_DVEC2, true, "", "", "", "", "", "" },
{ 2, Utils::VARIABLE_TYPE_UVEC3, Utils::VARIABLE_TYPE_DVEC3, false, "", "", "", "", "", "" },
{ 2, Utils::VARIABLE_TYPE_UVEC3, Utils::VARIABLE_TYPE_DVEC3, true, "", "", "", "", "", "" },
{ 2, Utils::VARIABLE_TYPE_UVEC4, Utils::VARIABLE_TYPE_DVEC4, false, "", "", "", "", "", "" },
{ 2, Utils::VARIABLE_TYPE_UVEC4, Utils::VARIABLE_TYPE_DVEC4, true, "", "", "", "", "", "" },
{ 2, Utils::VARIABLE_TYPE_FLOAT, Utils::VARIABLE_TYPE_DOUBLE, false, "", "", "", "", "", "" },
{ 2, Utils::VARIABLE_TYPE_FLOAT, Utils::VARIABLE_TYPE_DOUBLE, true, "", "", "", "", "", "" },
{ 2, Utils::VARIABLE_TYPE_VEC2, Utils::VARIABLE_TYPE_DVEC2, false, "", "", "", "", "", "" },
{ 2, Utils::VARIABLE_TYPE_VEC2, Utils::VARIABLE_TYPE_DVEC2, true, "", "", "", "", "", "" },
{ 2, Utils::VARIABLE_TYPE_VEC3, Utils::VARIABLE_TYPE_DVEC3, false, "", "", "", "", "", "" },
{ 2, Utils::VARIABLE_TYPE_VEC3, Utils::VARIABLE_TYPE_DVEC3, true, "", "", "", "", "", "" },
{ 2, Utils::VARIABLE_TYPE_VEC4, Utils::VARIABLE_TYPE_DVEC4, false, "", "", "", "", "", "" },
{ 2, Utils::VARIABLE_TYPE_VEC4, Utils::VARIABLE_TYPE_DVEC4, true, "", "", "", "", "", "" },
{ 2, Utils::VARIABLE_TYPE_MAT2, Utils::VARIABLE_TYPE_DMAT2, false, "", "", "", "", "", "" },
{ 2, Utils::VARIABLE_TYPE_MAT2, Utils::VARIABLE_TYPE_DMAT2, true, "", "", "", "", "", "" },
{ 2, Utils::VARIABLE_TYPE_MAT3, Utils::VARIABLE_TYPE_DMAT3, false, "", "", "", "", "", "" },
{ 2, Utils::VARIABLE_TYPE_MAT3, Utils::VARIABLE_TYPE_DMAT3, true, "", "", "", "", "", "" },
{ 2, Utils::VARIABLE_TYPE_MAT4, Utils::VARIABLE_TYPE_DMAT4, false, "", "", "", "", "", "" },
{ 2, Utils::VARIABLE_TYPE_MAT4, Utils::VARIABLE_TYPE_DMAT4, true, "", "", "", "", "", "" },
{ 2, Utils::VARIABLE_TYPE_MAT2X3, Utils::VARIABLE_TYPE_DMAT2X3, false, "", "", "", "", "", "" },
{ 2, Utils::VARIABLE_TYPE_MAT2X3, Utils::VARIABLE_TYPE_DMAT2X3, true, "", "", "", "", "", "" },
{ 2, Utils::VARIABLE_TYPE_MAT2X4, Utils::VARIABLE_TYPE_DMAT2X4, false, "", "", "", "", "", "" },
{ 2, Utils::VARIABLE_TYPE_MAT2X4, Utils::VARIABLE_TYPE_DMAT2X4, true, "", "", "", "", "", "" },
{ 2, Utils::VARIABLE_TYPE_MAT3X2, Utils::VARIABLE_TYPE_DMAT3X2, false, "", "", "", "", "", "" },
{ 2, Utils::VARIABLE_TYPE_MAT3X2, Utils::VARIABLE_TYPE_DMAT3X2, true, "", "", "", "", "", "" },
{ 2, Utils::VARIABLE_TYPE_MAT3X4, Utils::VARIABLE_TYPE_DMAT3X4, false, "", "", "", "", "", "" },
{ 2, Utils::VARIABLE_TYPE_MAT3X4, Utils::VARIABLE_TYPE_DMAT3X4, true, "", "", "", "", "", "" },
{ 2, Utils::VARIABLE_TYPE_MAT4X2, Utils::VARIABLE_TYPE_DMAT4X2, false, "", "", "", "", "", "" },
{ 2, Utils::VARIABLE_TYPE_MAT4X2, Utils::VARIABLE_TYPE_DMAT4X2, true, "", "", "", "", "", "" },
{ 2, Utils::VARIABLE_TYPE_MAT4X3, Utils::VARIABLE_TYPE_DMAT4X3, false, "", "", "", "", "", "" },
{ 2, Utils::VARIABLE_TYPE_MAT4X3, Utils::VARIABLE_TYPE_DMAT4X3, true, "", "", "", "", "", "" }
};
const unsigned int n_test_cases = sizeof(test_cases) / sizeof(test_cases[0]);
/* Execute all iterations */
for (unsigned int n_test_case = 0; n_test_case < n_test_cases; ++n_test_case)
{
_test_case& test_case = test_cases[n_test_case];
/* Initialize a program object we will use to perform the casting */
initIteration(test_case);
/* Use the program object to XFB the results */
m_has_test_passed &= executeIteration(test_case);
} /* for (all test cases) */
/* We're done */
if (m_has_test_passed)
{
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
}
else
{
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
}
return STOP;
}
/** Constructor
*
* @param context Rendering context.
*/
GPUShaderFP64Test7::GPUShaderFP64Test7(deqp::Context& context)
: TestCase(context, "varyings", "Verifies double-precision floating-point varyings work correctly "
"in all shader stages.")
, m_are_double_inputs_supported(false)
, m_fbo_id(0)
, m_fs_id(0)
, m_gs_id(0)
, m_has_test_passed(true)
, m_n_max_components_per_stage(0)
, m_n_xfb_varyings(0)
, m_po_id(0)
, m_tc_id(0)
, m_te_id(0)
, m_to_id(0)
, m_to_data(NULL)
, m_to_height(4)
, m_to_width(4)
, m_xfb_bo_id(0)
, m_xfb_varyings(NULL)
, m_vao_id(0)
, m_vs_id(0)
{
}
/** Compiles all shaders attached to test program object and links it.
*
* @param variables
*
* @return true if the process was executed successfully, false otherwise.
*/
bool GPUShaderFP64Test7::buildTestProgram(_variables& variables)
{
std::string fs_body = getFragmentShaderBody(variables);
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
std::string gs_body = getGeometryShaderBody(variables);
std::string tc_body = getTessellationControlShaderBody(variables);
std::string te_body = getTessellationEvaluationShaderBody(variables);
std::string vs_body = getVertexShaderBody(variables);
bool result = false;
/* Try to link the program object */
glw::GLint link_status = GL_FALSE;
/* Compile the shaders */
if (!compileShader(m_fs_id, fs_body))
{
m_testCtx.getLog() << tcu::TestLog::Message << "Fragment shader failed to compile." << tcu::TestLog::EndMessage;
goto end;
}
if (!compileShader(m_gs_id, gs_body))
{
m_testCtx.getLog() << tcu::TestLog::Message << "Geometry shader failed to compile." << tcu::TestLog::EndMessage;
goto end;
}
if (!compileShader(m_tc_id, tc_body))
{
m_testCtx.getLog() << tcu::TestLog::Message << "Tessellation control shader failed to compile."
<< tcu::TestLog::EndMessage;
goto end;
}
if (!compileShader(m_te_id, te_body))
{
m_testCtx.getLog() << tcu::TestLog::Message << "Tessellation evaluation shader failed to compile."
<< tcu::TestLog::EndMessage;
goto end;
}
if (!compileShader(m_vs_id, vs_body))
{
m_testCtx.getLog() << tcu::TestLog::Message << "Vertex shader failed to compile." << tcu::TestLog::EndMessage;
goto end;
}
/* Configure XFB */
releaseXFBVaryingNames();
generateXFBVaryingNames(variables);
gl.transformFeedbackVaryings(m_po_id, m_n_xfb_varyings, m_xfb_varyings, GL_INTERLEAVED_ATTRIBS);
gl.linkProgram(m_po_id);
/* Have we succeeded? */
GLU_EXPECT_NO_ERROR(gl.getError(), "Either glTransformFeedbackVaryings() or glLinkProgram() call failed.");
gl.getProgramiv(m_po_id, GL_LINK_STATUS, &link_status);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed.");
if (link_status != GL_TRUE)
{
m_testCtx.getLog() << tcu::TestLog::Message << "A valid program object failed to link."
<< tcu::TestLog::EndMessage;
goto end;
}
/* Retrieve attribute locations *if* GL_ARB_vertex_attrib_64bit is supported */
if (m_are_double_inputs_supported)
{
const size_t n_variables = variables.size();
for (size_t n_variable = 0; n_variable < n_variables; ++n_variable)
{
_variable& current_variable = variables[n_variable];
std::stringstream attribute_name_sstream;
attribute_name_sstream << "in_vs_variable" << n_variable;
if (current_variable.array_size > 1)
{
attribute_name_sstream << "[0]";
}
current_variable.attribute_location = gl.getAttribLocation(m_po_id, attribute_name_sstream.str().c_str());
if (current_variable.attribute_location == -1)
{
m_testCtx.getLog() << tcu::TestLog::Message << "Input double-precision attribute named ["
<< attribute_name_sstream.str().c_str()
<< "] is considered inactive which is invalid." << tcu::TestLog::EndMessage;
m_has_test_passed = false;
goto end;
}
} /* for (all test variables) */
} /* if (m_are_double_inputs_supported) */
m_current_fs_body = fs_body;
m_current_gs_body = gs_body;
m_current_tc_body = tc_body;
m_current_te_body = te_body;
m_current_vs_body = vs_body;
result = true;
end:
return result;
}
/** Updates shader object's body and then compiles the shader.
*
* @param body Body to use for the shader.
*
* @return true if the shader compiled successfully, false otherwise.
**/
bool GPUShaderFP64Test7::compileShader(glw::GLint shader_id, const std::string& body)
{
const char* body_raw_ptr = body.c_str();
glw::GLint compile_status = GL_FALSE;
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.shaderSource(shader_id, 1 /* count */, &body_raw_ptr, NULL /* length */);
GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed.");
gl.compileShader(shader_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed.");
gl.getShaderiv(shader_id, GL_COMPILE_STATUS, &compile_status);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed.");
return (compile_status == GL_TRUE);
}
/** Configure storage of a buffer object used for capturing XFB data.
*
* @param variables Holds descriptor for all variables used for the iteration the
* BO is being configured for. Storage size will be directly related
* to the number of the variables and their type.
*/
void GPUShaderFP64Test7::configureXFBBuffer(const _variables& variables)
{
DE_ASSERT(m_n_xfb_varyings != 0);
/* Geometry shaders outputs 4 vertices making up a triangle strip per draw call.
* The test only draws a single patch, and triangles are caught by transform feed-back.
* Let's initialize the storage, according to the list of variables that will be used
* for the test run.
*/
unsigned int bo_size = 0;
for (_variables_const_iterator variables_iterator = variables.begin(); variables_iterator != variables.end();
variables_iterator++)
{
const _variable& variable = *variables_iterator;
unsigned int n_bytes_needed = static_cast<unsigned int>(
Utils::getNumberOfComponentsForVariableType(variable.type) * variable.array_size * sizeof(double));
bo_size += n_bytes_needed;
} /* for (all variables) */
bo_size *= 3 /* vertices per triangle */ * 2; /* triangles emitted by geometry shader */
/* Set up the BO storage */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, bo_size, DE_NULL /* data */, GL_STATIC_DRAW);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call failed.");
}
/** Deinitializes all buffers and GL objects that may have been generated
* during test execution.
**/
void GPUShaderFP64Test7::deinit()
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
if (m_fbo_id != 0)
{
gl.deleteFramebuffers(1, &m_fbo_id);
m_fbo_id = 0;
}
if (m_fs_id != 0)
{
gl.deleteShader(m_fs_id);
m_fs_id = 0;
}
if (m_gs_id != 0)
{
gl.deleteShader(m_gs_id);
m_gs_id = 0;
}
if (m_po_id != 0)
{
gl.deleteProgram(m_po_id);
m_po_id = 0;
}
if (m_tc_id != 0)
{
gl.deleteShader(m_tc_id);
m_tc_id = 0;
}
if (m_te_id != 0)
{
gl.deleteShader(m_te_id);
m_te_id = 0;
}
if (m_to_data != NULL)
{
delete[] m_to_data;
m_to_data = NULL;
}
if (m_to_id != 0)
{
gl.deleteTextures(1, &m_to_id);
m_to_id = 0;
}
if (m_xfb_bo_id != 0)
{
gl.deleteBuffers(1, &m_xfb_bo_id);
m_xfb_bo_id = 0;
}
if (m_xfb_varyings != DE_NULL)
{
releaseXFBVaryingNames();
}
if (m_vao_id != 0)
{
gl.deleteVertexArrays(1, &m_vao_id);
m_vao_id = 0;
}
if (m_vs_id != 0)
{
gl.deleteShader(m_vs_id);
m_vs_id = 0;
}
}
/** Executes the functional part of the test (case a) from the test spec)
*
* @param variables Vector of variable descriptors defining properties of
* variables that should be used for the iteration.
*
* @return true if the test passed, false otherwise.
**/
bool GPUShaderFP64Test7::executeFunctionalTest(_variables& variables)
{
bool result = true;
/* Build the test program */
if (!buildTestProgram(variables))
{
return false;
}
/* Set up input attributes if GL_ARB_vertex_attrib_64bit extension is supported */
if (m_are_double_inputs_supported)
{
setInputAttributeValues(variables);
}
/* Set up buffer object to hold XFB data. The data will be used for logging purposes
* only, if a data mismatch is detected.
*/
configureXFBBuffer(variables);
/* Issue a draw call using the test program */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.clearColor(1.0f, 1.0f, 1.0f, 1.0f);
GLU_EXPECT_NO_ERROR(gl.getError(), "glClearColor() call failed.");
gl.clear(GL_COLOR_BUFFER_BIT);
GLU_EXPECT_NO_ERROR(gl.getError(), "glClear() call failed.");
gl.useProgram(m_po_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
gl.viewport(0, /* x */
0, /* y */
m_to_width, m_to_height);
GLU_EXPECT_NO_ERROR(gl.getError(), "glViewport() call failed.");
gl.beginTransformFeedback(GL_TRIANGLES);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() call failed.");
{
gl.drawArrays(GL_PATCHES, 0 /* first */, 4 /* count */);
GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed.");
}
gl.endTransformFeedback();
GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() call failed.");
/* Verify color attachment contents */
const float epsilon = 1.0f / 255.0f;
gl.readPixels(0 /* x */, 0 /* y */, m_to_width, m_to_height, GL_RGBA, GL_UNSIGNED_BYTE, m_to_data);
GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels() call failed.");
for (unsigned int y = 0; y < m_to_height; ++y)
{
const unsigned char* row_ptr = m_to_data + 4 /* rgba */ * m_to_width * y;
for (unsigned int x = 0; x < m_to_width; ++x)
{
const unsigned char* pixel_ptr = row_ptr + 4 /* rgba */ * x;
if (de::abs(pixel_ptr[0]) > epsilon || de::abs(pixel_ptr[1] - 255) > epsilon ||
de::abs(pixel_ptr[2]) > epsilon || de::abs(pixel_ptr[3]) > epsilon)
{
m_testCtx.getLog() << tcu::TestLog::Message << "Invalid pixel found at (" << x << ", " << y
<< ")"
"; expected:(0, 255, 0, 0), found: ("
<< (int)pixel_ptr[0] << ", " << (int)pixel_ptr[1] << ", " << (int)pixel_ptr[2]
<< ", " << (int)pixel_ptr[3]
<< "), with the following variable types used as varyings:"
<< tcu::TestLog::EndMessage;
/* List the variable types that failed the test */
const size_t n_variables = variables.size();
for (size_t n_variable = 0; n_variable < n_variables; ++n_variable)
{
m_testCtx.getLog() << tcu::TestLog::Message << "gs_variable" << n_variable << ": "
<< Utils::getVariableTypeString(variables[n_variable].type)
<< " (array size:" << variables[n_variable].array_size << ")"
<< tcu::TestLog::EndMessage;
} /* for (all variable types) */
/* Log the variable contents */
logVariableContents(variables);
/* Log shaders used for the iteration */
m_testCtx.getLog() << tcu::TestLog::Message << "Shaders used:\n"
"\n"
"(VS):\n"
<< m_current_vs_body.c_str() << "\n"
<< "(TC):\n"
"\n"
<< m_current_tc_body.c_str() << "\n"
"(TE):\n"
"\n"
<< m_current_te_body.c_str() << "\n"
"(GS):\n"
<< m_current_gs_body.c_str() << "\n"
"(FS):\n"
"\n"
<< m_current_fs_body.c_str() << tcu::TestLog::EndMessage;
result = false;
goto end;
}
} /* for (all columns) */
} /* for (all rows) */
/* All done! */
end:
return result;
}
/** Takes user-input vector of test variables and allocates & fills an array of strings
* holding names of geometry shader stage varyings that should be captured during
* transform feedback operation. The array will be stored in m_xfb_varyings.
*
* @param variables Holds all test variable descriptors to be used for the iteration.
*/
void GPUShaderFP64Test7::generateXFBVaryingNames(const _variables& variables)
{
unsigned int n_variable = 0;
unsigned int n_varying = 0;
unsigned int n_varyings = 0;
if (m_xfb_varyings != NULL)
{
releaseXFBVaryingNames();
}
for (_variables_const_iterator variables_iterator = variables.begin(); variables_iterator != variables.end();
++variables_iterator)
{
const _variable& variable = *variables_iterator;
n_varyings += variable.array_size;
}
m_xfb_varyings = new glw::GLchar*[n_varyings];
for (_variables_const_iterator variables_iterator = variables.begin(); variables_iterator != variables.end();
++variables_iterator, ++n_variable)
{
const _variable& variable = *variables_iterator;
for (unsigned int array_index = 0; array_index < variable.array_size; ++array_index, ++n_varying)
{
std::stringstream varying_sstream;
size_t varying_length;
varying_sstream << "gs_variable" << n_variable;
if (variable.array_size > 1)
{
varying_sstream << "[" << array_index << "]";
}
/* Store the varying name */
varying_length = varying_sstream.str().length();
m_xfb_varyings[n_varying] = new glw::GLchar[varying_length + 1 /* terminator */];
memcpy(m_xfb_varyings[n_varying], varying_sstream.str().c_str(), varying_length);
m_xfb_varyings[n_varying][varying_length] = 0;
} /* for (all array indices) */
} /* for (all varyings) */
m_n_xfb_varyings = n_varyings;
}
/** Retrieves body of a shader that defines input variable of user-specified type & array size
* without using the "flat" keyword. (case c) )
*
* @param input_variable_type Variable type to use for input variable declaration.
* @param array_size 1 if the variable should not be arrayed; otherwise defines size
* of the arrayed variable.
*
* @return Requested string.
**/
std::string GPUShaderFP64Test7::getCodeOfFragmentShaderWithNonFlatDoublePrecisionInput(
Utils::_variable_type input_variable_type, unsigned int array_size)
{
std::stringstream result_sstream;
std::stringstream array_index_stringstream;
std::stringstream array_size_stringstream;
if (array_size > 1)
{
array_index_stringstream << "[0]";
array_size_stringstream << "[" << array_size << "]";
}
if (Utils::isMatrixVariableType(input_variable_type))
{
array_index_stringstream << "[0].x";
}
else if (Utils::getNumberOfComponentsForVariableType(input_variable_type) > 1)
{
array_index_stringstream << "[0]";
}
result_sstream << "#version 400\n"
"\n"
"in "
<< Utils::getVariableTypeString(input_variable_type) << " test_input"
<< array_size_stringstream.str() << ";\n"
"\n"
"out float test_output;\n"
"\n"
"void main()\n"
"{\n"
" if (test_input"
<< array_index_stringstream.str() << " > 2.0)\n"
" {\n"
" test_output = 1.0;\n"
" }\n"
" else\n"
" {\n"
" test_output = 3.0;\n"
" }\n"
"}\n";
return result_sstream.str();
}
/** Retrieves body of a shader that defines double-precision floating-point output variable. (case b) ).
*
* @param input_variable_type Variable type to use for input variable declaration.
* @param array_size 1 if the variable should not be arrayed; otherwise defines size
* of the arrayed variable.
*
* @return Requested string.
**/
std::string GPUShaderFP64Test7::getCodeOfFragmentShaderWithDoublePrecisionOutput(
Utils::_variable_type output_variable_type, unsigned int array_size)
{
std::stringstream array_index_sstream;
std::stringstream array_size_sstream;
std::stringstream result_sstream;
std::string output_variable_type_string = Utils::getVariableTypeString(output_variable_type);
if (array_size > 1)
{
array_index_sstream << "[0]";
array_size_sstream << "[" << array_size << "]";
}
result_sstream << "#version 400\n"
"\n"
"out "
<< output_variable_type_string << " test_output" << array_size_sstream.str() << ";\n"
"\n"
"void main()\n"
"{\n"
" test_output"
<< array_index_sstream.str() << " = " << output_variable_type_string << "(2.0);\n"
"}\n";
return result_sstream.str();
}
/** Retrieves body of a fragment shader that uses user-specified set of variables
* to declare contents of input & output block.
*
* @param variables As per description.
*
* @return Requested string.
**/
std::string GPUShaderFP64Test7::getFragmentShaderBody(const _variables& variables)
{
std::stringstream result_sstream;
/* Form the pre-amble */
result_sstream << "#version 400\n"
"\n"
/* Add input block */
<< "in GS_DATA\n"
"{\n"
<< getVariableDeclarations("gs", variables, "flat") << "};\n"
"\n"
/* Add output variable */
<< "out vec4 result;\n"
"\n"
/* Add main() definition */
"void main()\n"
"{\n"
"const double epsilon = 1e-5;\n"
"\n"
"result = vec4(1, 0, 0, 0);\n"
"\n";
/* Determine expected values first */
unsigned int base_counter = 1;
const size_t n_variables = variables.size();
for (unsigned int n_variable = 0; n_variable < n_variables; ++n_variable)
{
unsigned int variable_array_size = variables[n_variable].array_size;
Utils::_variable_type variable_type = variables[n_variable].type;
unsigned int n_variable_type_components = Utils::getNumberOfComponentsForVariableType(variable_type);
std::string variable_type_string = Utils::getVariableTypeString(variable_type);
std::stringstream array_size_sstream;
if (variable_array_size > 1)
{
array_size_sstream << "[" << variable_array_size << "]";
}
/* Local variable declaration */
result_sstream << variable_type_string << " expected_variable" << n_variable << array_size_sstream.str()
<< ";\n"
"\n";
/* Set expected values */
for (unsigned int index = 0; index < variable_array_size; ++index)
{
std::stringstream array_index_sstream;
if (variable_array_size > 1)
{
array_index_sstream << "[" << index << "]";
}
result_sstream << "expected_variable" << n_variable << array_index_sstream.str() << " = "
<< variable_type_string << "(";
for (unsigned int n_component = 0; n_component < n_variable_type_components; ++n_component)
{
unsigned int expected_value =
(base_counter + 0) + (base_counter + 1) + (base_counter + 2) + (base_counter + 3);
if (m_are_double_inputs_supported)
{
/* VS input attributes */
//expected_value += (base_counter + 6);
expected_value -= 1;
}
result_sstream << expected_value;
if (n_component != (n_variable_type_components - 1))
{
result_sstream << ", ";
}
++base_counter;
} /* for (all components) */
result_sstream << ");\n";
} /* for (all array indices) */
result_sstream << "\n";
} /* for (all variable types) */
/* Now that we know the expected values, do a huge conditional check to verify if all
* input variables carry correct information.
*/
result_sstream << "if (";
for (unsigned int n_variable = 0; n_variable < n_variables; ++n_variable)
{
unsigned int variable_array_size = variables[n_variable].array_size;
Utils::_variable_type variable_type = variables[n_variable].type;
bool is_variable_type_matrix = Utils::isMatrixVariableType(variable_type);
unsigned int n_variable_type_components = Utils::getNumberOfComponentsForVariableType(variable_type);
std::string variable_type_string = Utils::getVariableTypeString(variable_type);
for (unsigned int index = 0; index < variable_array_size; ++index)
{
std::stringstream array_index_sstream;
if (variable_array_size > 1)
{
array_index_sstream << "[" << index << "]";
}
for (unsigned int n_component = 0; n_component < n_variable_type_components; ++n_component)
{
std::stringstream component_index_sstream;
if (n_variable_type_components > 1)
{
component_index_sstream << "[" << n_component << "]";
}
result_sstream << "abs(expected_variable" << n_variable << array_index_sstream.str();
if (is_variable_type_matrix)
{
const unsigned int n_columns = Utils::getNumberOfColumnsForVariableType(variable_type);
const unsigned int column = n_component % n_columns;
const unsigned int row = n_component / n_columns;
result_sstream << "[" << column << "]"
"."
<< Utils::getComponentAtIndex(row);
}
else
{
result_sstream << component_index_sstream.str();
}
result_sstream << " - gs_variable" << n_variable << array_index_sstream.str();
if (is_variable_type_matrix)
{
const unsigned int n_columns = Utils::getNumberOfColumnsForVariableType(variable_type);
const unsigned int column = n_component % n_columns;
const unsigned int row = n_component / n_columns;
result_sstream << "[" << column << "]"
"."
<< Utils::getComponentAtIndex(row);
}
else
{
result_sstream << component_index_sstream.str();
}
result_sstream << ") <= epsilon &&";
} /* for (all components) */
} /* for (all array indices) */
} /* for (all variable types) */
result_sstream << "true)\n"
"{\n"
" result = vec4(0, 1, 0, 0);\n"
"}\n"
"}\n";
/* All done */
return result_sstream.str();
}
/** Retrieves body of a geometry shader that uses user-specified set of variables
* to declare contents of input & output block.
*
* @param variables As per description.
*
* @return Requested string.
**/
std::string GPUShaderFP64Test7::getGeometryShaderBody(const _variables& variables)
{
std::stringstream result_sstream;
/* Form the pre-amble */
result_sstream << "#version 400\n"
"\n"
"layout(triangles) in;\n"
"layout(triangle_strip, max_vertices=4) out;\n"
"\n"
/* Add the input block */
"in TE_DATA\n"
"{\n"
<< getVariableDeclarations("te", variables) << "} in_data[];\n"
"\n"
/* Add the output block */
"out GS_DATA\n"
"{\n"
<< getVariableDeclarations("gs", variables, "flat") << "};\n"
"\n"
/* Declare main() function */
"void main()\n"
"{\n";
/* Take input variables, add a predefined value and forward them to output variables */
const float quad_vertices[] = { -1.0f, -1.0f, 0.0f, 1.0f, -1.0f, 1.0f, 0.0f, 1.0f,
1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f };
const unsigned int n_quad_vertices =
sizeof(quad_vertices) / sizeof(quad_vertices[0]) / 4 /* components per vertex */;
const size_t n_variables = variables.size();
for (unsigned int n_quad_vertex = 0; n_quad_vertex < n_quad_vertices; ++n_quad_vertex)
{
unsigned int counter = 4;
const float* current_quad_vertex = quad_vertices + n_quad_vertex * 4 /* components per vertex */;
for (unsigned int n_variable = 0; n_variable < n_variables; ++n_variable)
{
unsigned int variable_array_size = variables[n_variable].array_size;
Utils::_variable_type variable_type = variables[n_variable].type;
unsigned int n_variable_type_components = Utils::getNumberOfComponentsForVariableType(variable_type);
std::string variable_type_string = Utils::getVariableTypeString(variable_type);
for (unsigned int index = 0; index < variable_array_size; ++index)
{
std::stringstream array_index_sstream;
if (variable_array_size > 1)
{
array_index_sstream << "[" << index << "]";
}
result_sstream << "gs_variable" << n_variable << array_index_sstream.str()
<< " = in_data[0].te_variable" << n_variable << array_index_sstream.str() << " + "
<< variable_type_string << "(";
for (unsigned int n_component = 0; n_component < n_variable_type_components; ++n_component)
{
result_sstream << (counter++);
if (n_component != (n_variable_type_components - 1))
{
result_sstream << ", ";
}
} /* for (all components) */
result_sstream << ");\n";
} /* for (all array indices) */
} /* for (all variable types) */
result_sstream << "gl_Position = vec4(" << current_quad_vertex[0] << ", " << current_quad_vertex[1] << ", "
<< current_quad_vertex[2] << ", " << current_quad_vertex[3] << ");\n"
"EmitVertex();\n";
} /* for (all emitted quad vertices) */
result_sstream << "EndPrimitive();\n"
"}\n";
/* All done */
return result_sstream.str();
}
/** Retrieves body of a tessellation control shader that uses user-specified set of variables
* to declare contents of input & output block.
*
* @param variables As per description.
*
* @return Requested string.
**/
std::string GPUShaderFP64Test7::getTessellationControlShaderBody(const _variables& variables)
{
std::stringstream result_sstream;
/* Form the pre-amble */
result_sstream << "#version 400\n"
"\n"
"layout (vertices=4) out;\n"
/* Declare input block */
"in VS_DATA\n"
"{\n"
<< getVariableDeclarations("vs", variables) << "} in_data[];\n"
/* Declare output block */
"out TC_DATA\n"
"{\n"
<< getVariableDeclarations("tc", variables) << "} out_data[];\n"
"\n"
/* Define main() */
"void main()\n"
"{\n"
" gl_TessLevelInner[0] = 1;\n"
" gl_TessLevelInner[1] = 1;\n"
" gl_TessLevelOuter[0] = 1;\n"
" gl_TessLevelOuter[1] = 1;\n"
" gl_TessLevelOuter[2] = 1;\n"
" gl_TessLevelOuter[3] = 1;\n"
"\n";
/* Take input variables, add a predefined value and forward them to output variables */
const size_t n_variables = variables.size();
unsigned int counter = 2;
for (unsigned int n_variable = 0; n_variable < n_variables; ++n_variable)
{
unsigned int variable_array_size = variables[n_variable].array_size;
Utils::_variable_type variable_type = variables[n_variable].type;
unsigned int n_variable_type_components = Utils::getNumberOfComponentsForVariableType(variable_type);
std::string variable_type_string = Utils::getVariableTypeString(variable_type);
for (unsigned int index = 0; index < variable_array_size; ++index)
{
std::stringstream array_index_sstream;
if (variable_array_size > 1)
{
array_index_sstream << "[" << index << "]";
}
result_sstream << "out_data[gl_InvocationID].tc_variable" << n_variable << array_index_sstream.str()
<< " = in_data[0].vs_variable" << n_variable << array_index_sstream.str() << " + "
<< variable_type_string << "(";
for (unsigned int n_component = 0; n_component < n_variable_type_components; ++n_component)
{
result_sstream << (counter++);
if (n_component != (n_variable_type_components - 1))
{
result_sstream << ", ";
}
}
result_sstream << ");\n";
} /* for (all array indices) */
} /* for (all variable types) */
result_sstream << "}\n";
/* We're done */
return result_sstream.str();
}
/** Retrieves body of a tessellation evaluation shader that uses user-specified set of variables
* to declare contents of input & output block.
*
* @param variables As per description.
*
* @return Requested string.
**/
std::string GPUShaderFP64Test7::getTessellationEvaluationShaderBody(const _variables& variables)
{
std::stringstream result_sstream;
/* Form the pre-amble */
result_sstream << "#version 400\n"
"\n"
"layout(quads) in;\n"
"\n"
/* Define input block */
"in TC_DATA\n"
"{\n"
<< getVariableDeclarations("tc", variables) << "} in_data[];\n"
"\n"
/* Define output block */
"out TE_DATA\n"
"{\n"
<< getVariableDeclarations("te", variables) << "};\n"
"\n"
/* Define main() */
"void main()\n"
"{\n";
/* Take input variables, add a predefined value and forward them to output variables */
const size_t n_variables = variables.size();
unsigned int counter = 3;
for (unsigned int n_variable = 0; n_variable < n_variables; ++n_variable)
{
unsigned int variable_array_size = variables[n_variable].array_size;
Utils::_variable_type variable_type = variables[n_variable].type;
unsigned int n_variable_type_components = Utils::getNumberOfComponentsForVariableType(variable_type);
std::string variable_type_string = Utils::getVariableTypeString(variable_type);
for (unsigned int index = 0; index < variable_array_size; ++index)
{
std::stringstream array_index_sstream;
if (variable_array_size > 1)
{
array_index_sstream << "[" << index << "]";
}
result_sstream << "te_variable" << n_variable << array_index_sstream.str() << " = in_data[0].tc_variable"
<< n_variable << array_index_sstream.str() << " + " << variable_type_string << "(";
for (unsigned int n_component = 0; n_component < n_variable_type_components; ++n_component)
{
result_sstream << (counter++);
if (n_component != (n_variable_type_components - 1))
{
result_sstream << ", ";
}
} /* for (all components) */
result_sstream << ");\n";
} /* for (all array indices) */
} /* for (all variable types) */
result_sstream << "}\n";
/* All done */
return result_sstream.str();
}
/** Returns a string containing declarations of user-specified set of variables.
* Each declaration can optionally use a layot qualifier requested by the caller.
*
* @param prefix Prefix to use for variable names.
* @param variables List of variables to declare in the result string.
* @param explicit_locations true if each declaration should explicitly define location
* of the variable ( eg. (layout location=X) )
* @param layout_qualifier Optional qualifier to use for the declaration. Must not
* be NULL.
*
* @return Requested string.
**/
std::string GPUShaderFP64Test7::getVariableDeclarations(const char* prefix, const _variables& variables,
const char* layout_qualifier)
{
std::stringstream result_sstream;
/* Define output variables */
const size_t n_variables = variables.size();
for (unsigned int n_variable = 0; n_variable < n_variables; ++n_variable)
{
unsigned int variable_array_size = variables[n_variable].array_size;
Utils::_variable_type variable_type = variables[n_variable].type;
std::string variable_type_string = Utils::getVariableTypeString(variable_type);
result_sstream << layout_qualifier << " " << variable_type_string << " " << prefix << "_variable" << n_variable;
if (variable_array_size > 1)
{
result_sstream << "[" << variable_array_size << "]";
}
result_sstream << ";\n";
} /* for (all user-specified variable types) */
return result_sstream.str();
}
/** Retrieves body of a vertex shader that uses user-specified set of variables
* to declare contents of input & output block.
*
* @param variables As per description.
*
* @return Requested string.
**/
std::string GPUShaderFP64Test7::getVertexShaderBody(const _variables& variables)
{
std::stringstream result_sstream;
/* Form pre-amble */
result_sstream << "#version 400\n"
"\n";
/* Define input variables if GL_ARB_vertex_attrib_64bit is supported */
if (m_are_double_inputs_supported)
{
result_sstream << "#extension GL_ARB_vertex_attrib_64bit : require\n"
<< getVariableDeclarations("in_vs", variables, "in");
}
/* Define output variables */
result_sstream << "out VS_DATA\n"
"{\n"
<< getVariableDeclarations("vs", variables);
/* Define main() */
result_sstream << "};\n"
"\n"
"void main()\n"
"{\n";
/* Set output variable values */
unsigned int counter = 1;
const size_t n_variables = variables.size();
for (unsigned int n_variable = 0; n_variable < n_variables; ++n_variable)
{
unsigned int variable_array_size = variables[n_variable].array_size;
Utils::_variable_type variable_type = variables[n_variable].type;
const unsigned int n_variable_type_components = Utils::getNumberOfComponentsForVariableType(variable_type);
std::string variable_type_string = Utils::getVariableTypeString(variable_type);
for (unsigned int index = 0; index < variable_array_size; ++index)
{
if (variable_array_size == 1)
{
result_sstream << "vs_variable" << n_variable << " = " << variable_type_string << "(";
}
else
{
result_sstream << "vs_variable" << n_variable << "[" << index << "]"
<< " = " << variable_type_string << "(";
}
for (unsigned int n_component = 0; n_component < n_variable_type_components; ++n_component)
{
result_sstream << (double)(counter++);
/* Use input attributes, if available */
if (m_are_double_inputs_supported)
{
result_sstream << " + in_vs_variable" << n_variable;
if (variable_array_size > 1)
{
result_sstream << "[" << index << "]";
}
if (Utils::isMatrixVariableType(variables[n_variable].type))
{
const unsigned int n_columns = Utils::getNumberOfColumnsForVariableType(variable_type);
const unsigned int column = n_component % n_columns;
const unsigned int row = n_component / n_columns;
result_sstream << "[" << (column) << "]"
"."
<< Utils::getComponentAtIndex(row);
}
else if (n_variable_type_components > 1)
{
result_sstream << "[" << n_component << "]";
}
}
if (n_component != (n_variable_type_components - 1))
{
result_sstream << ", ";
}
} /* for (all components) */
result_sstream << ");\n";
}
} /* for (all variable types) */
/* We will be using geometry shader to lay out the actual vertices so
* the only thing we need to make sure is that the vertex never gets
* culled.
*/
result_sstream << "gl_Position = vec4(0, 0, 0, 1);\n"
"}\n";
/* That's it */
return result_sstream.str();
}
/** Initializes shader objects required to run the test. */
void GPUShaderFP64Test7::initTest()
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Are double-precision input variables supported? */
m_are_double_inputs_supported = m_context.getContextInfo().isExtensionSupported("GL_ARB_vertex_attrib_64bit");
/* Create a vertex array object */
gl.genVertexArrays(1, &m_vao_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call failed.");
gl.bindVertexArray(m_vao_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed.");
/* Create a texture object we will use as FBO's color attachment */
gl.genTextures(1, &m_to_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() call failed");
gl.bindTexture(GL_TEXTURE_2D, m_to_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed.");
gl.texStorage2D(GL_TEXTURE_2D, 1 /* levels */, GL_RGBA8, m_to_width, m_to_height);
GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage2D() call failed.");
/* Allocate temporary buffer to hold the texture data we will be reading
* from color attachment. */
m_to_data = new unsigned char[m_to_width * m_to_height * 4 /* RGBA */];
/* Create and set up a framebuffer object */
gl.genFramebuffers(1, &m_fbo_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers() call failed.");
gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindframebuffer() call failed.");
gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_to_id, 0 /* level */);
GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferTexture2D() call failed.");
/* Create all shader objects */
m_fs_id = gl.createShader(GL_FRAGMENT_SHADER);
m_gs_id = gl.createShader(GL_GEOMETRY_SHADER);
m_tc_id = gl.createShader(GL_TESS_CONTROL_SHADER);
m_te_id = gl.createShader(GL_TESS_EVALUATION_SHADER);
m_vs_id = gl.createShader(GL_VERTEX_SHADER);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call(s) failed.");
/* Create test program object */
m_po_id = gl.createProgram();
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed.");
/* Attach the shaders to the program object */
gl.attachShader(m_po_id, m_fs_id);
gl.attachShader(m_po_id, m_gs_id);
gl.attachShader(m_po_id, m_tc_id);
gl.attachShader(m_po_id, m_te_id);
gl.attachShader(m_po_id, m_vs_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call(s) failed.");
/* The test passes double-precision values through the whole rendering pipeline.
* This translates to a notable amount of components that we would need to transfer
* all values in one fell swoop. The number is large enough to exceed minimum
* capabilities as described for OpenGL 4.0 implementations.
* For that reason, the test executes in turns. Each turn is allocated as many
* double-precision scalar/matrix values as supported by the tested GL implementation.
*/
glw::GLint gl_max_fragment_input_components_value = 0;
glw::GLint gl_max_geometry_input_components_value = 0;
glw::GLint gl_max_geometry_output_components_value = 0;
glw::GLint gl_max_tess_control_input_components_value = 0;
glw::GLint gl_max_tess_control_output_components_value = 0;
glw::GLint gl_max_tess_evaluation_input_components_value = 0;
glw::GLint gl_max_tess_evaluation_output_components_value = 0;
glw::GLint gl_max_transform_feedback_interleaved_components_value = 0;
glw::GLint gl_max_vertex_output_components_value = 0;
gl.getIntegerv(GL_MAX_FRAGMENT_INPUT_COMPONENTS, &gl_max_fragment_input_components_value);
gl.getIntegerv(GL_MAX_GEOMETRY_INPUT_COMPONENTS, &gl_max_geometry_input_components_value);
gl.getIntegerv(GL_MAX_GEOMETRY_OUTPUT_COMPONENTS, &gl_max_geometry_output_components_value);
gl.getIntegerv(GL_MAX_TESS_CONTROL_INPUT_COMPONENTS, &gl_max_tess_control_input_components_value);
gl.getIntegerv(GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS, &gl_max_tess_control_output_components_value);
gl.getIntegerv(GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS, &gl_max_tess_evaluation_input_components_value);
gl.getIntegerv(GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS, &gl_max_tess_evaluation_output_components_value);
gl.getIntegerv(GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS,
&gl_max_transform_feedback_interleaved_components_value);
gl.getIntegerv(GL_MAX_VERTEX_OUTPUT_COMPONENTS, &gl_max_vertex_output_components_value);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetintegerv() call(s) failed.");
m_n_max_components_per_stage =
de::min(gl_max_vertex_output_components_value, gl_max_tess_control_input_components_value);
m_n_max_components_per_stage = de::min(m_n_max_components_per_stage, gl_max_fragment_input_components_value);
m_n_max_components_per_stage = de::min(m_n_max_components_per_stage, gl_max_geometry_input_components_value);
m_n_max_components_per_stage = de::min(m_n_max_components_per_stage, gl_max_geometry_output_components_value);
m_n_max_components_per_stage = de::min(m_n_max_components_per_stage, gl_max_tess_control_output_components_value);
m_n_max_components_per_stage = de::min(m_n_max_components_per_stage, gl_max_tess_evaluation_input_components_value);
m_n_max_components_per_stage =
de::min(m_n_max_components_per_stage, gl_max_tess_evaluation_output_components_value);
m_n_max_components_per_stage =
de::min(m_n_max_components_per_stage, gl_max_transform_feedback_interleaved_components_value);
/* Update GL_PATCH_VERTICES setting so that we only use a single vertex to build
* the input patch */
gl.patchParameteri(GL_PATCH_VERTICES, 1);
GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteri() call failed.");
/* Initialize a BO we will use to hold XFB data */
gl.genBuffers(1, &m_xfb_bo_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed.");
gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_xfb_bo_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed.");
gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, m_xfb_bo_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() call failed.");
}
/** Executes test iteration.
*
* @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
*/
tcu::TestNode::IterateResult GPUShaderFP64Test7::iterate()
{
/* Do not execute the test if GL_ARB_texture_view is not supported */
if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_gpu_shader_fp64"))
{
throw tcu::NotSupportedError("GL_ARB_gpu_shader_fp64 is not supported.");
}
if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_vertex_attrib_64bit"))
{
throw tcu::NotSupportedError("GL_ARB_vertex_attrib_64bit is not supported.");
}
/* Initialize GL objects required to run the test */
initTest();
/* Check the negative cases first */
const Utils::_variable_type double_variable_types[] = {
Utils::VARIABLE_TYPE_DOUBLE, Utils::VARIABLE_TYPE_DVEC2, Utils::VARIABLE_TYPE_DVEC3,
Utils::VARIABLE_TYPE_DVEC4, Utils::VARIABLE_TYPE_DMAT2, Utils::VARIABLE_TYPE_DMAT2X3,
Utils::VARIABLE_TYPE_DMAT2X4, Utils::VARIABLE_TYPE_DMAT3, Utils::VARIABLE_TYPE_DMAT3X2,
Utils::VARIABLE_TYPE_DMAT3X4, Utils::VARIABLE_TYPE_DMAT4, Utils::VARIABLE_TYPE_DMAT4X2,
Utils::VARIABLE_TYPE_DMAT4X3,
};
const unsigned int n_double_variable_types = sizeof(double_variable_types) / sizeof(double_variable_types[0]);
for (unsigned int n_double_variable_type = 0; n_double_variable_type < n_double_variable_types;
++n_double_variable_type)
{
for (unsigned int array_size = 1; array_size < 3; ++array_size)
{
Utils::_variable_type variable_type = double_variable_types[n_double_variable_type];
if (compileShader(m_fs_id, getCodeOfFragmentShaderWithDoublePrecisionOutput(variable_type, array_size)))
{
m_testCtx.getLog() << tcu::TestLog::Message
<< "A fragment shader with double-precision output variable compiled successfully."
<< tcu::TestLog::EndMessage;
m_has_test_passed = false;
}
if (compileShader(m_fs_id,
getCodeOfFragmentShaderWithNonFlatDoublePrecisionInput(variable_type, array_size)))
{
m_testCtx.getLog()
<< tcu::TestLog::Message
<< "A fragment shader with double-precision input variables lacking flat layout qualifier"
" compiled successfully."
<< tcu::TestLog::EndMessage;
m_has_test_passed = false;
}
}
} /* for (all variable types) */
/* Execute functional test. Split the run into as many iterations as necessary
* so that we do not exceed GL implementation's capabilities. */
unsigned int n_tested_variables = 0;
_variables variables_to_test;
while (n_tested_variables != n_double_variable_types * 2 /* arrayed & non-arrayed */)
{
glw::GLint total_n_used_components = 0;
/* Use as many variables as possible for the iterations. Do not exceed maximum amount
* of varying components that can be used for all shadr stages.
*/
while (total_n_used_components < m_n_max_components_per_stage &&
n_tested_variables != n_double_variable_types * 2 /* arrayed & non-arrayed */)
{
_variable new_variable;
unsigned int n_type_components = 0;
glw::GLint n_used_components = 0;
new_variable.array_size =
((n_tested_variables % 2) == 0) ? 1 /* non-arrayed variable */ : 2; /* arrayed variable */
new_variable.type = double_variable_types[n_tested_variables / 2];
/* Double-precision varyings can use twice as many components as single-precision FPs */
n_type_components = 4 /* components per location */ *
Utils::getNumberOfLocationsUsedByDoublePrecisionVariableType(new_variable.type);
n_used_components = n_type_components * new_variable.array_size * 2;
/* Do we have enough space? */
if (total_n_used_components + n_used_components > m_n_max_components_per_stage)
{
if (n_used_components > m_n_max_components_per_stage)
{ //if the number of components for this variable is larger than the max_components_per_stage, then skip it.
n_tested_variables++;
}
break;
}
/* We can safely test the type in current iteration */
total_n_used_components += n_used_components;
n_tested_variables++;
variables_to_test.push_back(new_variable);
}
if (variables_to_test.size() > 0)
{
m_has_test_passed &= executeFunctionalTest(variables_to_test);
variables_to_test.clear();
}
}
/* We're done */
if (m_has_test_passed)
{
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
}
else
{
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
}
return STOP;
}
/** Logs contents of test variables, as XFBed out by already executed test iteration. */
void GPUShaderFP64Test7::logVariableContents(const _variables& variables)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
std::stringstream log_sstream;
log_sstream << "Test variable values as retrieved from geometry shader:\n";
/* Map the XFB BO contents into process space */
const void* xfb_bo_data = gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBuffer() call failed.");
/* Read the variable contents. We only care about the set of varyings emitted
* for first vertex in the geometry shader */
unsigned int n_varying = 0;
const unsigned char* traveller_ptr = (const unsigned char*)xfb_bo_data;
for (_variables_const_iterator variables_iterator = variables.begin(); variables_iterator != variables.end();
++variables_iterator, ++n_varying)
{
const _variable& variable = *variables_iterator;
const Utils::_variable_type& base_variable_type = Utils::getBaseVariableType(variable.type);
const unsigned int n_components = Utils::getNumberOfComponentsForVariableType(variable.type);
for (unsigned int array_index = 0; array_index < variable.array_size; ++array_index)
{
log_sstream << "gs_variable" << n_varying;
if (variable.array_size > 1)
{
log_sstream << "[" << array_index << "]";
}
log_sstream << ": (";
for (unsigned int n_component = 0; n_component < n_components; ++n_component)
{
log_sstream << Utils::getStringForVariableTypeValue(base_variable_type, traveller_ptr);
if (n_component != (n_components - 1))
{
log_sstream << ", ";
}
traveller_ptr += sizeof(double);
}
log_sstream << ")\n";
} /* for (all array indices) */
} /* for (all variables) */
/* Unmap the BO */
gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed.");
/* Pass the logged stream into the framework */
m_testCtx.getLog() << tcu::TestLog::Message << log_sstream.str().c_str() << tcu::TestLog::EndMessage;
}
/** De-allocates an arary holding strings representing names of varyings that
* should be used for transform feed-back.
**/
void GPUShaderFP64Test7::releaseXFBVaryingNames()
{
for (unsigned int n_varying = 0; n_varying < m_n_xfb_varyings; ++n_varying)
{
delete[] m_xfb_varyings[n_varying];
}
delete[] m_xfb_varyings;
m_xfb_varyings = DE_NULL;
m_n_xfb_varyings = 0;
}
/** This function should only be called if GL_ARB_vertex_attrib_64bit extension is supported.
* Takes a list of test variables used for current iteration and assigns increasing values
* to subsequent input attributes of the test program.
*
* @param variables Test variables of the current iteration.
*/
void GPUShaderFP64Test7::setInputAttributeValues(const _variables& variables)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
unsigned int counter = 6;
for (_variables_const_iterator variable_iterator = variables.begin(); variable_iterator != variables.end();
variable_iterator++)
{
const _variable& variable = *variable_iterator;
const bool is_matrix_type = Utils::isMatrixVariableType(variable.type);
const unsigned int n_total_components = Utils::getNumberOfComponentsForVariableType(variable.type);
unsigned int n_components = 0;
unsigned int n_columns = 1;
if (is_matrix_type)
{
n_columns = Utils::getNumberOfColumnsForVariableType(variable.type);
n_components = n_total_components / n_columns;
DE_ASSERT(n_total_components % n_columns == 0);
}
else
{
n_components = n_total_components;
}
DE_ASSERT(n_components >= 1 && n_components <= 4);
for (unsigned int index = 0; index < n_columns * variable.array_size; ++index)
{
const double data[] = { -1, -1, -1, -1 };
switch (n_components)
{
case 1:
{
gl.vertexAttribL1dv(variable.attribute_location + index, data);
GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttrib1dv() call failed.");
break;
}
case 2:
{
gl.vertexAttribL2dv(variable.attribute_location + index, data);
GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttrib2dv() call failed.");
break;
}
case 3:
{
gl.vertexAttribL3dv(variable.attribute_location + index, data);
GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttrib3dv() call failed.");
break;
}
case 4:
{
gl.vertexAttribL4dv(variable.attribute_location + index, data);
GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttrib4dv() call failed.");
break;
}
default:
{
TCU_FAIL("Unrecognized number of components");
}
} /* switch (n_components) */
/* Make sure VAAs are disabled */
gl.disableVertexAttribArray(variable.attribute_location + index);
GLU_EXPECT_NO_ERROR(gl.getError(), "glDisableVertexAttribArray() call failed.");
counter += n_components;
} /* for (all array indices) */
} /* for (all variables) */
}
/** Constructor
*
* @param context Rendering context.
*/
GPUShaderFP64Test8::GPUShaderFP64Test8(deqp::Context& context)
: TestCase(context, "valid_constructors", "Verifies that valid double-precision floating-point constructors "
"are accepted during compilation stage")
, m_cs_id(0)
, m_fs_id(0)
, m_gs_id(0)
, m_tc_id(0)
, m_te_id(0)
, m_vs_id(0)
, m_has_test_passed(true)
{
}
/** Deinitializes all buffers and GL objects that may have been generated
* during test execution.
**/
void GPUShaderFP64Test8::deinit()
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
if (m_cs_id != 0)
{
gl.deleteShader(m_cs_id);
m_cs_id = 0;
}
if (m_fs_id != 0)
{
gl.deleteShader(m_fs_id);
m_fs_id = 0;
}
if (m_gs_id != 0)
{
gl.deleteShader(m_gs_id);
m_gs_id = 0;
}
if (m_tc_id != 0)
{
gl.deleteShader(m_tc_id);
m_tc_id = 0;
}
if (m_te_id != 0)
{
gl.deleteShader(m_te_id);
m_te_id = 0;
}
if (m_vs_id != 0)
{
gl.deleteShader(m_vs_id);
m_vs_id = 0;
}
}
/** Executes a single test case.
*
* This function can throw TestError exceptions if GL implementation reports
* an error.
*
* @param test_case Test case descriptor.
*
* @return true if test case passed, false otherwise.
**/
bool GPUShaderFP64Test8::executeIteration(const _test_case& test_case)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
const glw::GLuint so_ids[] = { m_cs_id, m_fs_id, m_gs_id, m_tc_id, m_te_id, m_vs_id };
const unsigned int n_so_ids = sizeof(so_ids) / sizeof(so_ids[0]);
bool result = true;
const char* stage_body = NULL;
const char* stage_name = NULL;
for (unsigned int n_so_id = 0; n_so_id < n_so_ids; ++n_so_id)
{
const glw::GLuint so_id = so_ids[n_so_id];
/* Skip compute shader if it is not supported */
if (0 == so_id)
{
continue;
}
/* Compile the shader */
gl.compileShader(so_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed.");
/* Has the compilation succeeded as expected? */
glw::GLint compile_status = GL_FALSE;
gl.getShaderiv(so_id, GL_COMPILE_STATUS, &compile_status);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed.");
if (compile_status == GL_FALSE)
{
/* What is the current stage's name? */
if (so_id == m_cs_id)
{
stage_body = test_case.cs_shader_body.c_str();
stage_name = "Compute shader";
}
else if (so_id == m_fs_id)
{
stage_body = test_case.fs_shader_body.c_str();
stage_name = "Fragment shader";
}
else if (so_id == m_gs_id)
{
stage_body = test_case.gs_shader_body.c_str();
stage_name = "Geometry shader";
}
else if (so_id == m_tc_id)
{
stage_body = test_case.tc_shader_body.c_str();
stage_name = "Tessellation control shader";
}
else if (so_id == m_te_id)
{
stage_body = test_case.te_shader_body.c_str();
stage_name = "Tessellation evaluation shader";
}
else if (so_id == m_vs_id)
{
stage_body = test_case.vs_shader_body.c_str();
stage_name = "Vertex shader";
}
else
{
/* Doesn't make much sense to throw exceptions here so.. */
stage_body = "";
stage_name = "[?]";
}
/* This shader should have never failed to compile! */
m_testCtx.getLog() << tcu::TestLog::Message << stage_name
<< " has not compiled successfully, even though the shader is valid."
" Following is shader's body:\n"
<< stage_body << tcu::TestLog::EndMessage;
result = false;
}
} /* for (all shader objects) */
return result;
}
/** Retrieves all argument lists that can be used to initialize a variable of user-specified
* type.
*
* @param variable_type Variable type to return valid argument lists for.
**/
GPUShaderFP64Test8::_argument_lists GPUShaderFP64Test8::getArgumentListsForVariableType(
const Utils::_variable_type& variable_type)
{
const Utils::_variable_type matrix_types[] = {
Utils::VARIABLE_TYPE_DMAT2, Utils::VARIABLE_TYPE_DMAT2X3, Utils::VARIABLE_TYPE_DMAT2X4,
Utils::VARIABLE_TYPE_DMAT3, Utils::VARIABLE_TYPE_DMAT3X2, Utils::VARIABLE_TYPE_DMAT3X4,
Utils::VARIABLE_TYPE_DMAT4, Utils::VARIABLE_TYPE_DMAT4X2, Utils::VARIABLE_TYPE_DMAT4X3,
};
const Utils::_variable_type scalar_types[] = { Utils::VARIABLE_TYPE_DOUBLE, Utils::VARIABLE_TYPE_DVEC2,
Utils::VARIABLE_TYPE_DVEC3, Utils::VARIABLE_TYPE_DVEC4 };
const unsigned int n_matrix_types = sizeof(matrix_types) / sizeof(matrix_types[0]);
const unsigned int n_scalar_types = sizeof(scalar_types) / sizeof(scalar_types[0]);
const int n_total_components = (int)Utils::getNumberOfComponentsForVariableType(variable_type);
/* Construct the argument list tree root. Each node carries a counter that tells how many components
* have already been assigned. Nodes that eat up all components are considered leaves and do not have
* any children. Otherwise, each node is assigned as many children, as there are types that could be
* used to define a subsequent argument, and its counter is increased by the amount of components
* described by the type.
*/
_argument_list_tree_node root;
root.n_components_used = 0;
root.parent = NULL;
root.type = variable_type;
/* Fill till all leaves use up all available components */
_argument_list_tree_node_queue nodes_queue;
nodes_queue.push(&root);
do
{
/* Pop the first item in the queue */
_argument_list_tree_node* current_node_ptr = nodes_queue.front();
nodes_queue.pop();
/* Matrix variable types can be defined by a combination of non-matrix variable types OR
* a single matrix variable type.
*
* Let's handle the latter case first.
*/
const int n_components_remaining = n_total_components - current_node_ptr->n_components_used;
if (Utils::isMatrixVariableType(current_node_ptr->type))
{
/* Iterate through all known matrix types. All the types can be used
* as a constructor, assuming only one value is used to define new matrix's
* contents. */
for (unsigned int n_matrix_type = 0; n_matrix_type < n_matrix_types; ++n_matrix_type)
{
Utils::_variable_type new_argument_type = matrix_types[n_matrix_type];
/* Construct a new child node. Since GLSL spec clearly states we must not use more
* than one constructor argument if the only argument is a matrix type, mark the node
* as if it defined all available components.
*/
_argument_list_tree_node* new_subnode = new _argument_list_tree_node;
new_subnode->n_components_used = n_total_components;
new_subnode->parent = current_node_ptr;
new_subnode->type = new_argument_type;
/* Add the descriptor to node list but do not add it to the queue. This would be
* a redundant operation, since no new children nodes would have been assigned to
* this node anyway.
*/
current_node_ptr->children.push_back(new_subnode);
} /* for (all matrix types) */
} /* if (current node's type is a matrix) */
/* Now for a combination of non-matrix variable types.. */
if (!Utils::isMatrixVariableType(current_node_ptr->type))
{
/* Iterate through all known scalar types */
for (unsigned int n_scalar_type = 0; n_scalar_type < n_scalar_types; ++n_scalar_type)
{
Utils::_variable_type new_argument_type = scalar_types[n_scalar_type];
const int n_new_argument_components = Utils::getNumberOfComponentsForVariableType(new_argument_type);
/* Only use the scalar type if we don't exceed the amount of components we can define
* for requested type.
*/
if (n_new_argument_components <= n_components_remaining)
{
/* Form new node descriptor */
_argument_list_tree_node* new_subnode = new _argument_list_tree_node;
new_subnode->n_components_used = n_new_argument_components + current_node_ptr->n_components_used;
new_subnode->parent = current_node_ptr;
new_subnode->type = new_argument_type;
current_node_ptr->children.push_back(new_subnode);
nodes_queue.push(new_subnode);
}
} /* for (all scalar types) */
} /* if (!Utils::isMatrixVariableType(current_node_ptr->type) ) */
} while (nodes_queue.size() > 0);
/* To construct the argument lists, traverse the tree. Each path from root to child
* gives us a single argument list.
*
* First, identify leaf nodes.
*/
_argument_list_tree_nodes leaf_nodes;
nodes_queue.push(&root);
do
{
_argument_list_tree_node* current_node_ptr = nodes_queue.front();
nodes_queue.pop();
if (current_node_ptr->children.size() == 0)
{
/* This is a leaf node !*/
leaf_nodes.push_back(current_node_ptr);
}
else
{
/* Throw all children nodes to the queue */
const unsigned int n_children_nodes = (unsigned int)current_node_ptr->children.size();
for (unsigned int n_children_node = 0; n_children_node < n_children_nodes; ++n_children_node)
{
nodes_queue.push(current_node_ptr->children[n_children_node]);
} /* for (all children nodes) */
}
} while (nodes_queue.size() > 0);
/* For all leaf nodes, move up the tree and construct the argument lists. */
const unsigned int n_leaf_nodes = (unsigned int)leaf_nodes.size();
_argument_lists result;
for (unsigned int n_leaf_node = 0; n_leaf_node < n_leaf_nodes; ++n_leaf_node)
{
_argument_list argument_list;
_argument_list_tree_node* current_node_ptr = leaf_nodes[n_leaf_node];
do
{
if (current_node_ptr != &root)
{
if (argument_list.size() == 0)
{
argument_list.push_back(current_node_ptr->type);
}
else
{
argument_list.insert(argument_list.begin(), current_node_ptr->type);
}
}
current_node_ptr = current_node_ptr->parent;
} while (current_node_ptr != NULL);
result.push_back(argument_list);
} /* for (all leaf nodes) */
return result;
}
/** Retrieves body of a compute shader that should be used for the purpose of
* user-specified test case.
*
* @param test_case Test case descriptor to use.
*
* @return Requested string.
**/
std::string GPUShaderFP64Test8::getComputeShaderBody(const _test_case& test_case)
{
std::stringstream result_sstream;
/* Form the body */
result_sstream << "#version 420\n"
"#extension GL_ARB_compute_shader : require\n"
"\n"
"layout(local_size_x = 1) in;\n"
"\n"
"void main()\n"
"{\n"
<< getGeneralBody(test_case) << "}\n";
/* Return the body */
return result_sstream.str();
}
/** Retrieves body of a fragment shader that should be used for the purpose of
* user-specified test case.
*
* @param test_case Test case descriptor to use.
*
* @return Requested string.
**/
std::string GPUShaderFP64Test8::getFragmentShaderBody(const _test_case& test_case)
{
std::stringstream result_sstream;
/* Form the body */
result_sstream << "#version 420\n"
"\n"
"void main()\n"
"{\n"
<< getGeneralBody(test_case) << "}\n"
"\n";
/* Return the body */
return result_sstream.str();
}
/** Returns a GLSL line that defines and initializes a variable as described by
* user-specified test case descriptor.
*
* @param test_case Test case descriptor to use for the query.
*
* @return As per description
**/
std::string GPUShaderFP64Test8::getGeneralBody(const _test_case& test_case)
{
std::stringstream result_sstream;
/* Form the body */
std::string variable_type_string = Utils::getVariableTypeString(test_case.type);
result_sstream << variable_type_string << " src = " << variable_type_string << "(";
for (_argument_list_const_iterator argument_list_iterator = test_case.argument_list.begin();
argument_list_iterator != test_case.argument_list.end(); argument_list_iterator++)
{
const Utils::_variable_type argument_variable_type = *argument_list_iterator;
std::string argument_variable_type_string = Utils::getVariableTypeString(argument_variable_type);
const unsigned int argument_n_components = Utils::getNumberOfComponentsForVariableType(argument_variable_type);
if (argument_list_iterator != test_case.argument_list.begin())
{
result_sstream << ", ";
}
result_sstream << argument_variable_type_string << "(";
for (unsigned int n_component = 0; n_component < argument_n_components; ++n_component)
{
result_sstream << (double)(n_component + 1);
if (n_component != (argument_n_components - 1))
{
result_sstream << ", ";
}
} /* for (all argument components) */
result_sstream << ")";
} /* for (all arguments) */
result_sstream << ");\n";
return result_sstream.str();
}
/** Retrieves body of a geometry shader that should be used for the purpose of
* user-specified test case.
*
* @param test_case Test case descriptor to use.
*
* @return Requested string.
**/
std::string GPUShaderFP64Test8::getGeometryShaderBody(const _test_case& test_case)
{
std::stringstream result_sstream;
/* Form the body */
result_sstream << "#version 420\n"
"\n"
"layout(points) in;\n"
"layout(max_vertices=1, points) out;\n"
"\n"
"void main()\n"
"{\n"
<< getGeneralBody(test_case) << "}\n"
"\n";
/* We're done! */
return result_sstream.str();
}
/** Retrieves body of a tesellation control shader that should be used for the purpose of
* user-specified test case.
*
* @param test_case Test case descriptor to use.
*
* @return Requested string.
**/
std::string GPUShaderFP64Test8::getTessellationControlShaderBody(const _test_case& test_case)
{
std::stringstream result_sstream;
/* Form the body */
result_sstream << "#version 420\n"
"\n"
"layout(vertices=4) out;\n"
"\n"
"void main()\n"
"{\n"
<< getGeneralBody(test_case) << "}\n"
"\n";
/* Return the body */
return result_sstream.str();
}
/** Retrieves body of a tessellation evaluation shader that should be used for the purpose of
* user-specified test case.
*
* @param test_case Test case descriptor to use.
*
* @return Requested string.
**/
std::string GPUShaderFP64Test8::getTessellationEvaluationShaderBody(const _test_case& test_case)
{
std::stringstream result_sstream;
/* Form the body */
result_sstream << "#version 420\n"
"\n"
"layout(isolines) in;\n"
"\n"
"void main()\n"
"{\n"
<< getGeneralBody(test_case) << "}\n"
"\n";
/* Return the body */
return result_sstream.str();
}
/** Retrieves body of a vertex shader that should be used for the purpose of
* user-specified test case.
*
* @param test_case Test case descriptor to use.
*
* @return Requested string.
**/
std::string GPUShaderFP64Test8::getVertexShaderBody(const _test_case& test_case)
{
std::stringstream result_sstream;
/* Form the body */
result_sstream << "#version 420\n"
"\n"
"void main()\n"
"{\n"
<< getGeneralBody(test_case) << "}\n"
"\n";
return result_sstream.str();
}
/** Initializes shader objects required to run the test. */
void GPUShaderFP64Test8::initTest()
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Generate shader objects */
/* Compute shader support and GL 4.2 required */
if ((true == m_context.getContextInfo().isExtensionSupported("GL_ARB_compute_shader")) &&
(true == Utils::isGLVersionAtLeast(gl, 4 /* major */, 2 /* minor */)))
{
m_cs_id = gl.createShader(GL_COMPUTE_SHADER);
}
m_fs_id = gl.createShader(GL_FRAGMENT_SHADER);
m_gs_id = gl.createShader(GL_GEOMETRY_SHADER);
m_tc_id = gl.createShader(GL_TESS_CONTROL_SHADER);
m_te_id = gl.createShader(GL_TESS_EVALUATION_SHADER);
m_vs_id = gl.createShader(GL_VERTEX_SHADER);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call(s) failed.");
}
/** Assigns shader bodies to all shader objects that will be used for a single iteration.
*
* @param test_case Test case descriptor to generate the shader bodies for.
**/
void GPUShaderFP64Test8::initIteration(_test_case& test_case)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
test_case.cs_shader_body = getComputeShaderBody(test_case);
test_case.fs_shader_body = getFragmentShaderBody(test_case);
test_case.gs_shader_body = getGeometryShaderBody(test_case);
test_case.tc_shader_body = getTessellationControlShaderBody(test_case);
test_case.te_shader_body = getTessellationEvaluationShaderBody(test_case);
test_case.vs_shader_body = getVertexShaderBody(test_case);
/* Assign the bodies to relevant shaders */
const char* cs_body_raw_ptr = test_case.cs_shader_body.c_str();
const char* fs_body_raw_ptr = test_case.fs_shader_body.c_str();
const char* gs_body_raw_ptr = test_case.gs_shader_body.c_str();
const char* tc_body_raw_ptr = test_case.tc_shader_body.c_str();
const char* te_body_raw_ptr = test_case.te_shader_body.c_str();
const char* vs_body_raw_ptr = test_case.vs_shader_body.c_str();
/* m_cs_id is initialized only if compute_shader is supported */
if (0 != m_cs_id)
{
gl.shaderSource(m_cs_id, 1 /* count */, &cs_body_raw_ptr, DE_NULL /* length */);
}
gl.shaderSource(m_fs_id, 1 /* count */, &fs_body_raw_ptr, DE_NULL /* length */);
gl.shaderSource(m_gs_id, 1 /* count */, &gs_body_raw_ptr, DE_NULL /* length */);
gl.shaderSource(m_tc_id, 1 /* count */, &tc_body_raw_ptr, DE_NULL /* length */);
gl.shaderSource(m_te_id, 1 /* count */, &te_body_raw_ptr, DE_NULL /* length */);
gl.shaderSource(m_vs_id, 1 /* count */, &vs_body_raw_ptr, DE_NULL /* length */);
GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call(s) failed.");
}
/** Executes test iteration.
*
* @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
*/
tcu::TestNode::IterateResult GPUShaderFP64Test8::iterate()
{
/* Do not execute the test if GL_ARB_texture_view is not supported */
if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_gpu_shader_fp64"))
{
throw tcu::NotSupportedError("GL_ARB_gpu_shader_fp64 is not supported.");
}
/* Initialize GL objects needed to run the tests */
initTest();
/* Build iteration array to run the tests in an automated manner */
const Utils::_variable_type variable_types[] = { Utils::VARIABLE_TYPE_DMAT2, Utils::VARIABLE_TYPE_DMAT2X3,
Utils::VARIABLE_TYPE_DMAT2X4, Utils::VARIABLE_TYPE_DMAT3,
Utils::VARIABLE_TYPE_DMAT3X2, Utils::VARIABLE_TYPE_DMAT3X4,
Utils::VARIABLE_TYPE_DMAT4, Utils::VARIABLE_TYPE_DMAT4X2,
Utils::VARIABLE_TYPE_DMAT4X3, Utils::VARIABLE_TYPE_DOUBLE,
Utils::VARIABLE_TYPE_DVEC2, Utils::VARIABLE_TYPE_DVEC3,
Utils::VARIABLE_TYPE_DVEC4 };
const unsigned int n_variable_types = sizeof(variable_types) / sizeof(variable_types[0]);
for (unsigned int n_variable_type = 0; n_variable_type < n_variable_types; ++n_variable_type)
{
const Utils::_variable_type variable_type = variable_types[n_variable_type];
/* Construct a set of argument lists valid for the variable type considered */
_argument_lists argument_lists = getArgumentListsForVariableType(variable_type);
for (_argument_lists_const_iterator argument_list_iterator = argument_lists.begin();
argument_list_iterator != argument_lists.end(); argument_list_iterator++)
{
/* Constructor thwe test case descriptor */
_test_case test_case;
test_case.argument_list = *argument_list_iterator;
test_case.type = variable_type;
/* Initialize a program object we will use to perform the casting */
initIteration(test_case);
/* See if the shader compiles. */
m_has_test_passed &= executeIteration(test_case);
} /* for (all argument lists) */
} /* for (all variable types) */
/* We're done */
if (m_has_test_passed)
{
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
}
else
{
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
}
return STOP;
}
/** Constructor.
*
* @param context Rendering context.
*
**/
GPUShaderFP64Test9::GPUShaderFP64Test9(deqp::Context& context)
: TestCase(context, "operators", "Verifies that general and relational operators work "
"correctly when used against double-precision floating-"
"point types.")
, m_has_test_passed(true)
, m_po_id(0)
, m_xfb_bo_id(0)
, m_vao_id(0)
, m_vs_id(0)
{
/* Left blank intentionally */
}
/** Deinitializes all ES objects that may have been created during
* test execution.
**/
void GPUShaderFP64Test9::deinit()
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
if (m_po_id != 0)
{
gl.deleteProgram(m_po_id);
m_po_id = 0;
}
if (m_xfb_bo_id != 0)
{
gl.deleteBuffers(1, &m_xfb_bo_id);
m_xfb_bo_id = 0;
}
if (m_vao_id != 0)
{
gl.deleteVertexArrays(1, &m_vao_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteVertexArrays() call failed.");
}
if (m_vs_id != 0)
{
gl.deleteShader(m_vs_id);
m_vs_id = 0;
}
}
/** Executes a single test iteration using user-specified test case properties.
*
* @param test_case Test case descriptor.
*
* @return true if the pass was successful, false if the test should fail.
**/
bool GPUShaderFP64Test9::executeTestIteration(const _test_case& test_case)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
bool result = true;
/* Activate the test program object */
gl.useProgram(m_po_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
/* Draw a single point with XFB enabled */
gl.beginTransformFeedback(GL_POINTS);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() call failed.");
{
gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed.");
}
gl.endTransformFeedback();
GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() call failed.");
/* Map the XFB BO into process space */
const void* xfb_data_ptr = gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBuffer() call failed.");
result = verifyXFBData(test_case, (const unsigned char*)xfb_data_ptr);
/* Unmap the BO */
gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed.");
return result;
}
/** Performs a matrix multiplication, given types of l-side and r-side matrices and stores the result
* under user-specified location.
*
* @param matrix_a_type Type of the l-side matrix.
* @param matrix_a_data Row-ordered data of l-side matrix.
* @param matrix_b_type Type of the r-side matrix.
* @param matrix_b_data Row-ordered data of r-side matrix.
* @param out_result_ptr Deref to be used to store the multiplication result.
**/
void GPUShaderFP64Test9::getMatrixMultiplicationResult(const Utils::_variable_type& matrix_a_type,
const std::vector<double>& matrix_a_data,
const Utils::_variable_type& matrix_b_type,
const std::vector<double>& matrix_b_data, double* out_result_ptr)
{
(void)matrix_b_type;
using namespace tcu;
/* To keep the code maintainable, we only consider cases relevant for this test */
switch (matrix_a_type)
{
case Utils::VARIABLE_TYPE_DMAT2:
{
DE_ASSERT(matrix_b_type == Utils::VARIABLE_TYPE_DMAT2);
tcu::Matrix2d matrix_a(&matrix_a_data[0]);
tcu::Matrix2d matrix_b(&matrix_b_data[0]);
tcu::Matrix2d result;
matrix_a = transpose(matrix_a);
matrix_b = transpose(matrix_b);
result = matrix_a * matrix_b;
memcpy(out_result_ptr, result.getColumnMajorData().getPtr(), sizeof(double) * 2 * 2);
break;
}
case Utils::VARIABLE_TYPE_DMAT2X3:
{
DE_ASSERT(matrix_b_type == Utils::VARIABLE_TYPE_DMAT3X2);
tcu::Matrix<double, 2, 3> matrix_a(&matrix_a_data[0]);
tcu::Matrix<double, 3, 2> matrix_a_transposed;
tcu::Matrix<double, 3, 2> matrix_b(&matrix_b_data[0]);
tcu::Matrix<double, 2, 3> matrix_b_transposed;
tcu::Matrix<double, 3, 3> result;
matrix_a_transposed = transpose(matrix_a);
matrix_b_transposed = transpose(matrix_b);
result = matrix_a_transposed * matrix_b_transposed;
memcpy(out_result_ptr, result.getColumnMajorData().getPtr(), sizeof(double) * 3 * 3);
break;
}
case Utils::VARIABLE_TYPE_DMAT2X4:
{
DE_ASSERT(matrix_b_type == Utils::VARIABLE_TYPE_DMAT4X2);
tcu::Matrix<double, 2, 4> matrix_a(&matrix_a_data[0]);
tcu::Matrix<double, 4, 2> matrix_a_transposed;
tcu::Matrix<double, 4, 2> matrix_b(&matrix_b_data[0]);
tcu::Matrix<double, 2, 4> matrix_b_transposed;
tcu::Matrix<double, 4, 4> result;
matrix_a_transposed = transpose(matrix_a);
matrix_b_transposed = transpose(matrix_b);
result = matrix_a_transposed * matrix_b_transposed;
memcpy(out_result_ptr, result.getColumnMajorData().getPtr(), sizeof(double) * 4 * 4);
break;
}
case Utils::VARIABLE_TYPE_DMAT3:
{
DE_ASSERT(matrix_b_type == Utils::VARIABLE_TYPE_DMAT3);
tcu::Matrix<double, 3, 3> matrix_a(&matrix_a_data[0]);
tcu::Matrix<double, 3, 3> matrix_b(&matrix_b_data[0]);
tcu::Matrix<double, 3, 3> result;
matrix_a = transpose(matrix_a);
matrix_b = transpose(matrix_b);
result = matrix_a * matrix_b;
memcpy(out_result_ptr, result.getColumnMajorData().getPtr(), sizeof(double) * 3 * 3);
break;
}
case Utils::VARIABLE_TYPE_DMAT3X2:
{
DE_ASSERT(matrix_b_type == Utils::VARIABLE_TYPE_DMAT2X3);
tcu::Matrix<double, 3, 2> matrix_a(&matrix_a_data[0]);
tcu::Matrix<double, 2, 3> matrix_a_transposed;
tcu::Matrix<double, 2, 3> matrix_b(&matrix_b_data[0]);
tcu::Matrix<double, 3, 2> matrix_b_transposed;
tcu::Matrix<double, 2, 2> result;
matrix_a_transposed = transpose(matrix_a);
matrix_b_transposed = transpose(matrix_b);
result = matrix_a_transposed * matrix_b_transposed;
memcpy(out_result_ptr, result.getColumnMajorData().getPtr(), sizeof(double) * 2 * 2);
break;
}
case Utils::VARIABLE_TYPE_DMAT3X4:
{
DE_ASSERT(matrix_b_type == Utils::VARIABLE_TYPE_DMAT4X3);
tcu::Matrix<double, 3, 4> matrix_a(&matrix_a_data[0]);
tcu::Matrix<double, 4, 3> matrix_a_transposed;
tcu::Matrix<double, 4, 3> matrix_b(&matrix_b_data[0]);
tcu::Matrix<double, 3, 4> matrix_b_transposed;
tcu::Matrix<double, 4, 4> result;
matrix_a_transposed = transpose(matrix_a);
matrix_b_transposed = transpose(matrix_b);
result = matrix_a_transposed * matrix_b_transposed;
memcpy(out_result_ptr, result.getColumnMajorData().getPtr(), sizeof(double) * 4 * 4);
break;
}
case Utils::VARIABLE_TYPE_DMAT4:
{
DE_ASSERT(matrix_b_type == Utils::VARIABLE_TYPE_DMAT4);
tcu::Matrix<double, 4, 4> matrix_a(&matrix_a_data[0]);
tcu::Matrix<double, 4, 4> matrix_b(&matrix_b_data[0]);
tcu::Matrix<double, 4, 4> result;
matrix_a = transpose(matrix_a);
matrix_b = transpose(matrix_b);
result = matrix_a * matrix_b;
memcpy(out_result_ptr, result.getColumnMajorData().getPtr(), sizeof(double) * 4 * 4);
break;
}
case Utils::VARIABLE_TYPE_DMAT4X2:
{
DE_ASSERT(matrix_b_type == Utils::VARIABLE_TYPE_DMAT2X4);
tcu::Matrix<double, 4, 2> matrix_a(&matrix_a_data[0]);
tcu::Matrix<double, 2, 4> matrix_a_transposed;
tcu::Matrix<double, 2, 4> matrix_b(&matrix_b_data[0]);
tcu::Matrix<double, 4, 2> matrix_b_transposed;
tcu::Matrix<double, 2, 2> result;
matrix_a_transposed = transpose(matrix_a);
matrix_b_transposed = transpose(matrix_b);
result = matrix_a_transposed * matrix_b_transposed;
memcpy(out_result_ptr, result.getColumnMajorData().getPtr(), sizeof(double) * 2 * 2);
break;
}
case Utils::VARIABLE_TYPE_DMAT4X3:
{
DE_ASSERT(matrix_b_type == Utils::VARIABLE_TYPE_DMAT3X4);
tcu::Matrix<double, 4, 3> matrix_a(&matrix_a_data[0]);
tcu::Matrix<double, 3, 4> matrix_a_transposed;
tcu::Matrix<double, 3, 4> matrix_b(&matrix_b_data[0]);
tcu::Matrix<double, 4, 3> matrix_b_transposed;
tcu::Matrix<double, 3, 3> result;
matrix_a_transposed = transpose(matrix_a);
matrix_b_transposed = transpose(matrix_b);
result = matrix_a_transposed * matrix_b_transposed;
memcpy(out_result_ptr, result.getColumnMajorData().getPtr(), sizeof(double) * 3 * 3);
break;
}
default:
{
TCU_FAIL("Unrecognized matrix A type");
}
} /* switch (matrix_a_type) */
}
/** Returns GLSL operator representation of the user-specified operation.
*
* @param operation_type Internal operation type to retrieve the operator for.
*
* @return As per description.
**/
const char* GPUShaderFP64Test9::getOperatorForOperationType(const _operation_type& operation_type)
{
const char* result = NULL;
switch (operation_type)
{
case OPERATION_TYPE_ADDITION:
result = "+";
break;
case OPERATION_TYPE_DIVISION:
result = "/";
break;
case OPERATION_TYPE_MULTIPLICATION:
result = "*";
break;
case OPERATION_TYPE_SUBTRACTION:
result = "-";
break;
case OPERATION_TYPE_PRE_DECREMENTATION:
case OPERATION_TYPE_POST_DECREMENTATION:
{
result = "--";
break;
}
case OPERATION_TYPE_PRE_INCREMENTATION:
case OPERATION_TYPE_POST_INCREMENTATION:
{
result = "++";
break;
}
default:
{
TCU_FAIL("Unrecognized operation type");
}
} /* switch(operation_type) */
return result;
}
/** Returns a string representing user-specified operation type.
*
* @param operation_type Operation type to return the literal for.
*
* @return Requested string.
**/
std::string GPUShaderFP64Test9::getOperationTypeString(const _operation_type& operation_type)
{
std::string result = "[?]";
switch (operation_type)
{
case OPERATION_TYPE_ADDITION:
result = "addition";
break;
case OPERATION_TYPE_DIVISION:
result = "division";
break;
case OPERATION_TYPE_MULTIPLICATION:
result = "multiplication";
break;
case OPERATION_TYPE_SUBTRACTION:
result = "subtraction";
break;
case OPERATION_TYPE_PRE_DECREMENTATION:
result = "pre-decrementation";
break;
case OPERATION_TYPE_PRE_INCREMENTATION:
result = "pre-incrementation";
break;
case OPERATION_TYPE_POST_DECREMENTATION:
result = "post-decrementation";
break;
case OPERATION_TYPE_POST_INCREMENTATION:
result = "post-incrementation";
break;
default:
{
TCU_FAIL("Unrecognized operation type");
}
}
return result;
}
/** Returns body of a vertex shader that should be used for user-specified test case
* descriptor.
*
* @param test_case Test case descriptor.
*
* @return Requested GLSL shader body.
**/
std::string GPUShaderFP64Test9::getVertexShaderBody(_test_case& test_case)
{
std::stringstream result_sstream;
std::string result_variable_type_string = Utils::getVariableTypeString(test_case.variable_type);
std::string variable_type_fp_string = Utils::getFPVariableTypeStringForVariableType(test_case.variable_type);
std::string variable_type_string = Utils::getVariableTypeString(test_case.variable_type);
const unsigned int n_variable_components = Utils::getNumberOfComponentsForVariableType(test_case.variable_type);
/* If we are to multiply matrices, we will need to use a different type
* for the result variable if either of the matrices is not square.
*/
if (test_case.operation_type == OPERATION_TYPE_MULTIPLICATION &&
Utils::isMatrixVariableType(test_case.variable_type))
{
Utils::_variable_type result_variable_type;
Utils::_variable_type transposed_matrix_variable_type =
Utils::getTransposedMatrixVariableType(test_case.variable_type);
result_variable_type =
Utils::getPostMatrixMultiplicationVariableType(test_case.variable_type, transposed_matrix_variable_type);
result_variable_type_string = Utils::getVariableTypeString(result_variable_type);
test_case.result_variable_type = result_variable_type;
}
/* Form the pre-amble */
result_sstream << "#version 400\n"
"\n"
/* Add output variables */
"out "
<< result_variable_type_string << " result;\n"
"out ivec2 result_lt;\n"
"out ivec2 result_lte;\n"
"out ivec2 result_gt;\n"
"out ivec2 result_gte;\n"
"void main()\n"
"{\n";
/* Form reference values */
result_sstream << variable_type_string << " reference1 = " << variable_type_string << "(";
for (unsigned int n_variable_component = 0; n_variable_component < n_variable_components; ++n_variable_component)
{
result_sstream << (n_variable_component + 1);
if (n_variable_component != (n_variable_components - 1))
{
result_sstream << ", ";
}
} /* for (all variable components) */
result_sstream << ");\n";
for (unsigned int n_ref2_case = 0; n_ref2_case < 2; /* single- and double-precision cases */
++n_ref2_case)
{
Utils::_variable_type compatible_variable_type = test_case.variable_type;
if (Utils::isMatrixVariableType(compatible_variable_type) &&
test_case.operation_type == OPERATION_TYPE_MULTIPLICATION)
{
compatible_variable_type = Utils::getTransposedMatrixVariableType(compatible_variable_type);
}
std::string ref2_variable_type_fp_string =
Utils::getFPVariableTypeStringForVariableType(compatible_variable_type);
std::string ref2_variable_type_string = Utils::getVariableTypeString(compatible_variable_type);
std::string ref2_variable_type = (n_ref2_case == 0) ? ref2_variable_type_fp_string : ref2_variable_type_string;
std::string ref2_variable_name = (n_ref2_case == 0) ? "reference2f" : "reference2";
result_sstream << ref2_variable_type << " " << ref2_variable_name << " = " << ref2_variable_type << "(";
for (unsigned int n_variable_component = 0; n_variable_component < n_variable_components;
++n_variable_component)
{
result_sstream << (n_variable_components - (n_variable_component + 1));
if (n_variable_component != (n_variable_components - 1))
{
result_sstream << ", ";
}
} /* for (all variable components) */
result_sstream << ");\n";
} /* for (both reference2 declarations) */
/* Add actual body */
result_sstream << "\n"
"result = ";
if (test_case.operation_type == OPERATION_TYPE_PRE_DECREMENTATION ||
test_case.operation_type == OPERATION_TYPE_PRE_INCREMENTATION)
{
result_sstream << getOperatorForOperationType(test_case.operation_type);
}
result_sstream << "reference1 ";
if (test_case.operation_type == OPERATION_TYPE_PRE_DECREMENTATION ||
test_case.operation_type == OPERATION_TYPE_PRE_INCREMENTATION ||
test_case.operation_type == OPERATION_TYPE_POST_DECREMENTATION ||
test_case.operation_type == OPERATION_TYPE_POST_INCREMENTATION)
{
if (test_case.operation_type == OPERATION_TYPE_POST_DECREMENTATION ||
test_case.operation_type == OPERATION_TYPE_POST_INCREMENTATION)
{
result_sstream << getOperatorForOperationType(test_case.operation_type);
}
}
else
{
result_sstream << getOperatorForOperationType(test_case.operation_type) << " reference2";
}
result_sstream << ";\n";
if (Utils::isScalarVariableType(test_case.variable_type))
{
result_sstream << "result_lt [0] = (reference1 < reference2) ? 1 : 0;\n"
"result_lt [1] = (reference1 < reference2f) ? 1 : 0;\n"
"result_lte[0] = (reference1 <= reference2) ? 1 : 0;\n"
"result_lte[1] = (reference1 <= reference2f) ? 1 : 0;\n"
"result_gt [0] = (reference1 > reference2) ? 1 : 0;\n"
"result_gt [1] = (reference1 > reference2f) ? 1 : 0;\n"
"result_gte[0] = (reference1 >= reference2) ? 1 : 0;\n"
"result_gte[1] = (reference1 >= reference2f) ? 1 : 0;\n";
}
else
{
result_sstream << "result_lt [0] = 1;\n"
"result_lt [1] = 1;\n"
"result_lte[0] = 1;\n"
"result_lte[1] = 1;\n"
"result_gt [0] = 1;\n"
"result_gt [1] = 1;\n"
"result_gte[0] = 1;\n"
"result_gte[1] = 1;\n";
}
result_sstream << "}\n";
/* All done */
return result_sstream.str();
}
/** Initializes all GL objects required to run the test.
*
* This function can throw a TestError exception if the implementation misbehaves.
*/
void GPUShaderFP64Test9::initTest()
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Create program & vertex shader objects */
m_po_id = gl.createProgram();
m_vs_id = gl.createShader(GL_VERTEX_SHADER);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() or glCreateShader() call failed.");
/* Attach the shader to the program */
gl.attachShader(m_po_id, m_vs_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call failed.");
/* Set up a buffer object */
gl.genBuffers(1, &m_xfb_bo_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed.");
gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_xfb_bo_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed.");
gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, m_xfb_bo_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() call failed.");
/* Set up a vertex array object */
gl.genVertexArrays(1, &m_vao_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays() call failed.");
gl.bindVertexArray(m_vao_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray() call failed.");
}
/** Initializes all GL objects required to run an iteration described by
* user-specified test case descriptor.
*
* @param test_case Test case descriptor to use for the initialization.
**/
void GPUShaderFP64Test9::initTestIteration(_test_case& test_case)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
std::string vs_body = getVertexShaderBody(test_case);
const char* vs_body_raw_ptr = vs_body.c_str();
/* Store the shader's body */
test_case.vs_body = vs_body;
/* Try to compile the shader */
glw::GLint compile_status = GL_FALSE;
gl.shaderSource(m_vs_id, 1 /* count */, &vs_body_raw_ptr, DE_NULL /* length */);
GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed.");
gl.compileShader(m_vs_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed.");
gl.getShaderiv(m_vs_id, GL_COMPILE_STATUS, &compile_status);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed.");
if (compile_status != GL_TRUE)
{
TCU_FAIL("Test shader compilation failed.");
}
/* Configure XFB */
const char* xfb_names[] = { "result", "result_lt", "result_lte", "result_gt", "result_gte" };
const unsigned int n_xfb_names = sizeof(xfb_names) / sizeof(xfb_names[0]);
gl.transformFeedbackVaryings(m_po_id, n_xfb_names, xfb_names, GL_INTERLEAVED_ATTRIBS);
GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() call failed.");
/* Try to link the program */
glw::GLint link_status = GL_FALSE;
gl.linkProgram(m_po_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed.");
gl.getProgramiv(m_po_id, GL_LINK_STATUS, &link_status);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed.");
if (link_status != GL_TRUE)
{
TCU_FAIL("Test program linking failure");
}
/* Set up XFB BO data storage */
const unsigned int result_variable_size = static_cast<unsigned int>(
Utils::getNumberOfComponentsForVariableType(test_case.result_variable_type) * sizeof(double));
const unsigned int xfb_bo_size = static_cast<unsigned int>(
result_variable_size + sizeof(int) * 2 /* ivec2s */ * 4); /* result_ output variables */
gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_bo_size, DE_NULL /* data */, GL_STATIC_DRAW);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call failed.");
}
/** Executes test iteration.
*
* @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
*/
tcu::TestNode::IterateResult GPUShaderFP64Test9::iterate()
{
/* Do not execute the test if GL_ARB_texture_view is not supported */
if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_gpu_shader_fp64"))
{
throw tcu::NotSupportedError("GL_ARB_gpu_shader_fp64 is not supported.");
}
/* Initialize all ES objects required to run all the checks */
initTest();
/* Iterate through all variable types we want to test */
const Utils::_variable_type variable_types[] = { Utils::VARIABLE_TYPE_DMAT2, Utils::VARIABLE_TYPE_DMAT2X3,
Utils::VARIABLE_TYPE_DMAT2X4, Utils::VARIABLE_TYPE_DMAT3,
Utils::VARIABLE_TYPE_DMAT3X2, Utils::VARIABLE_TYPE_DMAT3X4,
Utils::VARIABLE_TYPE_DMAT4, Utils::VARIABLE_TYPE_DMAT4X2,
Utils::VARIABLE_TYPE_DMAT4X3, Utils::VARIABLE_TYPE_DOUBLE,
Utils::VARIABLE_TYPE_DVEC2, Utils::VARIABLE_TYPE_DVEC3,
Utils::VARIABLE_TYPE_DVEC4 };
const unsigned int n_variable_types = sizeof(variable_types) / sizeof(variable_types[0]);
for (unsigned int n_variable_type = 0; n_variable_type < n_variable_types; ++n_variable_type)
{
/* Iterate through all operation types we want to check */
for (unsigned int n_operation_type = 0; n_operation_type < OPERATION_TYPE_COUNT; ++n_operation_type)
{
_operation_type operation_type = (_operation_type)n_operation_type;
const Utils::_variable_type& variable_type = variable_types[n_variable_type];
/* Construct test case descriptor */
_test_case test_case;
test_case.operation_type = operation_type;
test_case.result_variable_type = variable_type;
test_case.variable_type = variable_type;
/* Run the iteration */
initTestIteration(test_case);
m_has_test_passed &= executeTestIteration(test_case);
} /* for (all operation types) */
} /* for (all variable types) */
/* All done. */
if (m_has_test_passed)
{
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
}
else
{
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
}
return STOP;
}
/** Verifies data XFBed out by the draw call for user-specified test case
* descriptor.
*
* @param test_case Test case descriptor
* @param xfb_data Buffer holding the data XFBed out during the draw call.
* Must not be NULL.
*
* @return true if the data was found to be correct, false otherwise.
**/
bool GPUShaderFP64Test9::verifyXFBData(const _test_case& test_case, const unsigned char* xfb_data)
{
const double epsilon = 1e-5;
const unsigned int n_result_components =
Utils::getNumberOfComponentsForVariableType(test_case.result_variable_type);
bool result = true;
const double* xfb_data_result = (const double*)xfb_data;
const int* xfb_data_result_lt = (const int*)(xfb_data_result + n_result_components);
const int* xfb_data_result_lte = (const int*)xfb_data_result_lt + 2; /* cast/non-cast cases */
const int* xfb_data_result_gt = (const int*)xfb_data_result_lte + 2; /* cast/non-cast cases */
const int* xfb_data_result_gte = (const int*)xfb_data_result_gt + 2; /* cast/non-cast cases */
/* Prepare reference values */
int modifier;
std::vector<double> reference1;
std::vector<double> reference2;
if (test_case.operation_type == OPERATION_TYPE_PRE_INCREMENTATION ||
test_case.operation_type == OPERATION_TYPE_POST_INCREMENTATION)
{
modifier = 1;
}
else if (test_case.operation_type == OPERATION_TYPE_PRE_DECREMENTATION ||
test_case.operation_type == OPERATION_TYPE_POST_DECREMENTATION)
{
modifier = -1;
}
else
{
modifier = 0;
}
if (Utils::isMatrixVariableType(test_case.variable_type))
{
/* Matrices may be of different sizes so we need to compute the
* reference values separately for each matrix
*/
const Utils::_variable_type matrix_a_type = test_case.variable_type;
const Utils::_variable_type matrix_b_type = Utils::getTransposedMatrixVariableType(test_case.variable_type);
const unsigned int n_matrix_a_components = Utils::getNumberOfComponentsForVariableType(matrix_a_type);
const unsigned int n_matrix_b_components = Utils::getNumberOfComponentsForVariableType(matrix_b_type);
for (unsigned int n_component = 0; n_component < n_matrix_a_components; ++n_component)
{
reference1.push_back(modifier + n_component + 1);
}
for (unsigned int n_component = 0; n_component < n_matrix_b_components; ++n_component)
{
reference2.push_back(n_matrix_b_components - (n_component + 1));
}
} /* if (Utils::isMatrixVariableType(test_case.variable_type) */
else
{
/* Generate as many components as will be expected for the result variable */
for (unsigned int n_result_component = 0; n_result_component < n_result_components; ++n_result_component)
{
reference1.push_back(modifier + n_result_component + 1);
reference2.push_back(n_result_components - (n_result_component + 1));
}
}
/* Verify the result value(s) */
if (test_case.operation_type == OPERATION_TYPE_MULTIPLICATION &&
Utils::isMatrixVariableType(test_case.variable_type))
{
/* Matrix multiplication */
double expected_result_data[4 * 4];
Utils::_variable_type matrix_a_type = test_case.variable_type;
Utils::_variable_type matrix_b_type = Utils::getTransposedMatrixVariableType(test_case.variable_type);
getMatrixMultiplicationResult(matrix_a_type, reference1, matrix_b_type, reference2, expected_result_data);
for (unsigned int n_component = 0; n_component < n_result_components; ++n_component)
{
if (de::abs(xfb_data_result[n_component] - expected_result_data[n_component]) > epsilon)
{
std::stringstream log_sstream;
log_sstream << "Data returned for " << Utils::getVariableTypeString(matrix_a_type) << " * "
<< Utils::getVariableTypeString(matrix_b_type)
<< " matrix multiplication was incorrect; expected:(";
for (unsigned int n_logged_component = 0; n_logged_component < n_result_components;
++n_logged_component)
{
log_sstream << expected_result_data[n_logged_component];
if (n_logged_component != (n_result_components - 1))
{
log_sstream << ", ";
}
} /* for (all components to be logged) */
log_sstream << "), retrieved:(";
for (unsigned int n_logged_component = 0; n_logged_component < n_result_components;
++n_logged_component)
{
log_sstream << xfb_data_result[n_logged_component];
if (n_logged_component != (n_result_components - 1))
{
log_sstream << ", ";
}
} /* for (all components to be logged) */
log_sstream << ")";
m_testCtx.getLog() << tcu::TestLog::Message << log_sstream.str().c_str() << tcu::TestLog::EndMessage;
result = false;
break;
}
} /* for (all result components) */
} /* if (dealing with matrix multiplication) */
else
{
for (unsigned int n_component = 0; n_component < n_result_components; ++n_component)
{
double expected_value = reference1[n_component];
switch (test_case.operation_type)
{
case OPERATION_TYPE_ADDITION:
expected_value += reference2[n_component];
break;
case OPERATION_TYPE_DIVISION:
expected_value /= reference2[n_component];
break;
case OPERATION_TYPE_MULTIPLICATION:
expected_value *= reference2[n_component];
break;
case OPERATION_TYPE_SUBTRACTION:
expected_value -= reference2[n_component];
break;
case OPERATION_TYPE_PRE_DECREMENTATION:
case OPERATION_TYPE_PRE_INCREMENTATION:
{
/* Modifier already applied */
break;
}
case OPERATION_TYPE_POST_DECREMENTATION:
case OPERATION_TYPE_POST_INCREMENTATION:
{
/* Need to reverse the modification for the purpose of the following check */
expected_value -= modifier;
break;
}
default:
{
TCU_FAIL("Unrecognized operation type");
}
} /* switch (test_case.operation_type) */
if (de::abs(xfb_data_result[n_component] - expected_value) > epsilon)
{
std::string operation_type_string = getOperationTypeString(test_case.operation_type);
std::string variable_type_string = Utils::getVariableTypeString(test_case.variable_type);
m_testCtx.getLog() << tcu::TestLog::Message << "Value(s) generated for variable type ["
<< variable_type_string << "]"
" and operation type ["
<< operation_type_string << "]"
" were found invalid."
<< tcu::TestLog::EndMessage;
result = false;
break;
} /* if (test case failed) */
} /* for (all components) */
}
/* Verify the comparison operation results */
if (Utils::isScalarVariableType(test_case.variable_type))
{
DE_ASSERT(n_result_components == 1);
const bool expected_result_lt[2] = { reference1[0] < reference2[0], reference1[0] < (float)reference2[0] };
const bool expected_result_lte[2] = { reference1[0] <= reference2[0], reference1[0] <= (float)reference2[0] };
const bool expected_result_gt[2] = { reference1[0] > reference2[0], reference1[0] > (float)reference2[0] };
const bool expected_result_gte[2] = { reference1[0] >= reference2[0], reference1[0] >= (float)reference2[0] };
if ((xfb_data_result_lt[0] ? 1 : 0) != expected_result_lt[0] ||
(xfb_data_result_lt[1] ? 1 : 0) != expected_result_lt[1])
{
std::string operation_type_string = getOperationTypeString(test_case.operation_type);
std::string variable_type_string = Utils::getVariableTypeString(test_case.variable_type);
m_testCtx.getLog() << tcu::TestLog::Message << "Values reported for lower-than operator used for "
"variable type ["
<< variable_type_string << "]"
"and operation type ["
<< operation_type_string << "]"
"was found invalid; expected:("
<< expected_result_lt[0] << ", " << expected_result_lt[1] << "); found:("
<< xfb_data_result_lt[0] << ", " << xfb_data_result_lt[1] << ")."
<< tcu::TestLog::EndMessage;
result = false;
}
if ((xfb_data_result_lte[0] ? 1 : 0) != expected_result_lte[0] ||
(xfb_data_result_lte[1] ? 1 : 0) != expected_result_lte[1])
{
std::string operation_type_string = getOperationTypeString(test_case.operation_type);
std::string variable_type_string = Utils::getVariableTypeString(test_case.variable_type);
m_testCtx.getLog() << tcu::TestLog::Message << "Values reported for lower-than-or-equal operator used for "
"variable type ["
<< variable_type_string << "]"
"and operation type ["
<< operation_type_string << "]"
"was found invalid; expected:("
<< expected_result_lt[0] << ", " << expected_result_lt[1] << "); found:("
<< xfb_data_result_lt[0] << ", " << xfb_data_result_lt[1] << ")."
<< tcu::TestLog::EndMessage;
result = false;
}
if ((xfb_data_result_gt[0] ? 1 : 0) != expected_result_gt[0] ||
(xfb_data_result_gt[1] ? 1 : 0) != expected_result_gt[1])
{
std::string operation_type_string = getOperationTypeString(test_case.operation_type);
std::string variable_type_string = Utils::getVariableTypeString(test_case.variable_type);
m_testCtx.getLog() << tcu::TestLog::Message << "Values reported for greater-than operator used for "
"variable type ["
<< variable_type_string << "]"
"and operation type ["
<< operation_type_string << "]"
"was found invalid; expected:("
<< expected_result_lt[0] << ", " << expected_result_lt[1] << "); found:("
<< xfb_data_result_lt[0] << ", " << xfb_data_result_lt[1] << ")."
<< tcu::TestLog::EndMessage;
result = false;
}
if ((xfb_data_result_gte[0] ? 1 : 0) != expected_result_gte[0] ||
(xfb_data_result_gte[1] ? 1 : 0) != expected_result_gte[1])
{
std::string operation_type_string = getOperationTypeString(test_case.operation_type);
std::string variable_type_string = Utils::getVariableTypeString(test_case.variable_type);
m_testCtx.getLog() << tcu::TestLog::Message
<< "Values reported for greater-than-or-equal operator used for "
"variable type ["
<< variable_type_string << "]"
"and operation type ["
<< operation_type_string << "]"
"was found invalid; expected:("
<< expected_result_lt[0] << ", " << expected_result_lt[1] << "); found:("
<< xfb_data_result_lt[0] << ", " << xfb_data_result_lt[1] << ")."
<< tcu::TestLog::EndMessage;
result = false;
}
} /* if (Utils::isScalarVariableType(test_case.variable_type) ) */
else
{
if (xfb_data_result_lt[0] != 1 || xfb_data_result_lt[1] != 1 || xfb_data_result_lte[0] != 1 ||
xfb_data_result_lte[1] != 1 || xfb_data_result_gt[0] != 1 || xfb_data_result_gt[1] != 1 ||
xfb_data_result_gte[0] != 1 || xfb_data_result_gte[1] != 1)
{
std::string operation_type_string = getOperationTypeString(test_case.operation_type);
std::string variable_type_string = Utils::getVariableTypeString(test_case.variable_type);
m_testCtx.getLog() << tcu::TestLog::Message
<< "Invalid value was reported for matrix variable type, for which "
" operator checks are not executed; variable type ["
<< variable_type_string << "]"
"and operation type ["
<< operation_type_string << "]" << tcu::TestLog::EndMessage;
result = false;
}
}
return result;
}
namespace TypeHelpers
{
/** Get base type for reference types
*
* @tparam T type
**/
template <typename T>
class referenceToType
{
public:
typedef T result;
};
template <typename T>
class referenceToType<const T&>
{
public:
typedef T result;
};
/** Maps variable type with enumeration Utils::_variable_type
*
* @tparam T type
**/
template <typename T>
class typeInfo;
template <>
class typeInfo<glw::GLboolean>
{
public:
static const Utils::_variable_type variable_type = Utils::VARIABLE_TYPE_BOOL;
};
template <>
class typeInfo<glw::GLdouble>
{
public:
static const Utils::_variable_type variable_type = Utils::VARIABLE_TYPE_DOUBLE;
};
template <>
class typeInfo<tcu::UVec2>
{
public:
static const Utils::_variable_type variable_type = Utils::VARIABLE_TYPE_UVEC2;
};
template <>
class typeInfo<tcu::UVec3>
{
public:
static const Utils::_variable_type variable_type = Utils::VARIABLE_TYPE_UVEC3;
};
template <>
class typeInfo<tcu::UVec4>
{
public:
static const Utils::_variable_type variable_type = Utils::VARIABLE_TYPE_UVEC4;
};
template <>
class typeInfo<tcu::DVec2>
{
public:
static const Utils::_variable_type variable_type = Utils::VARIABLE_TYPE_DVEC2;
};
template <>
class typeInfo<tcu::DVec3>
{
public:
static const Utils::_variable_type variable_type = Utils::VARIABLE_TYPE_DVEC3;
};
template <>
class typeInfo<tcu::DVec4>
{
public:
static const Utils::_variable_type variable_type = Utils::VARIABLE_TYPE_DVEC4;
};
template <>
class typeInfo<tcu::Matrix<glw::GLdouble, 2, 2> >
{
public:
static const Utils::_variable_type variable_type = Utils::VARIABLE_TYPE_DMAT2;
};
template <>
class typeInfo<tcu::Matrix<glw::GLdouble, 3, 2> >
{
public:
static const Utils::_variable_type variable_type = Utils::VARIABLE_TYPE_DMAT2X3;
};
template <>
class typeInfo<tcu::Matrix<glw::GLdouble, 4, 2> >
{
public:
static const Utils::_variable_type variable_type = Utils::VARIABLE_TYPE_DMAT2X4;
};
template <>
class typeInfo<tcu::Matrix<glw::GLdouble, 3, 3> >
{
public:
static const Utils::_variable_type variable_type = Utils::VARIABLE_TYPE_DMAT3;
};
template <>
class typeInfo<tcu::Matrix<glw::GLdouble, 2, 3> >
{
public:
static const Utils::_variable_type variable_type = Utils::VARIABLE_TYPE_DMAT3X2;
};
template <>
class typeInfo<tcu::Matrix<glw::GLdouble, 4, 3> >
{
public:
static const Utils::_variable_type variable_type = Utils::VARIABLE_TYPE_DMAT3X4;
};
template <>
class typeInfo<tcu::Matrix<glw::GLdouble, 4, 4> >
{
public:
static const Utils::_variable_type variable_type = Utils::VARIABLE_TYPE_DMAT4;
};
template <>
class typeInfo<tcu::Matrix<glw::GLdouble, 2, 4> >
{
public:
static const Utils::_variable_type variable_type = Utils::VARIABLE_TYPE_DMAT4X2;
};
template <>
class typeInfo<tcu::Matrix<glw::GLdouble, 3, 4> >
{
public:
static const Utils::_variable_type variable_type = Utils::VARIABLE_TYPE_DMAT4X3;
};
} /* TypeHelpers */
/** Implementations of "math" functions required by "GPUShaderFP64Test10"
*
**/
namespace Math
{
template <typename T>
static T clamp(T x, T minVal, T maxVal);
template <int Size>
static tcu::Matrix<glw::GLdouble, Size, Size> cofactors(const tcu::Matrix<glw::GLdouble, Size, Size>& matrix);
template <int Size>
static tcu::Vector<glw::GLuint, Size> convertBvecToUvec(const tcu::Vector<bool, Size>& src);
template <typename T>
static T determinant(T val);
template <typename T>
static T determinant(const tcu::Matrix<T, 2, 2>& mat);
template <typename T>
static T determinant(const tcu::Matrix<T, 3, 3>& mat);
template <typename T>
static T determinant(const tcu::Matrix<T, 4, 4>& mat);
template <int Size>
static tcu::Matrix<glw::GLdouble, Size - 1, Size - 1> eliminate(const tcu::Matrix<glw::GLdouble, Size, Size>& matrix,
glw::GLuint column, glw::GLuint row);
template <int Size>
static tcu::Vector<glw::GLuint, Size> equal(const tcu::Vector<glw::GLdouble, Size>& left,
const tcu::Vector<glw::GLdouble, Size>& right);
static glw::GLdouble fma(glw::GLdouble a, glw::GLdouble b, glw::GLdouble c);
static glw::GLdouble fract(glw::GLdouble val);
template <typename T>
static T frexp(T val, glw::GLint& exp);
template <int Size>
static tcu::Vector<glw::GLuint, Size> greaterThan(const tcu::Vector<glw::GLdouble, Size>& left,
const tcu::Vector<glw::GLdouble, Size>& right);
template <int Size>
static tcu::Vector<glw::GLuint, Size> greaterThanEqual(const tcu::Vector<glw::GLdouble, Size>& left,
const tcu::Vector<glw::GLdouble, Size>& right);
template <int Size>
static tcu::Matrix<glw::GLdouble, Size, Size> inverse(const tcu::Matrix<glw::GLdouble, Size, Size>& matrix);
static glw::GLdouble inverseSqrt(glw::GLdouble val);
static glw::GLuint isinf_impl(glw::GLdouble val);
static glw::GLuint isnan_impl(glw::GLdouble val);
template <typename T>
static T ldexp(T val, glw::GLint exp);
template <int Size>
static tcu::Vector<glw::GLuint, Size> lessThan(const tcu::Vector<glw::GLdouble, Size>& left,
const tcu::Vector<glw::GLdouble, Size>& right);
template <int Size>
static tcu::Vector<glw::GLuint, Size> lessThanEqual(const tcu::Vector<glw::GLdouble, Size>& left,
const tcu::Vector<glw::GLdouble, Size>& right);
template <typename T>
static T max(T left, T right);
template <typename T>
static T min(T left, T right);
template <int Size>
static glw::GLdouble minor_impl(const tcu::Matrix<glw::GLdouble, Size, Size>& matrix, glw::GLuint column,
glw::GLuint row);
template <typename T>
static T mix(T left, T right, T weight);
template <typename T>
static T mod(T left, T right);
template <typename T>
static T modf(T val, T& integer);
template <typename T>
static T multiply(T left, T right);
template <int Size>
static tcu::Vector<glw::GLuint, Size> notEqual(const tcu::Vector<glw::GLdouble, Size>& left,
const tcu::Vector<glw::GLdouble, Size>& right);
template <int Cols, int Rows>
static tcu::Matrix<glw::GLdouble, Rows, Cols> outerProduct(const tcu::Vector<glw::GLdouble, Rows>& left,
const tcu::Vector<glw::GLdouble, Cols>& right);
static glw::GLdouble packDouble2x32(const tcu::UVec2& in);
template <typename T>
static T round(T t);
template <typename T>
static T roundEven(T t);
template <typename T>
static T sign(T t);
template <typename T>
static T smoothStep(T e0, T e1, T val);
template <typename T>
static T step(T edge, T val);
template <typename T, int Rows, int Cols>
static tcu::Matrix<T, Cols, Rows> transpose(const tcu::Matrix<T, Rows, Cols>& matrix);
template <typename T>
static T trunc(T t);
static tcu::UVec2 unpackDouble2x32(const glw::GLdouble& val);
template <typename T>
static T clamp(T x, T minVal, T maxVal)
{
return min(max(x, minVal), maxVal);
}
template <int Size>
static tcu::Matrix<glw::GLdouble, Size, Size> cofactors(const tcu::Matrix<glw::GLdouble, Size, Size>& matrix)
{
tcu::Matrix<glw::GLdouble, Size, Size> result;
for (glw::GLuint c = 0; c < Size; ++c)
{
for (glw::GLuint r = 0; r < Size; ++r)
{
const glw::GLdouble minor_value = minor_impl(matrix, c, r);
result(r, c) = (1 == (c + r) % 2) ? -minor_value : minor_value;
}
}
return result;
}
template <int Size>
static tcu::Vector<glw::GLuint, Size> convertBvecToUvec(const tcu::Vector<bool, Size>& src)
{
tcu::Vector<glw::GLuint, Size> result;
for (glw::GLint i = 0; i < Size; ++i)
{
if (GL_FALSE != src[i])
{
result[i] = 1;
}
else
{
result[i] = 0;
}
}
return result;
}
template <typename T>
static T det2(T _00, T _10, T _01, T _11)
{
return _00 * _11 - _01 * _10;
}
template <typename T>
static T det3(T _00, T _10, T _20, T _01, T _11, T _21, T _02, T _12, T _22)
{
return _00 * det2(_11, _21, _12, _22) - _10 * det2(_01, _21, _02, _22) + _20 * det2(_01, _11, _02, _12);
}
template <typename T>
static T det4(T _00, T _10, T _20, T _30, T _01, T _11, T _21, T _31, T _02, T _12, T _22, T _32, T _03, T _13, T _23,
T _33)
{
return _00 * det3(_11, _21, _31, _12, _22, _32, _13, _23, _33) -
_10 * det3(_01, _21, _31, _02, _22, _32, _03, _23, _33) +
_20 * det3(_01, _11, _31, _02, _12, _32, _03, _13, _33) -
_30 * det3(_01, _11, _21, _02, _12, _22, _03, _13, _23);
}
template <typename T>
static T determinant(T val)
{
return val;
}
template <typename T>
static T determinant(const tcu::Matrix<T, 2, 2>& mat)
{
return det2(mat(0, 0), mat(0, 1), mat(1, 0), mat(1, 1));
}
template <typename T>
static T determinant(const tcu::Matrix<T, 3, 3>& mat)
{
return det3(mat(0, 0), mat(0, 1), mat(0, 2), mat(1, 0), mat(1, 1), mat(1, 2), mat(2, 0), mat(2, 1), mat(2, 2));
}
template <typename T>
static T determinant(const tcu::Matrix<T, 4, 4>& mat)
{
return det4(mat(0, 0), mat(0, 1), mat(0, 2), mat(0, 3), mat(1, 0), mat(1, 1), mat(1, 2), mat(1, 3), mat(2, 0),
mat(2, 1), mat(2, 2), mat(2, 3), mat(3, 0), mat(3, 1), mat(3, 2), mat(3, 3));
}
template <int Size>
static tcu::Matrix<glw::GLdouble, Size - 1, Size - 1> eliminate(const tcu::Matrix<glw::GLdouble, Size, Size>& matrix,
glw::GLuint column, glw::GLuint row)
{
tcu::Matrix<glw::GLdouble, Size - 1, Size - 1> result;
for (glw::GLuint c = 0; c < Size; ++c)
{
/* Skip eliminated column */
if (column == c)
{
continue;
}
for (glw::GLuint r = 0; r < Size; ++r)
{
/* Skip eliminated row */
if (row == r)
{
continue;
}
const glw::GLint r_offset = (r > row) ? -1 : 0;
const glw::GLint c_offset = (c > column) ? -1 : 0;
result(r + r_offset, c + c_offset) = matrix(r, c);
}
}
return result;
}
template <int Size>
static tcu::Vector<glw::GLuint, Size> equal(const tcu::Vector<glw::GLdouble, Size>& left,
const tcu::Vector<glw::GLdouble, Size>& right)
{
return convertBvecToUvec(tcu::equal(left, right));
}
static glw::GLdouble fma(glw::GLdouble a, glw::GLdouble b, glw::GLdouble c)
{
return a * b + c;
}
static glw::GLdouble fract(glw::GLdouble val)
{
return val - floor(val);
}
template <typename T>
static T frexp(T val, glw::GLint& exp)
{
return ::frexp(val, &exp);
}
template <int Size>
static tcu::Vector<glw::GLuint, Size> greaterThan(const tcu::Vector<glw::GLdouble, Size>& left,
const tcu::Vector<glw::GLdouble, Size>& right)
{
return convertBvecToUvec(tcu::greaterThan(left, right));
}
template <int Size>
static tcu::Vector<glw::GLuint, Size> greaterThanEqual(const tcu::Vector<glw::GLdouble, Size>& left,
const tcu::Vector<glw::GLdouble, Size>& right)
{
return convertBvecToUvec(tcu::greaterThanEqual(left, right));
}
template <int Size>
static tcu::Matrix<glw::GLdouble, Size, Size> inverse(const tcu::Matrix<glw::GLdouble, Size, Size>& matrix)
{
const tcu::Matrix<glw::GLdouble, Size, Size> cof = cofactors(matrix);
const tcu::Matrix<glw::GLdouble, Size, Size> adjugate = tcu::transpose(cof);
const glw::GLdouble det = determinant(matrix);
const glw::GLdouble inv_det = 1.0 / det;
tcu::Matrix<glw::GLdouble, Size, Size> result = adjugate * inv_det;
return result;
}
static glw::GLdouble inverseSqrt(glw::GLdouble val)
{
const glw::GLdouble root = sqrt(val);
return (1.0 / root);
}
static glw::GLuint isinf_impl(glw::GLdouble val)
{
const glw::GLdouble infinity = std::numeric_limits<glw::GLdouble>::infinity();
return ((infinity == val) || (-infinity == val));
}
static glw::GLuint isnan_impl(glw::GLdouble val)
{
return val != val;
}
template <typename T>
static T ldexp(T val, glw::GLint exp)
{
return ::ldexp(val, exp);
}
template <int Size>
static tcu::Vector<glw::GLuint, Size> lessThan(const tcu::Vector<glw::GLdouble, Size>& left,
const tcu::Vector<glw::GLdouble, Size>& right)
{
return convertBvecToUvec(tcu::lessThan(left, right));
}
template <int Size>
static tcu::Vector<glw::GLuint, Size> lessThanEqual(const tcu::Vector<glw::GLdouble, Size>& left,
const tcu::Vector<glw::GLdouble, Size>& right)
{
return convertBvecToUvec(tcu::lessThanEqual(left, right));
}
template <typename T>
static T max(T left, T right)
{
return (left >= right) ? left : right;
}
template <typename T>
static T min(T left, T right)
{
return (left <= right) ? left : right;
}
template <int Size>
static glw::GLdouble minor_impl(const tcu::Matrix<glw::GLdouble, Size, Size>& matrix, glw::GLuint column,
glw::GLuint row)
{
tcu::Matrix<glw::GLdouble, Size - 1, Size - 1> eliminated = eliminate(matrix, column, row);
return determinant(eliminated);
}
template <>
glw::GLdouble minor_impl<2>(const tcu::Matrix<glw::GLdouble, 2, 2>& matrix, glw::GLuint column, glw::GLuint row)
{
const glw::GLuint r = (0 == row) ? 1 : 0;
const glw::GLuint c = (0 == column) ? 1 : 0;
return matrix(r, c);
}
template <typename T>
static T mix(T left, T right, T weight)
{
return left * (1 - weight) + right * (weight);
}
template <typename T>
static T mod(T left, T right)
{
const T div_res = left / right;
const T floored = floor(div_res);
return left - right * floored;
}
template <typename T>
static T modf(T val, T& integer)
{
return ::modf(val, &integer);
}
template <typename T>
static T multiply(T left, T right)
{
T result = left * right;
return result;
}
template <int Size>
static tcu::Vector<glw::GLuint, Size> notEqual(const tcu::Vector<glw::GLdouble, Size>& left,
const tcu::Vector<glw::GLdouble, Size>& right)
{
return convertBvecToUvec(tcu::notEqual(left, right));
}
template <int Cols, int Rows>
static tcu::Matrix<glw::GLdouble, Rows, Cols> outerProduct(const tcu::Vector<glw::GLdouble, Rows>& left,
const tcu::Vector<glw::GLdouble, Cols>& right)
{
tcu::Matrix<glw::GLdouble, Rows, 1> left_mat;
tcu::Matrix<glw::GLdouble, 1, Cols> right_mat;
tcu::Matrix<glw::GLdouble, Rows, Cols> result;
for (glw::GLuint i = 0; i < Rows; ++i)
{
left_mat(i, 0) = left[i];
}
for (glw::GLuint i = 0; i < Cols; ++i)
{
right_mat(0, i) = right[i];
}
result = left_mat * right_mat;
return result;
}
static glw::GLdouble packDouble2x32(const tcu::UVec2& in)
{
const glw::GLuint buffer[2] = { in[0], in[1] };
glw::GLdouble result;
memcpy(&result, buffer, sizeof(result));
return result;
}
template <typename T>
static T round(T t)
{
T frac = fract(t);
T res = t - frac;
if (((T)0.5) < frac)
{
res += ((T)1.0);
}
return res;
}
template <typename T>
static T roundEven(T t)
{
T frac = fract(t);
T res = t - frac;
if (((T)0.5) < frac)
{
res += ((T)1.0);
}
else if ((((T)0.5) == frac) && (0 != ((int)res) % 2))
{
res += ((T)1.0);
}
return res;
}
template <typename T>
static T sign(T t)
{
if (0 > t)
{
return -1;
}
else if (0 == t)
{
return 0;
}
else
{
return 1;
}
}
template <typename T>
static T smoothStep(T e0, T e1, T val)
{
if (e0 >= val)
{
return 0;
}
if (e1 <= val)
{
return 1;
}
T temp = (val - e0) / (e1 - e0);
T result = temp * temp * (3 - 2 * temp);
return result;
}
template <typename T>
static T step(T edge, T val)
{
if (edge > val)
{
return 0;
}
else
{
return 1;
}
}
template <typename T, int Rows, int Cols>
static tcu::Matrix<T, Cols, Rows> transpose(const tcu::Matrix<T, Rows, Cols>& matrix)
{
tcu::Matrix<T, Cols, Rows> result = tcu::transpose(matrix);
return result;
}
template <typename T>
static T trunc(T t)
{
const T abs_value = de::abs(t);
const T result_value = floor(abs_value);
const T result = sign(t) * result_value;
return result;
}
static tcu::UVec2 unpackDouble2x32(const glw::GLdouble& val)
{
glw::GLuint* ptr = (glw::GLuint*)&val;
tcu::UVec2 result(ptr[0], ptr[1]);
return result;
}
} /* Math */
/** Enumeration of tested functions
* *_AGAINT_SCALAR enums are used to call glsl function with mixed scalar and genDType arguments.
* For example "max" can be called for (dvec3, double).
**/
enum FunctionEnum
{
FUNCTION_ABS = 0,
FUNCTION_CEIL,
FUNCTION_CLAMP,
FUNCTION_CLAMP_AGAINST_SCALAR,
FUNCTION_CROSS,
FUNCTION_DETERMINANT,
FUNCTION_DISTANCE,
FUNCTION_DOT,
FUNCTION_EQUAL,
FUNCTION_FACEFORWARD,
FUNCTION_FLOOR,
FUNCTION_FMA,
FUNCTION_FRACT,
FUNCTION_FREXP,
FUNCTION_GREATERTHAN,
FUNCTION_GREATERTHANEQUAL,
FUNCTION_INVERSE,
FUNCTION_INVERSESQRT,
FUNCTION_LDEXP,
FUNCTION_LESSTHAN,
FUNCTION_LESSTHANEQUAL,
FUNCTION_LENGTH,
FUNCTION_MATRIXCOMPMULT,
FUNCTION_MAX,
FUNCTION_MAX_AGAINST_SCALAR,
FUNCTION_MIN,
FUNCTION_MIN_AGAINST_SCALAR,
FUNCTION_MIX,
FUNCTION_MOD,
FUNCTION_MOD_AGAINST_SCALAR,
FUNCTION_MODF,
FUNCTION_NORMALIZE,
FUNCTION_NOTEQUAL,
FUNCTION_OUTERPRODUCT,
FUNCTION_PACKDOUBLE2X32,
FUNCTION_REFLECT,
FUNCTION_REFRACT,
FUNCTION_ROUND,
FUNCTION_ROUNDEVEN,
FUNCTION_SIGN,
FUNCTION_SMOOTHSTEP,
FUNCTION_SMOOTHSTEP_AGAINST_SCALAR,
FUNCTION_SQRT,
FUNCTION_STEP,
FUNCTION_STEP_AGAINST_SCALAR,
FUNCTION_TRANSPOSE,
FUNCTION_TRUNC,
FUNCTION_UNPACKDOUBLE2X32,
FUNCTION_ISNAN,
FUNCTION_ISINF,
};
struct TypeDefinition
{
std::string name;
glw::GLuint n_columns;
glw::GLuint n_rows;
};
/** Implementation of BuiltinFunctionTest test, description follows:
*
* Verify double-precision support in common functions works correctly.
* All double-precision types that apply for particular cases should
* be tested for the following functions:
*
* - abs();
* - ceil();
* - clamp();
* - cross();
* - determinant();
* - distance();
* - dot();
* - equal();
* - faceforward();
* - floor();
* - fma();
* - fract();
* - frexp();
* - greaterThan();
* - greaterThanEqual();
* - inverse();
* - inversesqrt();
* - ldexp();
* - lessThan();
* - lessThanEqual();
* - length();
* - matrixCompMult();
* - max();
* - min();
* - mix();
* - mod();
* - modf();
* - normalize();
* - notEqual();
* - outerProduct();
* - packDouble2x32();
* - reflect();
* - refract();
* - round();
* - roundEven();
* - sign();
* - smoothstep();
* - sqrt();
* - step();
* - transpose();
* - trunc();
* - unpackDouble2x32();
* - isnan();
* - isinf();
*
* The test should work by creating a program object (for each case
* considered), to which a vertex shader should be attached. The
* shader should define input variables that should be used as
* arguments for the function in question. The result of the
* operation should then be XFBed back to the test, where the
* value should be verified.
*
* Reference function implementation from pre-DEQP CTS framework
* should be ported to C for verification purposes where available.
*
* The test should use 1024 different scalar/vector/matrix argument
* combinations. It should pass if all functions are determined
* to work correctly for all argument combinations used.
**/
class BuiltinFunctionTest : public deqp::TestCase
{
public:
/* Public methods */
BuiltinFunctionTest(deqp::Context& context, std::string caseName, FunctionEnum function,
TypeDefinition typeDefinition);
virtual void deinit();
virtual tcu::TestNode::IterateResult iterate();
/** Base class of functionObject. Main goal of it is to keep function details toghether and hide calling code.
*
**/
class functionObject
{
public:
functionObject(FunctionEnum function_enum, const glw::GLchar* function_name, glw::GLvoid* function_pointer,
Utils::_variable_type result_type);
virtual ~functionObject()
{
}
virtual void call(glw::GLvoid* result_dst, const glw::GLvoid* argument_src) const = 0;
virtual glw::GLuint getArgumentCount() const = 0;
virtual Utils::_variable_type getArgumentType(glw::GLuint argument) const = 0;
glw::GLuint getArgumentComponents(glw::GLuint argument) const;
glw::GLuint getArgumentComponentSize(glw::GLuint argument) const;
glw::GLuint getArgumentOffset(glw::GLuint argument) const;
glw::GLuint getArgumentStride() const;
glw::GLuint getArgumentStride(glw::GLuint argument) const;
FunctionEnum getFunctionEnum() const;
const glw::GLchar* getName() const;
glw::GLuint getResultComponents(glw::GLuint result) const;
virtual glw::GLuint getResultCount() const;
glw::GLuint getResultOffset(glw::GLuint result) const;
virtual Utils::_variable_type getResultType(glw::GLuint result) const;
glw::GLuint getResultStride(glw::GLuint result) const;
glw::GLuint getBaseTypeSize(glw::GLuint result) const;
glw::GLuint getResultStride() const;
protected:
const FunctionEnum m_function_enum;
const glw::GLchar* m_function_name;
const glw::GLvoid* m_p_function;
const Utils::_variable_type m_res_type;
};
private:
/* Private types */
/** General type enumeration
*
**/
enum generalType
{
SCALAR = 0,
VECTOR,
MATRIX,
};
/** Details of variable type
*
**/
struct typeDetails
{
typeDetails(glw::GLuint n_columns, glw::GLuint n_rows);
generalType m_general_type;
glw::GLuint m_n_columns;
glw::GLuint m_n_rows;
glw::GLenum m_type;
std::string m_type_name;
};
/* Typedefs for gl.uniform* function pointers */
typedef GLW_APICALL void(GLW_APIENTRY* uniformDMatFunctionPointer)(glw::GLint, glw::GLsizei, glw::GLboolean,
const glw::GLdouble*);
typedef GLW_APICALL void(GLW_APIENTRY* uniformDVecFunctionPointer)(glw::GLint, glw::GLsizei, const glw::GLdouble*);
typedef GLW_APICALL void(GLW_APIENTRY* uniformIVecFunctionPointer)(glw::GLint, glw::GLsizei, const glw::GLint*);
typedef GLW_APICALL void(GLW_APIENTRY* uniformUVecFunctionPointer)(glw::GLint, glw::GLsizei, const glw::GLuint*);
/* Private methods */
bool compare(Utils::_variable_type type, const glw::GLvoid* left, const glw::GLvoid* right);
functionObject* getFunctionObject(FunctionEnum function, const typeDetails& type);
uniformDMatFunctionPointer getUniformFunctionForDMat(glw::GLuint argument,
const functionObject& function_object) const;
uniformDVecFunctionPointer getUniformFunctionForDVec(glw::GLuint argument,
const functionObject& function_object) const;
uniformIVecFunctionPointer getUniformFunctionForIVec(glw::GLuint argument,
const functionObject& function_object) const;
uniformUVecFunctionPointer getUniformFunctionForUVec(glw::GLuint argument,
const functionObject& function_object) const;
const glw::GLchar* getUniformName(glw::GLuint argument) const;
const glw::GLchar* getVaryingName(glw::GLuint argument) const;
bool isFunctionImplemented(FunctionEnum function, const typeDetails& type) const;
void logVariableType(const glw::GLvoid* buffer, const glw::GLchar* name, Utils::_variable_type type) const;
void prepareArgument(const functionObject& function_object, glw::GLuint vertex, glw::GLubyte* buffer);
void prepareComponents(const functionObject& function_object, glw::GLuint vertex, glw::GLuint argument,
glw::GLubyte* buffer);
void prepareProgram(const functionObject& function_object, Utils::programInfo& program_info);
void prepareTestData(const functionObject& function_object);
void prepareVertexShaderCode(const functionObject& function_object);
bool test(FunctionEnum function, const typeDetails& type);
void testBegin(const functionObject& function_object, glw::GLuint program_id, glw::GLuint vertex);
void testInit();
bool isResultEdgeCase(const functionObject& function_object, glw::GLuint vertex,
const Utils::_variable_type result_type, const glw::GLvoid* expected_result_src,
const glw::GLvoid* result_src);
bool verifyResults(const functionObject& function_object, glw::GLuint vertex);
/* Private constants */
static const glw::GLdouble m_epsilon;
static const glw::GLuint m_n_veritces;
/* Private fields */
glw::GLuint m_transform_feedback_buffer_id;
glw::GLuint m_vertex_array_object_id;
std::vector<glw::GLubyte> m_expected_results_data;
FunctionEnum m_function;
TypeDefinition m_typeDefinition;
std::vector<glw::GLubyte> m_argument_data;
std::string m_vertex_shader_code;
};
/* Constants used by BuiltinFunctionTest */
/** Khronos Bug #14010
* Using an epsilon value for comparing floating points is error prone.
* Rather than writing a new floating point comparison function, I am
* increasing the epsilon value to allow greater orders of magnitude
* of floating point values.
**/
const glw::GLdouble BuiltinFunctionTest::m_epsilon = 0.00002;
const glw::GLuint BuiltinFunctionTest::m_n_veritces = 1024;
/** Implementations of function objects required by "BuiltinFunctionTest"
*
**/
namespace FunctionObject
{
/** Maps variable type with enumeration Utils::_variable_type
*
* @tparam T type
**/
template <typename T>
class typeInfo
{
public:
static const Utils::_variable_type variable_type =
TypeHelpers::typeInfo<typename TypeHelpers::referenceToType<T>::result>::variable_type;
};
/** Place data from <in> into <buffer>
*
* @param buffer Buffer
* @param in Input data
**/
template <typename T>
class pack
{
public:
static void set(glw::GLvoid* buffer, const T& in)
{
*(T*)buffer = in;
}
};
/** Place tcu::Matrix data from <in> into <buffer>
*
* @param buffer Buffer
* @param in Input data
**/
template <int Cols, int Rows>
class pack<tcu::Matrix<glw::GLdouble, Rows, Cols> >
{
public:
static void set(glw::GLvoid* buffer, const tcu::Matrix<glw::GLdouble, Rows, Cols>& in)
{
glw::GLdouble* data = (glw::GLdouble*)buffer;
for (glw::GLint column = 0; column < Cols; ++column)
{
for (glw::GLint row = 0; row < Rows; ++row)
{
glw::GLint index = column * Rows + row;
data[index] = in(row, column);
}
}
}
};
/** Get data of <out> from <buffer>
*
* @param buffer Buffer
* @param out Output data
**/
template <typename T>
class unpack
{
public:
static void get(const glw::GLvoid* buffer, T& out)
{
out = *(T*)buffer;
}
};
/** Get tcu::Matrix data from <buffer>
*
* @param buffer Buffer
* @param out Output data
**/
template <int Cols, int Rows>
class unpack<tcu::Matrix<glw::GLdouble, Rows, Cols> >
{
public:
static void get(const glw::GLvoid* buffer, tcu::Matrix<glw::GLdouble, Rows, Cols>& out)
{
const glw::GLdouble* data = (glw::GLdouble*)buffer;
for (glw::GLint column = 0; column < Cols; ++column)
{
for (glw::GLint row = 0; row < Rows; ++row)
{
glw::GLint index = column * Rows + row;
out(row, column) = data[index];
}
}
}
};
/** Base of unary function classes
*
**/
class unaryBase : public BuiltinFunctionTest::functionObject
{
public:
unaryBase(FunctionEnum function_enum, const glw::GLchar* function_name, glw::GLvoid* function_pointer,
const Utils::_variable_type res_type, const Utils::_variable_type arg_type)
: functionObject(function_enum, function_name, function_pointer, res_type), m_arg_type(arg_type)
{
}
virtual glw::GLuint getArgumentCount() const
{
return 1;
}
virtual Utils::_variable_type getArgumentType(glw::GLuint /* argument */) const
{
return m_arg_type;
}
protected:
const Utils::_variable_type m_arg_type;
};
/** Unary function class. It treats input argument as one variable.
*
* @tparam ResT Type of result
* @tparam ArgT Type of argument
**/
template <typename ResT, typename ArgT>
class unary : public unaryBase
{
public:
typedef ResT (*functionPointer)(const ArgT&);
unary(FunctionEnum function_enum, const glw::GLchar* function_name, functionPointer function_pointer)
: unaryBase(function_enum, function_name, (glw::GLvoid*)function_pointer, typeInfo<ResT>::variable_type,
typeInfo<ArgT>::variable_type)
{
}
virtual void call(glw::GLvoid* result_dst, const glw::GLvoid* argument_src) const
{
ResT result;
ArgT arg;
unpack<ArgT>::get(argument_src, arg);
functionPointer p_function = (functionPointer)m_p_function;
result = p_function(arg);
pack<ResT>::set(result_dst, result);
}
};
/** Unary function class. It treats input argument as separate components.
*
* @tparam ResT Type of result
**/
template <typename ResT>
class unaryByComponent : public unaryBase
{
public:
typedef ResT (*functionPointer)(glw::GLdouble);
unaryByComponent(FunctionEnum function_enum, const glw::GLchar* function_name, functionPointer function_pointer,
const Utils::_variable_type res_type, const Utils::_variable_type arg_type)
: unaryBase(function_enum, function_name, (glw::GLvoid*)function_pointer, res_type, arg_type)
{
}
virtual void call(glw::GLvoid* result_dst, const glw::GLvoid* argument_src) const
{
glw::GLuint n_components = Utils::getNumberOfComponentsForVariableType(m_arg_type);
ResT* p_result = (ResT*)result_dst;
glw::GLdouble* p_arg = (glw::GLdouble*)argument_src;
functionPointer p_function = (functionPointer)m_p_function;
for (glw::GLuint component = 0; component < n_components; ++component)
{
p_result[component] = p_function(p_arg[component]);
}
}
};
/** Class of functions with one input and one output parameter. It treats arguments as separate components.
*
* @tparam ResT Type of result
* @tparam ArgT Type of argument
* @tparam OutT Type of output parameter
**/
template <typename ResT, typename ArgT, typename OutT>
class unaryWithOutputByComponent : public unaryBase
{
public:
typedef ResT (*functionPointer)(ArgT, OutT&);
unaryWithOutputByComponent(FunctionEnum function_enum, const glw::GLchar* function_name,
functionPointer function_pointer, const Utils::_variable_type res_type,
const Utils::_variable_type arg_type, const Utils::_variable_type out_type)
: unaryBase(function_enum, function_name, (glw::GLvoid*)function_pointer, res_type, arg_type)
, m_out_type(out_type)
{
}
virtual void call(glw::GLvoid* result_dst, const glw::GLvoid* argument_src) const
{
ResT* p_result = (ResT*)result_dst;
OutT* p_out = (OutT*)((glw::GLubyte*)result_dst + getResultOffset(1));
ArgT* p_arg = (ArgT*)argument_src;
const glw::GLuint n_components_0 = getArgumentComponents(0);
const glw::GLuint n_components_1 = getResultComponents(1);
const glw::GLuint n_components = de::max(n_components_0, n_components_1);
const glw::GLuint component_step_0 = (1 == n_components_0) ? 0 : 1;
const glw::GLuint component_step_1 = (1 == n_components_1) ? 0 : 1;
functionPointer p_function = (functionPointer)m_p_function;
for (glw::GLuint component = 0; component < n_components; ++component)
{
const ArgT first_arg = p_arg[component * component_step_0];
OutT& second_arg = p_out[component * component_step_1];
p_result[component] = p_function(first_arg, second_arg);
}
}
glw::GLuint getResultCount() const
{
return 2;
}
Utils::_variable_type getResultType(glw::GLuint result) const
{
Utils::_variable_type type = Utils::VARIABLE_TYPE_UNKNOWN;
switch (result)
{
case 0:
type = m_res_type;
break;
case 1:
type = m_out_type;
break;
default:
TCU_FAIL("Not implemented");
break;
}
return type;
}
protected:
const Utils::_variable_type m_out_type;
};
/** Base of binary function classes.
*
**/
class binaryBase : public BuiltinFunctionTest::functionObject
{
public:
binaryBase(FunctionEnum function_enum, const glw::GLchar* function_name, glw::GLvoid* function_pointer,
const Utils::_variable_type res_type, const Utils::_variable_type arg_1_type,
const Utils::_variable_type arg_2_type)
: functionObject(function_enum, function_name, function_pointer, res_type)
, m_arg_1_type(arg_1_type)
, m_arg_2_type(arg_2_type)
{
}
virtual glw::GLuint getArgumentCount() const
{
return 2;
}
virtual Utils::_variable_type getArgumentType(glw::GLuint argument) const
{
switch (argument)
{
case 0:
return m_arg_1_type;
case 1:
return m_arg_2_type;
default:
return Utils::VARIABLE_TYPE_UNKNOWN;
}
}
protected:
const Utils::_variable_type m_arg_1_type;
const Utils::_variable_type m_arg_2_type;
};
/** Binary function class. It treats input arguments as two variables.
*
* @param ResT Type of result
* @param Arg1T Type of first argument
* @param Arg2T Type of second argument
**/
template <typename ResT, typename Arg1T, typename Arg2T>
class binary : public binaryBase
{
public:
typedef ResT (*functionPointer)(const Arg1T&, const Arg2T&);
binary(FunctionEnum function_enum, const glw::GLchar* function_name, functionPointer function_pointer)
: binaryBase(function_enum, function_name, (glw::GLvoid*)function_pointer, typeInfo<ResT>::variable_type,
typeInfo<Arg1T>::variable_type, typeInfo<Arg2T>::variable_type)
{
}
virtual void call(glw::GLvoid* result_dst, const glw::GLvoid* argument_src) const
{
const glw::GLuint argument_1_stride = getArgumentStride(0);
functionPointer p_function = (functionPointer)m_p_function;
Arg1T arg_1;
Arg2T arg_2;
ResT result;
unpack<Arg1T>::get(argument_src, arg_1);
unpack<Arg2T>::get((glw::GLubyte*)argument_src + argument_1_stride, arg_2);
result = p_function(arg_1, arg_2);
pack<ResT>::set(result_dst, result);
}
};
/** Binary function class. It treats input arguments as separate components.
*
* @param ResT Type of result
* @param Arg1T Type of first argument
* @param Arg2T Type of second argument
**/
template <typename ResT, typename Arg1T, typename Arg2T>
class binaryByComponent : public binaryBase
{
public:
typedef ResT (*functionPointer)(Arg1T, Arg2T);
binaryByComponent(FunctionEnum function_enum, const glw::GLchar* function_name, functionPointer function_pointer,
const Utils::_variable_type res_type, const Utils::_variable_type arg_1_type,
const Utils::_variable_type arg_2_type)
: binaryBase(function_enum, function_name, (glw::GLvoid*)function_pointer, res_type, arg_1_type, arg_2_type)
{
}
virtual void call(glw::GLvoid* result_dst, const glw::GLvoid* argument_src) const
{
ResT* p_result = (ResT*)result_dst;
Arg1T* p_arg_1 = (Arg1T*)argument_src;
Arg2T* p_arg_2 = (Arg2T*)((glw::GLubyte*)argument_src + getArgumentOffset(1));
const glw::GLuint n_components_0 = getArgumentComponents(0);
const glw::GLuint n_components_1 = getArgumentComponents(1);
const glw::GLuint n_components = de::max(n_components_0, n_components_1);
const glw::GLuint component_step_0 = (1 == n_components_0) ? 0 : 1;
const glw::GLuint component_step_1 = (1 == n_components_1) ? 0 : 1;
functionPointer p_function = (functionPointer)m_p_function;
for (glw::GLuint component = 0; component < n_components; ++component)
{
const Arg1T first_arg = p_arg_1[component * component_step_0];
const Arg2T second_arg = p_arg_2[component * component_step_1];
p_result[component] = p_function(first_arg, second_arg);
}
}
};
/** Base of tenary function classes.
*
**/
class tenaryBase : public BuiltinFunctionTest::functionObject
{
public:
tenaryBase(FunctionEnum function_enum, const glw::GLchar* function_name, glw::GLvoid* function_pointer,
const Utils::_variable_type res_type, const Utils::_variable_type arg_1_type,
const Utils::_variable_type arg_2_type, const Utils::_variable_type arg_3_type)
: functionObject(function_enum, function_name, function_pointer, res_type)
, m_arg_1_type(arg_1_type)
, m_arg_2_type(arg_2_type)
, m_arg_3_type(arg_3_type)
{
}
virtual glw::GLuint getArgumentCount() const
{
return 3;
}
virtual Utils::_variable_type getArgumentType(glw::GLuint argument) const
{
switch (argument)
{
case 0:
return m_arg_1_type;
case 1:
return m_arg_2_type;
case 2:
return m_arg_3_type;
default:
return Utils::VARIABLE_TYPE_UNKNOWN;
}
}
protected:
const Utils::_variable_type m_arg_1_type;
const Utils::_variable_type m_arg_2_type;
const Utils::_variable_type m_arg_3_type;
};
/** Tenary function class. It treats input arguments as three variables.
*
* @param ResT Type of result
* @param Arg1T Type of first argument
* @param Arg2T Type of second argument
* @param Arg3T Type of third argument
**/
template <typename ResT, typename Arg1T, typename Arg2T, typename Arg3T>
class tenary : public tenaryBase
{
public:
typedef ResT (*functionPointer)(Arg1T, Arg2T, Arg3T);
typedef typename TypeHelpers::referenceToType<Arg1T>::result arg1T;
typedef typename TypeHelpers::referenceToType<Arg2T>::result arg2T;
typedef typename TypeHelpers::referenceToType<Arg3T>::result arg3T;
tenary(FunctionEnum function_enum, const glw::GLchar* function_name, functionPointer function_pointer)
: tenaryBase(function_enum, function_name, (glw::GLvoid*)function_pointer, typeInfo<ResT>::variable_type,
typeInfo<Arg1T>::variable_type, typeInfo<Arg2T>::variable_type, typeInfo<Arg3T>::variable_type)
{
}
virtual void call(glw::GLvoid* result_dst, const glw::GLvoid* argument_src) const
{
const glw::GLuint argument_2_offset = getArgumentOffset(1);
const glw::GLuint argument_3_offset = getArgumentOffset(2);
functionPointer p_function = (functionPointer)m_p_function;
arg1T arg_1;
arg2T arg_2;
arg3T arg_3;
ResT result;
unpack<arg1T>::get(argument_src, arg_1);
unpack<arg2T>::get((glw::GLubyte*)argument_src + argument_2_offset, arg_2);
unpack<arg3T>::get((glw::GLubyte*)argument_src + argument_3_offset, arg_3);
result = p_function(arg_1, arg_2, arg_3);
pack<ResT>::set(result_dst, result);
}
};
/** Tenary function class. It treats input arguments as separate components.
*
**/
class tenaryByComponent : public tenaryBase
{
public:
typedef glw::GLdouble (*functionPointer)(glw::GLdouble, glw::GLdouble, glw::GLdouble);
tenaryByComponent(FunctionEnum function_enum, const glw::GLchar* function_name, functionPointer function_pointer,
const Utils::_variable_type res_type, const Utils::_variable_type arg_1_type,
const Utils::_variable_type arg_2_type, const Utils::_variable_type arg_3_type)
: tenaryBase(function_enum, function_name, (glw::GLvoid*)function_pointer, res_type, arg_1_type, arg_2_type,
arg_3_type)
{
}
virtual void call(glw::GLvoid* result_dst, const glw::GLvoid* argument_src) const
{
glw::GLdouble* p_result = (glw::GLdouble*)result_dst;
const glw::GLdouble* p_arg = (const glw::GLdouble*)argument_src;
const glw::GLuint n_components_0 = getArgumentComponents(0);
const glw::GLuint n_components_1 = getArgumentComponents(1);
const glw::GLuint n_components_2 = getArgumentComponents(2);
const glw::GLuint n_components = de::max(de::max(n_components_0, n_components_1), n_components_2);
const glw::GLuint component_step_0 = (1 == n_components_0) ? 0 : 1;
const glw::GLuint component_step_1 = (1 == n_components_1) ? 0 : 1;
const glw::GLuint component_step_2 = (1 == n_components_2) ? 0 : 1;
functionPointer p_function = (functionPointer)m_p_function;
for (glw::GLuint component = 0; component < n_components; ++component)
{
const glw::GLdouble first_arg = p_arg[component * component_step_0];
const glw::GLdouble second_arg = p_arg[component * component_step_1 + n_components_0];
const glw::GLdouble third_arg = p_arg[component * component_step_2 + n_components_0 + n_components_1];
p_result[component] = p_function(first_arg, second_arg, third_arg);
}
}
};
} /* FunctionObject */
/** Constructor.
*
* @param context Rendering context.
**/
BuiltinFunctionTest::BuiltinFunctionTest(deqp::Context& context, std::string caseName, FunctionEnum function,
TypeDefinition typeDefinition)
: TestCase(context, caseName.c_str(), "Verify that built-in functions support double-precision types")
, m_transform_feedback_buffer_id(0)
, m_vertex_array_object_id(0)
, m_function(function)
, m_typeDefinition(typeDefinition)
{
/* Nothing to be done here */
}
/** Deinitializes all GL objects that may have been created during test execution.
*
**/
void BuiltinFunctionTest::deinit()
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Clean buffers */
if (0 != m_transform_feedback_buffer_id)
{
gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0);
gl.deleteBuffers(1, &m_transform_feedback_buffer_id);
m_transform_feedback_buffer_id = 0;
}
/* Clean VAO */
if (0 != m_vertex_array_object_id)
{
gl.bindVertexArray(0);
gl.deleteVertexArrays(1, &m_vertex_array_object_id);
m_vertex_array_object_id = 0;
}
}
/** Execute test
*
* @return tcu::TestNode::STOP
**/
tcu::TestNode::IterateResult BuiltinFunctionTest::iterate()
{
/* Check if extension is supported */
if (false == m_context.getContextInfo().isExtensionSupported("GL_ARB_gpu_shader_fp64"))
{
throw tcu::NotSupportedError("GL_ARB_gpu_shader_fp64 is not supported");
}
testInit();
/* Verify result */
typeDetails type(m_typeDefinition.n_columns, m_typeDefinition.n_rows);
if (test(m_function, type))
{
m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Pass");
}
else
{
m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Fail");
}
/* Done */
return tcu::TestNode::STOP;
}
/** Constructor
*
* @param function_enum Function enumeration
* @param function_name Function name
* @param function_pointer Pointer to routine that wiil be executed
* @param result_type Type of result
**/
BuiltinFunctionTest::functionObject::functionObject(FunctionEnum function_enum, const glw::GLchar* function_name,
glw::GLvoid* function_pointer, Utils::_variable_type result_type)
: m_function_enum(function_enum)
, m_function_name(function_name)
, m_p_function(function_pointer)
, m_res_type(result_type)
{
/* Nothing to be done here */
}
/** Get number of components for <argument>
*
* @param argument Argument ordinal, starts with 0
*
* @return Number of components
**/
glw::GLuint BuiltinFunctionTest::functionObject::getArgumentComponents(glw::GLuint argument) const
{
const Utils::_variable_type type = getArgumentType(argument);
const glw::GLuint n_components = Utils::getNumberOfComponentsForVariableType(type);
return n_components;
}
/** Get size in bytes of single component of <argument>
*
* @param argument Argument ordinal, starts with 0
*
* @return Size of component
**/
glw::GLuint BuiltinFunctionTest::functionObject::getArgumentComponentSize(glw::GLuint argument) const
{
const Utils::_variable_type type = getArgumentType(argument);
const Utils::_variable_type base_type = Utils::getBaseVariableType(type);
const glw::GLuint base_type_size = Utils::getBaseVariableTypeComponentSize(base_type);
return base_type_size;
}
/** Get offset in bytes of <argument>. 0 is offset of first argument. Assumes tight packing.
*
* @param argument Argument ordinal, starts with 0
*
* @return Offset of arguemnt's data
**/
glw::GLuint BuiltinFunctionTest::functionObject::getArgumentOffset(glw::GLuint argument) const
{
glw::GLuint result = 0;
for (glw::GLuint i = 0; i < argument; ++i)
{
result += getArgumentStride(i);
}
return result;
}
/** Get stride in bytes of all arguments
*
* @return Stride of all arguments
**/
glw::GLuint BuiltinFunctionTest::functionObject::getArgumentStride() const
{
const glw::GLuint n_args = getArgumentCount();
glw::GLuint result = 0;
for (glw::GLuint i = 0; i < n_args; ++i)
{
result += getArgumentStride(i);
}
return result;
}
/** Get stride in bytes of <argument>
*
* @param argument Argument ordinal, starts with 0
*
* @return Stride of argument
**/
glw::GLuint BuiltinFunctionTest::functionObject::getArgumentStride(glw::GLuint argument) const
{
const glw::GLuint component_size = getArgumentComponentSize(argument);
const glw::GLuint n_components = getArgumentComponents(argument);
return n_components * component_size;
}
/** Get function enumeration
*
* @return Function enumeration
**/
FunctionEnum BuiltinFunctionTest::functionObject::getFunctionEnum() const
{
return m_function_enum;
}
/** Get function name
*
* @return Function name
**/
const glw::GLchar* BuiltinFunctionTest::functionObject::getName() const
{
return m_function_name;
}
/** Get number of components for <result>
*
* @param result Result ordinal, starts with 0
*
* @return Number of components
**/
glw::GLuint BuiltinFunctionTest::functionObject::getResultComponents(glw::GLuint result) const
{
const Utils::_variable_type type = getResultType(result);
const glw::GLuint n_components = Utils::getNumberOfComponentsForVariableType(type);
return n_components;
}
/** Get number of results
*
* @return Number of results
**/
glw::GLuint BuiltinFunctionTest::functionObject::getResultCount() const
{
return 1;
}
/** Get offset in bytes of <result>. First result offset is 0. Assume tight packing.
*
* @param result Result ordinal, starts with 0
*
* @return Offset
**/
glw::GLuint BuiltinFunctionTest::functionObject::getResultOffset(glw::GLuint result) const
{
glw::GLuint offset = 0;
for (glw::GLuint i = 0; i < result; ++i)
{
offset += getResultStride(i);
offset = deAlign32(offset, getBaseTypeSize(i));
}
return offset;
}
/** Get stride in bytes of <result>.
*
* @param result Result ordinal, starts with 0
*
* @return Stride
**/
glw::GLuint BuiltinFunctionTest::functionObject::getResultStride(glw::GLuint result) const
{
const Utils::_variable_type type = getResultType(result);
const glw::GLuint n_components = Utils::getNumberOfComponentsForVariableType(type);
return n_components * getBaseTypeSize(result);
}
/** Get size in bytes of <result> base component.
*
* @param result Result ordinal, starts with 0
*
* @return Alignment
**/
glw::GLuint BuiltinFunctionTest::functionObject::getBaseTypeSize(glw::GLuint result) const
{
const Utils::_variable_type type = getResultType(result);
const Utils::_variable_type base_type = Utils::getBaseVariableType(type);
const glw::GLuint base_type_size = Utils::getBaseVariableTypeComponentSize(base_type);
return base_type_size;
}
/** Get stride in bytes of all results.
*
* @return Stride
**/
glw::GLuint BuiltinFunctionTest::functionObject::getResultStride() const
{
const glw::GLuint n_results = getResultCount();
glw::GLuint stride = 0;
glw::GLuint maxAlignment = 0;
for (glw::GLuint i = 0; i < n_results; ++i)
{
const glw::GLuint alignment = getBaseTypeSize(i);
stride += getResultStride(i);
stride = deAlign32(stride, alignment);
maxAlignment = deMaxu32(maxAlignment, alignment);
}
// The stride of all results must also be aligned,
// so results for next vertex are aligned.
return deAlign32(stride, maxAlignment);
}
/** Get type of <result>.
*
* @param result Result ordinal, starts with 0
*
* @return Type
**/
Utils::_variable_type BuiltinFunctionTest::functionObject::getResultType(glw::GLuint /* result */) const
{
return m_res_type;
}
/** Constructor
*
* @param n_columns Number of columns
* @param n_rows Number of rows
**/
BuiltinFunctionTest::typeDetails::typeDetails(glw::GLuint n_columns, glw::GLuint n_rows)
: m_n_columns(n_columns), m_n_rows(n_rows)
{
Utils::_variable_type type = Utils::getDoubleVariableType(n_columns, n_rows);
m_type = Utils::getGLDataTypeOfVariableType(type);
m_type_name = Utils::getVariableTypeString(type);
if (1 == m_n_columns)
{
if (1 == m_n_rows)
{
m_general_type = SCALAR;
}
else
{
m_general_type = VECTOR;
}
}
else
{
m_general_type = MATRIX;
}
}
/** Compare two values
*
* @param type Type of values
* @param left Pointer to left value
* @param right Pointer to right value
*
* @return true if values are equal, false otherwise
**/
bool BuiltinFunctionTest::compare(Utils::_variable_type type, const glw::GLvoid* left, const glw::GLvoid* right)
{
bool result = true;
const glw::GLuint n_components = Utils::getNumberOfComponentsForVariableType(type);
const Utils::_variable_type base_type = Utils::getBaseVariableType(type);
switch (base_type)
{
case Utils::VARIABLE_TYPE_DOUBLE:
{
const glw::GLdouble* left_values = (glw::GLdouble*)left;
const glw::GLdouble* right_values = (glw::GLdouble*)right;
for (glw::GLuint component = 0; component < n_components; ++component)
{
const glw::GLdouble left_value = left_values[component];
const glw::GLdouble right_value = right_values[component];
if ((left_value != right_value) && (m_epsilon < de::abs(left_value - right_value)) &&
(0 == Math::isnan_impl(left_value)) && (0 == Math::isnan_impl(right_value)))
{
result = false;
break;
}
}
}
break;
case Utils::VARIABLE_TYPE_INT:
{
const glw::GLint* left_values = (glw::GLint*)left;
const glw::GLint* right_values = (glw::GLint*)right;
for (glw::GLuint component = 0; component < n_components; ++component)
{
const glw::GLint left_value = left_values[component];
const glw::GLint right_value = right_values[component];
if (left_value != right_value)
{
result = false;
break;
}
}
}
break;
case Utils::VARIABLE_TYPE_UINT:
{
const glw::GLuint* left_values = (glw::GLuint*)left;
const glw::GLuint* right_values = (glw::GLuint*)right;
for (glw::GLuint component = 0; component < n_components; ++component)
{
const glw::GLuint left_value = left_values[component];
const glw::GLuint right_value = right_values[component];
if (left_value != right_value)
{
result = false;
break;
}
}
}
break;
default:
TCU_FAIL("Not implemented");
}
return result;
}
/** Create instance of function object for given function enumeration and type
*
* @param function Function enumeration
* @param type Type details
*
* @return Create object
**/
BuiltinFunctionTest::functionObject* BuiltinFunctionTest::getFunctionObject(FunctionEnum function,
const typeDetails& type)
{
typedef tcu::Matrix<glw::GLdouble, 2, 2> DMat2;
typedef tcu::Matrix<glw::GLdouble, 3, 2> DMat2x3;
typedef tcu::Matrix<glw::GLdouble, 4, 2> DMat2x4;
typedef tcu::Matrix<glw::GLdouble, 2, 3> DMat3x2;
typedef tcu::Matrix<glw::GLdouble, 3, 3> DMat3;
typedef tcu::Matrix<glw::GLdouble, 4, 3> DMat3x4;
typedef tcu::Matrix<glw::GLdouble, 2, 4> DMat4x2;
typedef tcu::Matrix<glw::GLdouble, 3, 4> DMat4x3;
typedef tcu::Matrix<glw::GLdouble, 4, 4> DMat4;
const glw::GLuint n_columns = type.m_n_columns;
const glw::GLuint n_rows = type.m_n_rows;
const Utils::_variable_type scalar_type = Utils::getDoubleVariableType(1, 1);
const Utils::_variable_type variable_type = Utils::getDoubleVariableType(n_columns, n_rows);
const Utils::_variable_type uint_type = Utils::getUintVariableType(1, n_rows);
const Utils::_variable_type int_type = Utils::getIntVariableType(1, n_rows);
switch (function)
{
case FUNCTION_ABS:
return new FunctionObject::unaryByComponent<glw::GLdouble /* ResT */>(
function, "abs", de::abs, variable_type /* res_type */, variable_type /* arg_type */);
case FUNCTION_CEIL:
return new FunctionObject::unaryByComponent<glw::GLdouble /* ResT */>(
function, "ceil", ceil, variable_type /* res_type */, variable_type /* arg_type */);
case FUNCTION_CLAMP:
return new FunctionObject::tenaryByComponent(function, "clamp", Math::clamp, variable_type /* res_type */,
variable_type /* arg1_type */, variable_type /* arg2_type */,
variable_type /* arg3_type */);
case FUNCTION_CLAMP_AGAINST_SCALAR:
return new FunctionObject::tenaryByComponent(function, "clamp", Math::clamp, variable_type /* res_type */,
variable_type /* arg1_type */, scalar_type /* arg2_type */,
scalar_type /* arg3_type */);
case FUNCTION_CROSS:
return new FunctionObject::binary<tcu::DVec3 /* ResT */, tcu::DVec3 /* Arg1T */, tcu::DVec3 /* Arg2T */>(
function, "cross", tcu::cross);
case FUNCTION_DETERMINANT:
switch (variable_type)
{
case Utils::VARIABLE_TYPE_DMAT2:
return new FunctionObject::unary<glw::GLdouble /* ResT */, DMat2 /* ArgT */>(function, "determinant",
Math::determinant);
case Utils::VARIABLE_TYPE_DMAT3:
return new FunctionObject::unary<glw::GLdouble /* ResT */, DMat3 /* ArgT */>(function, "determinant",
Math::determinant);
case Utils::VARIABLE_TYPE_DMAT4:
return new FunctionObject::unary<glw::GLdouble /* ResT */, DMat4 /* ArgT */>(function, "determinant",
Math::determinant);
default:
TCU_FAIL("Not implemented");
}
case FUNCTION_DISTANCE:
switch (variable_type)
{
case Utils::VARIABLE_TYPE_DVEC2:
return new FunctionObject::binary<glw::GLdouble /* ResT */, tcu::DVec2 /* Arg1T */, tcu::DVec2 /* Arg2T */>(
function, "distance", tcu::distance);
case Utils::VARIABLE_TYPE_DVEC3:
return new FunctionObject::binary<glw::GLdouble /* ResT */, tcu::DVec3 /* Arg1T */, tcu::DVec3 /* Arg2T */>(
function, "distance", tcu::distance);
case Utils::VARIABLE_TYPE_DVEC4:
return new FunctionObject::binary<glw::GLdouble /* ResT */, tcu::DVec4 /* Arg1T */, tcu::DVec4 /* Arg2T */>(
function, "distance", tcu::distance);
default:
break;
}
break;
case FUNCTION_DOT:
switch (variable_type)
{
case Utils::VARIABLE_TYPE_DVEC2:
return new FunctionObject::binary<glw::GLdouble /* ResT */, tcu::DVec2 /* Arg1T */, tcu::DVec2 /* Arg2T */>(
function, "dot", tcu::dot);
case Utils::VARIABLE_TYPE_DVEC3:
return new FunctionObject::binary<glw::GLdouble /* ResT */, tcu::DVec3 /* Arg1T */, tcu::DVec3 /* Arg2T */>(
function, "dot", tcu::dot);
case Utils::VARIABLE_TYPE_DVEC4:
return new FunctionObject::binary<glw::GLdouble /* ResT */, tcu::DVec4 /* Arg1T */, tcu::DVec4 /* Arg2T */>(
function, "dot", tcu::dot);
default:
break;
}
break;
case FUNCTION_EQUAL:
switch (variable_type)
{
case Utils::VARIABLE_TYPE_DVEC2:
return new FunctionObject::binary<tcu::UVec2 /* ResT */, tcu::DVec2 /* Arg1T */, tcu::DVec2 /* Arg2T */>(
function, "equal", Math::equal);
case Utils::VARIABLE_TYPE_DVEC3:
return new FunctionObject::binary<tcu::UVec3 /* ResT */, tcu::DVec3 /* Arg1T */, tcu::DVec3 /* Arg2T */>(
function, "equal", Math::equal);
case Utils::VARIABLE_TYPE_DVEC4:
return new FunctionObject::binary<tcu::UVec4 /* ResT */, tcu::DVec4 /* Arg1T */, tcu::DVec4 /* Arg2T */>(
function, "equal", Math::equal);
default:
break;
}
break;
case FUNCTION_FACEFORWARD:
switch (variable_type)
{
case Utils::VARIABLE_TYPE_DVEC2:
return new FunctionObject::tenary<tcu::DVec2 /* ResT */, const tcu::DVec2& /* Arg1T */,
const tcu::DVec2& /* Arg2T */, const tcu::DVec2& /* Arg3T */>(
function, "faceforward", tcu::faceForward);
case Utils::VARIABLE_TYPE_DVEC3:
return new FunctionObject::tenary<tcu::DVec3 /* ResT */, const tcu::DVec3& /* Arg1T */,
const tcu::DVec3& /* Arg2T */, const tcu::DVec3& /* Arg3T */>(
function, "faceforward", tcu::faceForward);
case Utils::VARIABLE_TYPE_DVEC4:
return new FunctionObject::tenary<tcu::DVec4 /* ResT */, const tcu::DVec4& /* Arg1T */,
const tcu::DVec4& /* Arg2T */, const tcu::DVec4& /* Arg3T */>(
function, "faceforward", tcu::faceForward);
default:
break;
}
break;
case FUNCTION_FLOOR:
return new FunctionObject::unaryByComponent<glw::GLdouble /* ResT */>(
function, "floor", floor, variable_type /* res_type */, variable_type /* arg_type */);
case FUNCTION_FMA:
return new FunctionObject::tenaryByComponent(function, "fma", Math::fma, variable_type /* res_type */,
variable_type /* arg1_type */, variable_type /* arg2_type */,
variable_type /* arg3_type */);
case FUNCTION_FRACT:
return new FunctionObject::unaryByComponent<glw::GLdouble /* ResT */>(
function, "fract", Math::fract, variable_type /* res_type */, variable_type /* arg_type */);
case FUNCTION_FREXP:
return new FunctionObject::unaryWithOutputByComponent<glw::GLdouble /* ResT */, glw::GLdouble /* ArgT */,
glw::GLint /* OutT */>(
function, "frexp", Math::frexp, variable_type /* res_type */, variable_type /* arg_type */,
int_type /* out_type */);
case FUNCTION_GREATERTHAN:
switch (variable_type)
{
case Utils::VARIABLE_TYPE_DVEC2:
return new FunctionObject::binary<tcu::UVec2 /* ResT */, tcu::DVec2 /* Arg1T */, tcu::DVec2 /* Arg2T */>(
function, "greaterThan", Math::greaterThan);
case Utils::VARIABLE_TYPE_DVEC3:
return new FunctionObject::binary<tcu::UVec3 /* ResT */, tcu::DVec3 /* Arg1T */, tcu::DVec3 /* Arg2T */>(
function, "greaterThan", Math::greaterThan);
case Utils::VARIABLE_TYPE_DVEC4:
return new FunctionObject::binary<tcu::UVec4 /* ResT */, tcu::DVec4 /* Arg1T */, tcu::DVec4 /* Arg2T */>(
function, "greaterThan", Math::greaterThan);
default:
break;
}
break;
case FUNCTION_GREATERTHANEQUAL:
switch (variable_type)
{
case Utils::VARIABLE_TYPE_DVEC2:
return new FunctionObject::binary<tcu::UVec2 /* ResT */, tcu::DVec2 /* Arg1T */, tcu::DVec2 /* Arg2T */>(
function, "greaterThanEqual", Math::greaterThanEqual);
case Utils::VARIABLE_TYPE_DVEC3:
return new FunctionObject::binary<tcu::UVec3 /* ResT */, tcu::DVec3 /* Arg1T */, tcu::DVec3 /* Arg2T */>(
function, "greaterThanEqual", Math::greaterThanEqual);
case Utils::VARIABLE_TYPE_DVEC4:
return new FunctionObject::binary<tcu::UVec4 /* ResT */, tcu::DVec4 /* Arg1T */, tcu::DVec4 /* Arg2T */>(
function, "greaterThanEqual", Math::greaterThanEqual);
default:
break;
}
break;
case FUNCTION_INVERSE:
switch (variable_type)
{
case Utils::VARIABLE_TYPE_DMAT2:
return new FunctionObject::unary<DMat2 /* ResT */, DMat2 /* ArgT */>(function, "inverse", Math::inverse);
case Utils::VARIABLE_TYPE_DMAT3:
return new FunctionObject::unary<DMat3 /* ResT */, DMat3 /* ArgT */>(function, "inverse", Math::inverse);
case Utils::VARIABLE_TYPE_DMAT4:
return new FunctionObject::unary<DMat4 /* ResT */, DMat4 /* ArgT */>(function, "inverse", Math::inverse);
default:
break;
}
break;
case FUNCTION_INVERSESQRT:
return new FunctionObject::unaryByComponent<glw::GLdouble /* ResT */>(
function, "inversesqrt", Math::inverseSqrt, variable_type /* res_type */, variable_type /* arg_type */);
case FUNCTION_LDEXP:
return new FunctionObject::binaryByComponent<glw::GLdouble /* ResT */, glw::GLdouble /* Arg1T */,
glw::GLint /* Arg2T */>(
function, "ldexp", ::ldexp, variable_type /* res_type */, variable_type /* arg1_type */,
int_type /* arg2_type */);
case FUNCTION_LESSTHAN:
switch (variable_type)
{
case Utils::VARIABLE_TYPE_DVEC2:
return new FunctionObject::binary<tcu::UVec2 /* ResT */, tcu::DVec2 /* Arg1T */, tcu::DVec2 /* Arg2T */>(
function, "lessThan", Math::lessThan);
case Utils::VARIABLE_TYPE_DVEC3:
return new FunctionObject::binary<tcu::UVec3 /* ResT */, tcu::DVec3 /* Arg1T */, tcu::DVec3 /* Arg2T */>(
function, "lessThan", Math::lessThan);
case Utils::VARIABLE_TYPE_DVEC4:
return new FunctionObject::binary<tcu::UVec4 /* ResT */, tcu::DVec4 /* Arg1T */, tcu::DVec4 /* Arg2T */>(
function, "lessThan", Math::lessThan);
default:
break;
}
break;
case FUNCTION_LESSTHANEQUAL:
switch (variable_type)
{
case Utils::VARIABLE_TYPE_DVEC2:
return new FunctionObject::binary<tcu::UVec2 /* ResT */, tcu::DVec2 /* Arg1T */, tcu::DVec2 /* Arg2T */>(
function, "lessThanEqual", Math::lessThanEqual);
case Utils::VARIABLE_TYPE_DVEC3:
return new FunctionObject::binary<tcu::UVec3 /* ResT */, tcu::DVec3 /* Arg1T */, tcu::DVec3 /* Arg2T */>(
function, "lessThanEqual", Math::lessThanEqual);
case Utils::VARIABLE_TYPE_DVEC4:
return new FunctionObject::binary<tcu::UVec4 /* ResT */, tcu::DVec4 /* Arg1T */, tcu::DVec4 /* Arg2T */>(
function, "lessThanEqual", Math::lessThanEqual);
default:
break;
}
break;
case FUNCTION_LENGTH:
switch (variable_type)
{
case Utils::VARIABLE_TYPE_DVEC2:
return new FunctionObject::unary<glw::GLdouble /* ResT */, tcu::DVec2 /* ArgT */>(function, "length",
tcu::length);
case Utils::VARIABLE_TYPE_DVEC3:
return new FunctionObject::unary<glw::GLdouble /* ResT */, tcu::DVec3 /* ArgT */>(function, "length",
tcu::length);
case Utils::VARIABLE_TYPE_DVEC4:
return new FunctionObject::unary<glw::GLdouble /* ResT */, tcu::DVec4 /* ArgT */>(function, "length",
tcu::length);
default:
break;
}
break;
case FUNCTION_MATRIXCOMPMULT:
return new FunctionObject::binaryByComponent<glw::GLdouble /* ResT */, glw::GLdouble /* Arg1T */,
glw::GLdouble /* Arg2T */>(
function, "matrixCompMult", Math::multiply, variable_type /* res_type */, variable_type /* arg1_type */,
variable_type /* arg2_type */);
case FUNCTION_MAX:
return new FunctionObject::binaryByComponent<glw::GLdouble /* ResT */, glw::GLdouble /* Arg1T */,
glw::GLdouble /* Arg2T */>(
function, "max", Math::max, variable_type /* res_type */, variable_type /* arg1_type */,
variable_type /* arg2_type */);
case FUNCTION_MAX_AGAINST_SCALAR:
return new FunctionObject::binaryByComponent<glw::GLdouble /* ResT */, glw::GLdouble /* Arg1T */,
glw::GLdouble /* Arg2T */>(
function, "max", Math::max, variable_type /* res_type */, variable_type /* arg1_type */,
scalar_type /* arg2_type */);
case FUNCTION_MIN:
return new FunctionObject::binaryByComponent<glw::GLdouble /* ResT */, glw::GLdouble /* Arg1T */,
glw::GLdouble /* Arg2T */>(
function, "min", Math::min, variable_type /* res_type */, variable_type /* arg1_type */,
variable_type /* arg2_type */);
case FUNCTION_MIN_AGAINST_SCALAR:
return new FunctionObject::binaryByComponent<glw::GLdouble /* ResT */, glw::GLdouble /* Arg1T */,
glw::GLdouble /* Arg2T */>(
function, "min", Math::min, variable_type /* res_type */, variable_type /* arg1_type */,
scalar_type /* arg2_type */);
case FUNCTION_MIX:
return new FunctionObject::tenaryByComponent(function, "mix", Math::mix, variable_type /* res_type */,
variable_type /* arg1_type */, variable_type /* arg2_type */,
variable_type /* arg3_type */);
case FUNCTION_MOD:
return new FunctionObject::binaryByComponent<glw::GLdouble /* ResT */, glw::GLdouble /* Arg1T */,
glw::GLdouble /* Arg2T */>(
function, "mod", Math::mod, variable_type /* res_type */, variable_type /* arg1_type */,
variable_type /* arg2_type */);
case FUNCTION_MOD_AGAINST_SCALAR:
return new FunctionObject::binaryByComponent<glw::GLdouble /* ResT */, glw::GLdouble /* Arg1T */,
glw::GLdouble /* Arg2T */>(
function, "mod", Math::mod, variable_type /* res_type */, variable_type /* arg1_type */,
scalar_type /* arg2_type */);
case FUNCTION_MODF:
return new FunctionObject::unaryWithOutputByComponent<glw::GLdouble /* ResT */, glw::GLdouble /* ArgT */,
glw::GLdouble /* OutT */>(
function, "modf", Math::modf, variable_type /* res_type */, variable_type /* arg_type */,
variable_type /* out_type */);
case FUNCTION_NORMALIZE:
switch (variable_type)
{
case Utils::VARIABLE_TYPE_DVEC2:
return new FunctionObject::unary<tcu::DVec2 /* ResT */, tcu::DVec2 /* ArgT */>(function, "normalize",
tcu::normalize);
case Utils::VARIABLE_TYPE_DVEC3:
return new FunctionObject::unary<tcu::DVec3 /* ResT */, tcu::DVec3 /* ArgT */>(function, "normalize",
tcu::normalize);
case Utils::VARIABLE_TYPE_DVEC4:
return new FunctionObject::unary<tcu::DVec4 /* ResT */, tcu::DVec4 /* ArgT */>(function, "normalize",
tcu::normalize);
default:
break;
}
break;
case FUNCTION_NOTEQUAL:
switch (variable_type)
{
case Utils::VARIABLE_TYPE_DVEC2:
return new FunctionObject::binary<tcu::UVec2 /* ResT */, tcu::DVec2 /* Arg1T */, tcu::DVec2 /* Arg2T */>(
function, "notEqual", Math::notEqual);
case Utils::VARIABLE_TYPE_DVEC3:
return new FunctionObject::binary<tcu::UVec3 /* ResT */, tcu::DVec3 /* Arg1T */, tcu::DVec3 /* Arg2T */>(
function, "notEqual", Math::notEqual);
case Utils::VARIABLE_TYPE_DVEC4:
return new FunctionObject::binary<tcu::UVec4 /* ResT */, tcu::DVec4 /* Arg1T */, tcu::DVec4 /* Arg2T */>(
function, "notEqual", Math::notEqual);
default:
break;
}
break;
case FUNCTION_OUTERPRODUCT:
switch (variable_type)
{
case Utils::VARIABLE_TYPE_DMAT2:
return new FunctionObject::binary<DMat2 /* ResT */, tcu::DVec2 /* Arg1T */, tcu::DVec2 /* Arg2T */>(
function, "outerProduct", Math::outerProduct);
case Utils::VARIABLE_TYPE_DMAT2X3:
return new FunctionObject::binary<DMat2x3 /* ResT */, tcu::DVec3 /* Arg1T */, tcu::DVec2 /* Arg2T */>(
function, "outerProduct", Math::outerProduct);
case Utils::VARIABLE_TYPE_DMAT2X4:
return new FunctionObject::binary<DMat2x4 /* ResT */, tcu::DVec4 /* Arg1T */, tcu::DVec2 /* Arg2T */>(
function, "outerProduct", Math::outerProduct);
case Utils::VARIABLE_TYPE_DMAT3:
return new FunctionObject::binary<DMat3 /* ResT */, tcu::DVec3 /* Arg1T */, tcu::DVec3 /* Arg2T */>(
function, "outerProduct", Math::outerProduct);
case Utils::VARIABLE_TYPE_DMAT3X2:
return new FunctionObject::binary<DMat3x2 /* ResT */, tcu::DVec2 /* Arg1T */, tcu::DVec3 /* Arg2T */>(
function, "outerProduct", Math::outerProduct);
case Utils::VARIABLE_TYPE_DMAT3X4:
return new FunctionObject::binary<DMat3x4 /* ResT */, tcu::DVec4 /* Arg1T */, tcu::DVec3 /* Arg2T */>(
function, "outerProduct", Math::outerProduct);
case Utils::VARIABLE_TYPE_DMAT4:
return new FunctionObject::binary<DMat4 /* ResT */, tcu::DVec4 /* Arg1T */, tcu::DVec4 /* Arg2T */>(
function, "outerProduct", Math::outerProduct);
case Utils::VARIABLE_TYPE_DMAT4X2:
return new FunctionObject::binary<DMat4x2 /* ResT */, tcu::DVec2 /* Arg1T */, tcu::DVec4 /* Arg2T */>(
function, "outerProduct", Math::outerProduct);
case Utils::VARIABLE_TYPE_DMAT4X3:
return new FunctionObject::binary<DMat4x3 /* ResT */, tcu::DVec3 /* Arg1T */, tcu::DVec4 /* Arg2T */>(
function, "outerProduct", Math::outerProduct);
default:
break;
}
break;
case FUNCTION_PACKDOUBLE2X32:
return new FunctionObject::unary<glw::GLdouble /* ResT */, tcu::UVec2 /* ArgT */>(function, "packDouble2x32",
Math::packDouble2x32);
case FUNCTION_REFLECT:
switch (variable_type)
{
case Utils::VARIABLE_TYPE_DVEC2:
return new FunctionObject::binary<tcu::DVec2 /* ResT */, tcu::DVec2 /* Arg1T */, tcu::DVec2 /* Arg2T */>(
function, "reflect", tcu::reflect);
case Utils::VARIABLE_TYPE_DVEC3:
return new FunctionObject::binary<tcu::DVec3 /* ResT */, tcu::DVec3 /* Arg1T */, tcu::DVec3 /* Arg2T */>(
function, "reflect", tcu::reflect);
case Utils::VARIABLE_TYPE_DVEC4:
return new FunctionObject::binary<tcu::DVec4 /* ResT */, tcu::DVec4 /* Arg1T */, tcu::DVec4 /* Arg2T */>(
function, "reflect", tcu::reflect);
default:
break;
}
break;
case FUNCTION_REFRACT:
switch (variable_type)
{
case Utils::VARIABLE_TYPE_DVEC2:
return new FunctionObject::tenary<tcu::DVec2 /* ResT */, const tcu::DVec2& /* Arg1T */,
const tcu::DVec2& /* Arg2T */, glw::GLdouble /* Arg3T */>(
function, "refract", tcu::refract);
case Utils::VARIABLE_TYPE_DVEC3:
return new FunctionObject::tenary<tcu::DVec3 /* ResT */, const tcu::DVec3& /* Arg1T */,
const tcu::DVec3& /* Arg2T */, glw::GLdouble /* Arg3T */>(
function, "refract", tcu::refract);
case Utils::VARIABLE_TYPE_DVEC4:
return new FunctionObject::tenary<tcu::DVec4 /* ResT */, const tcu::DVec4& /* Arg1T */,
const tcu::DVec4& /* Arg2T */, glw::GLdouble /* Arg3T */>(
function, "refract", tcu::refract);
default:
break;
}
break;
case FUNCTION_ROUND:
return new FunctionObject::unaryByComponent<glw::GLdouble /* ResT */>(
function, "round", Math::round, variable_type /* res_type */, variable_type /* arg_type */);
case FUNCTION_ROUNDEVEN:
return new FunctionObject::unaryByComponent<glw::GLdouble /* ResT */>(
function, "roundEven", Math::roundEven, variable_type /* res_type */, variable_type /* arg_type */);
case FUNCTION_SIGN:
return new FunctionObject::unaryByComponent<glw::GLdouble /* ResT */>(
function, "sign", Math::sign, variable_type /* res_type */, variable_type /* arg_type */);
case FUNCTION_SMOOTHSTEP:
return new FunctionObject::tenaryByComponent(function, "smoothstep", Math::smoothStep,
variable_type /* res_type */, variable_type /* arg1_type */,
variable_type /* arg2_type */, variable_type /* arg3_type */);
case FUNCTION_SMOOTHSTEP_AGAINST_SCALAR:
return new FunctionObject::tenaryByComponent(function, "smoothstep", Math::smoothStep,
variable_type /* res_type */, scalar_type /* arg1_type */,
scalar_type /* arg2_type */, variable_type /* arg3_type */);
case FUNCTION_SQRT:
return new FunctionObject::unaryByComponent<glw::GLdouble /* ResT */>(
function, "sqrt", sqrt, variable_type /* res_type */, variable_type /* arg_type */);
case FUNCTION_STEP:
return new FunctionObject::binaryByComponent<glw::GLdouble /* ResT */, glw::GLdouble /* Arg1T */,
glw::GLdouble /* Arg2T */>(
function, "step", Math::step, variable_type /* res_type */, variable_type /* arg1_type */,
variable_type /* arg2_type */);
case FUNCTION_STEP_AGAINST_SCALAR:
return new FunctionObject::binaryByComponent<glw::GLdouble /* ResT */, glw::GLdouble /* Arg1T */,
glw::GLdouble /* Arg2T */>(
function, "step", Math::step, variable_type /* res_type */, scalar_type /* arg1_type */,
variable_type /* arg2_type */);
case FUNCTION_TRANSPOSE:
switch (variable_type)
{
case Utils::VARIABLE_TYPE_DMAT2:
return new FunctionObject::unary<DMat2 /* ResT */, DMat2 /* ArgT */>(function, "transpose",
Math::transpose);
case Utils::VARIABLE_TYPE_DMAT2X3:
return new FunctionObject::unary<DMat2x3 /* ResT */, DMat3x2 /* ArgT */>(function, "transpose",
Math::transpose);
case Utils::VARIABLE_TYPE_DMAT2X4:
return new FunctionObject::unary<DMat2x4 /* ResT */, DMat4x2 /* ArgT */>(function, "transpose",
Math::transpose);
case Utils::VARIABLE_TYPE_DMAT3:
return new FunctionObject::unary<DMat3 /* ResT */, DMat3 /* ArgT */>(function, "transpose",
Math::transpose);
case Utils::VARIABLE_TYPE_DMAT3X2:
return new FunctionObject::unary<DMat3x2 /* ResT */, DMat2x3 /* ArgT */>(function, "transpose",
Math::transpose);
case Utils::VARIABLE_TYPE_DMAT3X4:
return new FunctionObject::unary<DMat3x4 /* ResT */, DMat4x3 /* ArgT */>(function, "transpose",
Math::transpose);
case Utils::VARIABLE_TYPE_DMAT4:
return new FunctionObject::unary<DMat4 /* ResT */, DMat4 /* ArgT */>(function, "transpose",
Math::transpose);
case Utils::VARIABLE_TYPE_DMAT4X2:
return new FunctionObject::unary<DMat4x2 /* ResT */, DMat2x4 /* ArgT */>(function, "transpose",
Math::transpose);
case Utils::VARIABLE_TYPE_DMAT4X3:
return new FunctionObject::unary<DMat4x3 /* ResT */, DMat3x4 /* ArgT */>(function, "transpose",
Math::transpose);
default:
break;
}
break;
case FUNCTION_TRUNC:
return new FunctionObject::unaryByComponent<glw::GLdouble /* ResT */>(
function, "trunc", Math::trunc, variable_type /* res_type */, variable_type /* arg_type */);
case FUNCTION_UNPACKDOUBLE2X32:
return new FunctionObject::unary<tcu::UVec2 /* ResT */, glw::GLdouble /* ArgT */>(function, "unpackDouble2x32",
Math::unpackDouble2x32);
case FUNCTION_ISNAN:
return new FunctionObject::unaryByComponent<glw::GLuint /* ResT */>(
function, "isnan", Math::isnan_impl, uint_type /* res_type */, variable_type /* arg_type */);
case FUNCTION_ISINF:
return new FunctionObject::unaryByComponent<glw::GLuint /* ResT */>(
function, "isinf", Math::isinf_impl, uint_type /* res_type */, variable_type /* arg_type */);
default:
TCU_FAIL("Not implemented");
return 0;
}
TCU_FAIL("Not implemented");
return 0;
}
/** Get gl.uniform* that match type of argument. Assumes that type is matrix of double.
*
* @param argument Argument index
* @param function_object Function object
*
* @return Function pointer
**/
BuiltinFunctionTest::uniformDMatFunctionPointer BuiltinFunctionTest::getUniformFunctionForDMat(
glw::GLuint argument, const functionObject& function_object) const
{
const Utils::_variable_type argument_type = function_object.getArgumentType(argument);
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
switch (argument_type)
{
case Utils::VARIABLE_TYPE_DMAT2:
return gl.uniformMatrix2dv;
case Utils::VARIABLE_TYPE_DMAT2X3:
return gl.uniformMatrix2x3dv;
case Utils::VARIABLE_TYPE_DMAT2X4:
return gl.uniformMatrix2x4dv;
case Utils::VARIABLE_TYPE_DMAT3:
return gl.uniformMatrix3dv;
case Utils::VARIABLE_TYPE_DMAT3X2:
return gl.uniformMatrix3x2dv;
case Utils::VARIABLE_TYPE_DMAT3X4:
return gl.uniformMatrix3x4dv;
case Utils::VARIABLE_TYPE_DMAT4:
return gl.uniformMatrix4dv;
case Utils::VARIABLE_TYPE_DMAT4X2:
return gl.uniformMatrix4x2dv;
case Utils::VARIABLE_TYPE_DMAT4X3:
return gl.uniformMatrix4x3dv;
default:
break;
}
TCU_FAIL("Not implemented");
return 0;
}
/** Get gl.uniform* that match type of argument. Assumes that type is scalar or vector of double.
*
* @param argument Argument index
* @param function_object Function object
*
* @return Function pointer
**/
BuiltinFunctionTest::uniformDVecFunctionPointer BuiltinFunctionTest::getUniformFunctionForDVec(
glw::GLuint argument, const functionObject& function_object) const
{
const Utils::_variable_type argument_type = function_object.getArgumentType(argument);
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
switch (argument_type)
{
case Utils::VARIABLE_TYPE_DOUBLE:
return gl.uniform1dv;
case Utils::VARIABLE_TYPE_DVEC2:
return gl.uniform2dv;
case Utils::VARIABLE_TYPE_DVEC3:
return gl.uniform3dv;
case Utils::VARIABLE_TYPE_DVEC4:
return gl.uniform4dv;
default:
TCU_FAIL("Not implemented");
}
return 0;
}
/** Get gl.uniform* that match type of argument. Assumes that type is scalar or vector of signed integer.
*
* @param argument Argument index
* @param function_object Function object
*
* @return Function pointer
**/
BuiltinFunctionTest::uniformIVecFunctionPointer BuiltinFunctionTest::getUniformFunctionForIVec(
glw::GLuint argument, const functionObject& function_object) const
{
const Utils::_variable_type argument_type = function_object.getArgumentType(argument);
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
switch (argument_type)
{
case Utils::VARIABLE_TYPE_INT:
return gl.uniform1iv;
case Utils::VARIABLE_TYPE_IVEC2:
return gl.uniform2iv;
case Utils::VARIABLE_TYPE_IVEC3:
return gl.uniform3iv;
case Utils::VARIABLE_TYPE_IVEC4:
return gl.uniform4iv;
default:
TCU_FAIL("Not implemented");
}
return 0;
}
/** Get gl.uniform* that match type of argument. Assumes that type is scalar or vector of unsigned integer.
*
* @param argument Argument index
* @param function_object Function object
*
* @return Function pointer
**/
BuiltinFunctionTest::uniformUVecFunctionPointer BuiltinFunctionTest::getUniformFunctionForUVec(
glw::GLuint argument, const functionObject& function_object) const
{
const Utils::_variable_type argument_type = function_object.getArgumentType(argument);
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
switch (argument_type)
{
case Utils::VARIABLE_TYPE_UVEC2:
return gl.uniform2uiv;
default:
TCU_FAIL("Not implemented");
}
return 0;
}
/** Get name of uniform that will be used as <argument>.
*
* @param argument Argument index
*
* @return Name of uniform
**/
const glw::GLchar* BuiltinFunctionTest::getUniformName(glw::GLuint argument) const
{
switch (argument)
{
case 0:
return "uniform_0";
case 1:
return "uniform_1";
case 2:
return "uniform_2";
default:
TCU_FAIL("Not implemented");
return 0;
}
}
/** Get name of varying that will be used as <result>.
*
* @param result Result index
*
* @return Name of varying
**/
const glw::GLchar* BuiltinFunctionTest::getVaryingName(glw::GLuint result) const
{
switch (result)
{
case 0:
return "result_0";
case 1:
return "result_1";
case 2:
return "result_2";
default:
TCU_FAIL("Not implemented");
return 0;
}
}
/** Check if given combination of function and type is implemented
*
* @param function Function enumeration
* @param type Type details
*
* @return true if function is available for given type, false otherwise
**/
bool BuiltinFunctionTest::isFunctionImplemented(FunctionEnum function, const typeDetails& type) const
{
static const bool look_up_table[][3] = {
/* SCALAR, VECTOR, MATRIX */
/* FUNCTION_ABS: */ { true, true, false },
/* FUNCTION_CEIL: */ { true, true, false },
/* FUNCTION_CLAMP: */ { true, true, false },
/* FUNCTION_CLAMP_AGAINST_SCALAR: */ { false, true, false },
/* FUNCTION_CROSS: */ { false, true, false },
/* FUNCTION_DETERMINANT: */ { false, false, true },
/* FUNCTION_DISTANCE: */ { false, true, false },
/* FUNCTION_DOT: */ { false, true, false },
/* FUNCTION_EQUAL: */ { false, true, false },
/* FUNCTION_FACEFORWARD: */ { false, true, false },
/* FUNCTION_FLOOR: */ { true, true, false },
/* FUNCTION_FMA: */ { true, true, false },
/* FUNCTION_FRACT: */ { true, true, false },
/* FUNCTION_FREXP: */ { true, true, false },
/* FUNCTION_GREATERTHAN: */ { false, true, false },
/* FUNCTION_GREATERTHANEQUAL: */ { false, true, false },
/* FUNCTION_INVERSE: */ { false, false, true },
/* FUNCTION_INVERSESQRT: */ { true, true, false },
/* FUNCTION_LDEXP: */ { true, true, false },
/* FUNCTION_LESSTHAN: */ { false, true, false },
/* FUNCTION_LESSTHANEQUAL: */ { false, true, false },
/* FUNCTION_LENGTH: */ { false, true, false },
/* FUNCTION_MATRIXCOMPMULT: */ { false, false, true },
/* FUNCTION_MAX: */ { true, true, false },
/* FUNCTION_MAX_AGAINST_SCALAR: */ { false, true, false },
/* FUNCTION_MIN: */ { true, true, false },
/* FUNCTION_MIN_AGAINST_SCALAR: */ { false, true, false },
/* FUNCTION_MIX: */ { true, true, false },
/* FUNCTION_MOD: */ { true, true, false },
/* FUNCTION_MOD_AGAINST_SCALAR: */ { false, true, false },
/* FUNCTION_MODF: */ { true, true, false },
/* FUNCTION_NORMALIZE: */ { false, true, false },
/* FUNCTION_NOTEQUAL: */ { false, true, false },
/* FUNCTION_OUTERPRODUCT: */ { false, false, true },
/* FUNCTION_PACKDOUBLE2X32: */ { true, false, false },
/* FUNCTION_REFLECT: */ { false, true, false },
/* FUNCTION_REFRACT: */ { false, true, false },
/* FUNCTION_ROUND: */ { true, true, false },
/* FUNCTION_ROUNDEVEN: */ { true, true, false },
/* FUNCTION_SIGN: */ { true, false, false },
/* FUNCTION_SMOOTHSTEP: */ { true, true, false },
/* FUNCTION_SMOOTHSTEP_AGAINST_SCALAR: */ { false, true, false },
/* FUNCTION_SQRT: */ { true, true, false },
/* FUNCTION_STEP: */ { true, true, false },
/* FUNCTION_STEP_AGAINST_SCALAR: */ { false, true, false },
/* FUNCTION_TRANSPOSE: */ { false, false, false },
/* FUNCTION_TRUNC: */ { true, true, false },
/* FUNCTION_UNPACKDOUBLE2X32: */ { true, false, false },
/* FUNCTION_ISNAN: */ { true, true, false },
/* FUNCTION_ISINF: */ { true, true, false },
};
bool result = look_up_table[function][type.m_general_type];
if (true == result)
{
switch (function)
{
case FUNCTION_CROSS: /* Only 3 element vectors */
result = (3 == type.m_n_rows);
break;
case FUNCTION_DETERMINANT: /* Only square matrices */
case FUNCTION_INVERSE:
result = (type.m_n_columns == type.m_n_rows);
break;
default:
break;
}
}
return result;
}
/** Logs variable of given type: name (type) [values]
*
* @param buffer Source of data
* @param name Name of variable
* @param type Type of variable
**/
void BuiltinFunctionTest::logVariableType(const glw::GLvoid* buffer, const glw::GLchar* name,
Utils::_variable_type type) const
{
const Utils::_variable_type base_type = Utils::getBaseVariableType(type);
const glw::GLuint n_components = Utils::getNumberOfComponentsForVariableType(type);
tcu::MessageBuilder message = m_context.getTestContext().getLog() << tcu::TestLog::Message;
message << name << " (" << Utils::getVariableTypeString(type) << ") [";
for (glw::GLuint component = 0; component < n_components; ++component)
{
if (0 != component)
{
message << ", ";
}
switch (base_type)
{
case Utils::VARIABLE_TYPE_DOUBLE:
message << ((glw::GLdouble*)buffer)[component];
break;
case Utils::VARIABLE_TYPE_INT:
message << ((glw::GLint*)buffer)[component];
break;
case Utils::VARIABLE_TYPE_UINT:
message << ((glw::GLuint*)buffer)[component];
break;
default:
TCU_FAIL("Not implemented");
}
}
message << "]" << tcu::TestLog::EndMessage;
}
/** Prepare input arguments, data are stored in <buffer>
*
* @param function_object Function object
* @param vertex Vertex index
* @param buffer Buffer pointer
**/
void BuiltinFunctionTest::prepareArgument(const functionObject& function_object, glw::GLuint vertex,
glw::GLubyte* buffer)
{
const glw::GLuint n_arguments = function_object.getArgumentCount();
for (glw::GLuint argument = 0; argument < n_arguments; ++argument)
{
const glw::GLuint offset = function_object.getArgumentOffset(argument);
prepareComponents(function_object, vertex, argument, buffer + offset);
}
}
/** Prepare components for given <function_object>, <vertex> and <argument>
*
* @param function_object Function object
* @param vertex Vertex index
* @param argument Argument index
* @param buffer Buffer pointer
**/
void BuiltinFunctionTest::prepareComponents(const functionObject& function_object, glw::GLuint vertex,
glw::GLuint argument, glw::GLubyte* buffer)
{
glw::GLuint argument_index[3] = { 0 };
glw::GLuint argument_reset[3] = { 0 };
glw::GLuint argument_step[3] = { 0 };
glw::GLdouble double_argument_start[3] = { 0.0 };
const Utils::_variable_type base_arg_type = Utils::getBaseVariableType(function_object.getArgumentType(argument));
glw::GLuint int_argument_start = -4;
const glw::GLuint n_arguments = function_object.getArgumentCount();
const glw::GLuint n_components = function_object.getArgumentComponents(argument);
glw::GLuint uint_argument_start = 0;
switch (n_arguments)
{
case 1:
argument_step[0] = 1;
argument_reset[0] = 1024;
double_argument_start[0] = -511.5;
break;
case 2:
argument_step[0] = 32;
argument_step[1] = 1;
argument_reset[0] = 32;
argument_reset[1] = 32;
double_argument_start[0] = -15.5;
double_argument_start[1] = -15.5;
break;
case 3:
argument_step[0] = 64;
argument_step[1] = 8;
argument_step[2] = 1;
argument_reset[0] = 16;
argument_reset[1] = 8;
argument_reset[2] = 8;
double_argument_start[0] = -7.5;
double_argument_start[1] = -3.5;
double_argument_start[2] = -3.5;
break;
default:
TCU_FAIL("Not implemented");
return;
}
switch (function_object.getFunctionEnum())
{
case FUNCTION_CLAMP: /* arg_2 must be less than arg_3 */
case FUNCTION_CLAMP_AGAINST_SCALAR:
double_argument_start[2] = 4.5;
break;
case FUNCTION_INVERSESQRT: /* inversesqrt is undefined for argument <= 0 */
double_argument_start[0] = 16.5;
break;
case FUNCTION_SMOOTHSTEP: /* arg_1 must be less than arg_2 */
case FUNCTION_SMOOTHSTEP_AGAINST_SCALAR:
argument_step[0] = 1;
argument_step[1] = 8;
argument_step[2] = 64;
argument_reset[0] = 8;
argument_reset[1] = 8;
argument_reset[2] = 16;
double_argument_start[0] = -3.5;
double_argument_start[1] = 4.5;
double_argument_start[2] = -7.5;
break;
default:
break;
}
for (glw::GLuint i = 0; i < n_arguments; ++i)
{
argument_index[i] = (vertex / argument_step[i]) % argument_reset[i];
}
switch (base_arg_type)
{
case Utils::VARIABLE_TYPE_DOUBLE:
{
glw::GLdouble* argument_dst = (glw::GLdouble*)buffer;
double_argument_start[argument] += argument_index[argument];
for (glw::GLuint component = 0; component < n_components; ++component)
{
glw::GLdouble value = double_argument_start[argument] + ((glw::GLdouble)component) / 8.0;
switch (function_object.getFunctionEnum())
{
case FUNCTION_ROUND: /* Result for 0.5 depends on implementation */
if (0.5 == Math::fract(value))
{
value += 0.01;
}
break;
default:
break;
}
argument_dst[component] = value;
}
}
break;
case Utils::VARIABLE_TYPE_INT:
{
glw::GLint* argument_dst = (glw::GLint*)buffer;
uint_argument_start += argument_index[argument];
for (glw::GLuint component = 0; component < n_components; ++component)
{
const glw::GLint value = int_argument_start + component;
argument_dst[component] = value;
}
}
break;
case Utils::VARIABLE_TYPE_UINT:
{
glw::GLuint* argument_dst = (glw::GLuint*)buffer;
uint_argument_start += argument_index[argument];
for (glw::GLuint component = 0; component < n_components; ++component)
{
const glw::GLuint value = uint_argument_start + component;
argument_dst[component] = value;
}
}
break;
default:
TCU_FAIL("Not implemented");
return;
}
}
/** Prepare programInfo for given functionObject
*
* @param function_object Function object
* @param out_program_info Program info
**/
void BuiltinFunctionTest::prepareProgram(const functionObject& function_object, Utils::programInfo& out_program_info)
{
const glw::GLuint n_varying_names = function_object.getResultCount();
static const glw::GLchar* varying_names[3] = { getVaryingName(0), getVaryingName(1), getVaryingName(2) };
prepareVertexShaderCode(function_object);
out_program_info.build(0 /* cs */, 0 /* fs */, 0 /* gs */, 0 /* tcs */, 0 /* tes */, m_vertex_shader_code.c_str(),
varying_names, n_varying_names);
}
/** Prepare input data and expected results for given function object
*
* @param function_object Function object
**/
void BuiltinFunctionTest::prepareTestData(const functionObject& function_object)
{
const glw::GLuint result_stride = function_object.getResultStride();
const glw::GLuint result_buffer_size = result_stride * m_n_veritces;
const glw::GLuint argument_stride = function_object.getArgumentStride();
const glw::GLuint argument_buffer_size = m_n_veritces * argument_stride;
m_argument_data.clear();
m_expected_results_data.clear();
m_argument_data.resize(argument_buffer_size);
m_expected_results_data.resize(result_buffer_size);
for (glw::GLuint vertex = 0; vertex < m_n_veritces; ++vertex)
{
const glw::GLuint result_offset = vertex * result_stride;
glw::GLdouble* result_dst = (glw::GLdouble*)&m_expected_results_data[result_offset];
const glw::GLuint argument_offset = vertex * argument_stride;
glw::GLubyte* argument_dst = &m_argument_data[argument_offset];
prepareArgument(function_object, vertex, argument_dst);
function_object.call(result_dst, argument_dst);
}
}
/** Prepare source code of vertex shader for given function object. Result is stored in m_vertex_shader_code.
*
* @param function_object Function object
**/
void BuiltinFunctionTest::prepareVertexShaderCode(const functionObject& function_object)
{
static const glw::GLchar* shader_template_code = "#version 400 core\n"
"\n"
"precision highp float;\n"
"\n"
"ARGUMENT_DEFINITION"
"\n"
"RESULT_DEFINITION"
"\n"
"void main()\n"
"{\n"
" RESULT_NAME = RESULT_TYPE(FUNCTION_NAME(ARGUMENT));\n"
"}\n"
"\n";
static const glw::GLchar* argument_definition_token = "ARGUMENT_DEFINITION";
static const glw::GLchar* argument_token = "ARGUMENT";
static const glw::GLchar* function_name_token = "FUNCTION_NAME";
static const glw::GLchar* result_definition_token = "RESULT_DEFINITION";
static const glw::GLchar* result_name_token = "RESULT_NAME";
static const glw::GLchar* result_type_token = "RESULT_TYPE";
static const glw::GLchar* uniform_name_token = "UNIFORM_NAME";
static const glw::GLchar* uniform_type_token = "UNIFORM_TYPE";
static const glw::GLchar* argument_definition = "uniform UNIFORM_TYPE UNIFORM_NAME;\nARGUMENT_DEFINITION";
static const glw::GLchar* argument_str = ", UNIFORM_NAMEARGUMENT";
static const glw::GLchar* first_argument = "UNIFORM_NAMEARGUMENT";
static const glw::GLchar* result_definition = "flat out RESULT_TYPE RESULT_NAME;\nRESULT_DEFINITION";
const glw::GLuint argument_definition_length = (glw::GLuint)strlen(argument_definition);
const glw::GLuint first_argument_length = (glw::GLuint)strlen(first_argument);
const glw::GLuint n_arguments = function_object.getArgumentCount();
const glw::GLuint n_results = function_object.getResultCount();
const glw::GLuint result_definition_length = (glw::GLuint)strlen(result_definition);
std::string result_type = Utils::getVariableTypeString(function_object.getResultType(0));
size_t search_position = 0;
std::string string = shader_template_code;
/* Replace ARGUMENT_DEFINITION with definitions */
for (glw::GLuint argument = 0; argument < n_arguments; ++argument)
{
Utils::_variable_type argument_type = function_object.getArgumentType(argument);
const glw::GLchar* uniform_name = getUniformName(argument);
std::string uniform_type = Utils::getVariableTypeString(argument_type);
Utils::replaceToken(argument_definition_token, search_position, argument_definition, string);
search_position -= argument_definition_length;
Utils::replaceToken(uniform_type_token, search_position, uniform_type.c_str(), string);
Utils::replaceToken(uniform_name_token, search_position, uniform_name, string);
}
/* Remove ARGUMENT_DEFINITION */
Utils::replaceToken(argument_definition_token, search_position, "", string);
/* Replace RESULT_DEFINITION with definitions */
for (glw::GLuint result = 0; result < n_results; ++result)
{
Utils::_variable_type variable_type = function_object.getResultType(result);
const glw::GLchar* varying_name = getVaryingName(result);
std::string varying_type = Utils::getVariableTypeString(variable_type);
Utils::replaceToken(result_definition_token, search_position, result_definition, string);
search_position -= result_definition_length;
Utils::replaceToken(result_type_token, search_position, varying_type.c_str(), string);
Utils::replaceToken(result_name_token, search_position, varying_name, string);
}
/* Remove RESULT_DEFINITION */
Utils::replaceToken(result_definition_token, search_position, "", string);
/* Replace RESULT_NAME */
Utils::replaceToken(result_name_token, search_position, getVaryingName(0), string);
/* Replace RESULT_TYPE */
Utils::replaceToken(result_type_token, search_position, result_type.c_str(), string);
/* Replace FUNCTION_NAME */
Utils::replaceToken(function_name_token, search_position, function_object.getName(), string);
/* Replace ARGUMENT with list of arguments */
for (glw::GLuint argument = 0; argument < n_arguments; ++argument)
{
const glw::GLchar* uniform_name = getUniformName(argument);
if (0 == argument)
{
Utils::replaceToken(argument_token, search_position, first_argument, string);
}
else
{
Utils::replaceToken(argument_token, search_position, argument_str, string);
}
search_position -= first_argument_length;
Utils::replaceToken(uniform_name_token, search_position, uniform_name, string);
}
for (glw::GLuint result = 1; result < n_results; ++result)
{
const glw::GLchar* varying_name = getVaryingName(result);
Utils::replaceToken(argument_token, search_position, argument_str, string);
search_position -= first_argument_length;
Utils::replaceToken(uniform_name_token, search_position, varying_name, string);
}
/* Remove ARGUMENT */
Utils::replaceToken(argument_token, search_position, "", string);
m_vertex_shader_code = string;
}
/** Test single function with one type
*
* param function Function enumeration
* param type Type details
*
* @return true if test pass (or function is not available for <type>), false otherwise
**/
bool BuiltinFunctionTest::test(FunctionEnum function, const typeDetails& type)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Skip if function is not implemented for type */
if (false == isFunctionImplemented(function, type))
{
return true;
}
Utils::programInfo program(m_context);
de::UniquePtr<functionObject> function_object(getFunctionObject(function, type));
prepareProgram(*function_object, program);
prepareTestData(*function_object);
/* Set up program */
gl.useProgram(program.m_program_object_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "UseProgram");
for (glw::GLuint vertex = 0; vertex < m_n_veritces; ++vertex)
{
testBegin(*function_object, program.m_program_object_id, vertex);
gl.beginTransformFeedback(GL_POINTS);
GLU_EXPECT_NO_ERROR(gl.getError(), "BeginTransformFeedback");
gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
GLU_EXPECT_NO_ERROR(gl.getError(), "DrawArrays");
gl.endTransformFeedback();
GLU_EXPECT_NO_ERROR(gl.getError(), "EndTransformFeedback");
if (false == verifyResults(*function_object, vertex))
{
return false;
}
}
return true;
}
/** Update transform feedback buffer and uniforms
*
* @param function_object Function object
* @param program_id Program object id
* @param vertex Vertex index
**/
void BuiltinFunctionTest::testBegin(const functionObject& function_object, glw::GLuint program_id, glw::GLuint vertex)
{
const glw::GLuint arguments_stride = function_object.getArgumentStride();
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
const glw::GLuint n_arguments = function_object.getArgumentCount();
const glw::GLuint result_buffer_size = function_object.getResultStride();
const glw::GLuint vertex_offset = arguments_stride * vertex;
/* Update transform feedback buffer */
std::vector<glw::GLubyte> transform_feedback_buffer_data;
transform_feedback_buffer_data.resize(result_buffer_size);
gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_transform_feedback_buffer_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindBuffer");
gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, result_buffer_size, &transform_feedback_buffer_data[0],
GL_DYNAMIC_COPY);
GLU_EXPECT_NO_ERROR(gl.getError(), "BufferData");
gl.bindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, m_transform_feedback_buffer_id, 0 /* offset */,
result_buffer_size);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindBufferRange");
/* Update VAO */
gl.bindVertexArray(m_vertex_array_object_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindVertexArray");
for (glw::GLuint argument = 0; argument < n_arguments; ++argument)
{
const glw::GLuint argument_offset = function_object.getArgumentOffset(argument);
const Utils::_variable_type argument_type = function_object.getArgumentType(argument);
const glw::GLuint n_columns = Utils::getNumberOfColumnsForVariableType(argument_type);
const glw::GLchar* uniform_name = getUniformName(argument);
const glw::GLint uniform_location = gl.getUniformLocation(program_id, uniform_name);
const glw::GLdouble* uniform_src = (glw::GLdouble*)&m_argument_data[vertex_offset + argument_offset];
GLU_EXPECT_NO_ERROR(gl.getError(), "GetUniformLocation");
if (-1 == uniform_location)
{
TCU_FAIL("Inactive uniform");
}
if (1 == n_columns)
{
switch (Utils::getBaseVariableType(argument_type))
{
case Utils::VARIABLE_TYPE_DOUBLE:
{
uniformDVecFunctionPointer p_uniform_function = getUniformFunctionForDVec(argument, function_object);
p_uniform_function(uniform_location, 1 /* count */, uniform_src);
}
break;
case Utils::VARIABLE_TYPE_UINT:
{
uniformUVecFunctionPointer p_uniform_function = getUniformFunctionForUVec(argument, function_object);
p_uniform_function(uniform_location, 1 /* count */, (glw::GLuint*)uniform_src);
}
break;
case Utils::VARIABLE_TYPE_INT:
{
uniformIVecFunctionPointer p_uniform_function = getUniformFunctionForIVec(argument, function_object);
p_uniform_function(uniform_location, 1 /* count */, (glw::GLint*)uniform_src);
}
break;
default:
TCU_FAIL("Not implemented");
}
}
else
{
uniformDMatFunctionPointer p_uniform_function = getUniformFunctionForDMat(argument, function_object);
p_uniform_function(uniform_location, 1 /* count */, GL_FALSE /* transpose */, uniform_src);
}
}
}
/** Init GL obejcts
*
**/
void BuiltinFunctionTest::testInit()
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.genBuffers(1, &m_transform_feedback_buffer_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "GenBuffers");
gl.genVertexArrays(1, &m_vertex_array_object_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "GenVertexArrays");
gl.enable(GL_RASTERIZER_DISCARD);
}
/** Checks if function result is an acceptable edge case
*
* @param function_object Function object
* @param vertex Vertex index
*
* @return true if all results are as expected, false otherwise
**/
bool BuiltinFunctionTest::isResultEdgeCase(const functionObject& function_object, glw::GLuint vertex,
const Utils::_variable_type result_type,
const glw::GLvoid* expected_result_src, const glw::GLvoid* result_src)
{
FunctionEnum function_type = function_object.getFunctionEnum();
switch (function_type)
{
// mod(a, b) is defined as a - b * floor(a/b) and mod(a,a) should be 0. However OpenGL
// allows for some error in division, so a/a could actually end up being 1.0 - 1ULP.
// In such a case, floor(a/a) would end up as 0, with mod(a,a) becoming a.
case FUNCTION_MOD:
case FUNCTION_MOD_AGAINST_SCALAR:
{
const glw::GLuint arguments_stride = function_object.getArgumentStride();
const glw::GLuint vertex_offset = arguments_stride * vertex;
const glw::GLuint argument_1_offset = function_object.getArgumentOffset(0);
const glw::GLuint argument_2_offset = function_object.getArgumentOffset(1);
const glw::GLuint argument_1_index = argument_1_offset + vertex_offset;
const glw::GLuint argument_2_index = argument_2_offset + vertex_offset;
const glw::GLubyte* argument_1_bytes = &m_argument_data[argument_1_index];
const glw::GLubyte* argument_2_bytes = &m_argument_data[argument_2_index];
const glw::GLdouble* argument_1 = reinterpret_cast<const glw::GLdouble*>(argument_1_bytes);
const glw::GLdouble* argument_2 = reinterpret_cast<const glw::GLdouble*>(argument_2_bytes);
const glw::GLdouble* expected_result = reinterpret_cast<const glw::GLdouble*>(expected_result_src);
const glw::GLdouble* actual_result = reinterpret_cast<const glw::GLdouble*>(result_src);
bool edge_case_present = false;
bool recheck = false;
// verify if there is a mod(a, a) case and prepare new expected result
const glw::GLuint n_components = Utils::getNumberOfComponentsForVariableType(result_type);
std::vector<glw::GLdouble> corrected_expected_result(n_components, 0.0);
for (glw::GLuint component = 0; component < n_components; ++component)
{
glw::GLdouble expected_result_component = expected_result[component];
glw::GLdouble actual_result_component = actual_result[component];
glw::GLdouble argument_1_component = argument_1[component];
glw::GLdouble argument_2_component = argument_2[(function_type == FUNCTION_MOD) ? component : 0];
// if coresponding components of arguments are equal and if component of first argument
// and component of result are equal then expected result must be corrected
bool possible_edge_case = m_epsilon > de::abs((argument_1_component / argument_2_component) -
round(argument_1_component / argument_2_component));
edge_case_present = possible_edge_case &&
(m_epsilon > de::abs(argument_2_component - actual_result_component));
recheck |= edge_case_present;
corrected_expected_result[component] = edge_case_present ? argument_2_component : expected_result_component;
}
// recheck test result with corrected expected result
return (recheck && compare(result_type, &(corrected_expected_result[0]), result_src));
}
default:
return false;
}
}
/** Compare contents of transform feedback buffer with expected results
*
* @param function_object Function object
* @param vertex Vertex index
*
* @return true if all results are as expected, false otherwise
**/
bool BuiltinFunctionTest::verifyResults(const functionObject& function_object, glw::GLuint vertex)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
bool test_result = true;
const glw::GLuint n_results = function_object.getResultCount();
const glw::GLuint results_stride = function_object.getResultStride();
const glw::GLuint results_offset = vertex * results_stride;
const glw::GLubyte* expected_results = &m_expected_results_data[results_offset];
/* Get transform feedback data */
gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_transform_feedback_buffer_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindBuffer");
glw::GLubyte* feedback_data = (glw::GLubyte*)gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
GLU_EXPECT_NO_ERROR(gl.getError(), "MapBuffer");
for (glw::GLuint result = 0; result < n_results; ++result)
{
const Utils::_variable_type result_type = function_object.getResultType(result);
const glw::GLuint result_offset = function_object.getResultOffset(result);
const glw::GLvoid* expected_result_src = expected_results + result_offset;
const glw::GLvoid* result_src = feedback_data + result_offset;
if (compare(result_type, expected_result_src, result_src))
continue;
if (!isResultEdgeCase(function_object, vertex, result_type, expected_result_src, result_src))
{
test_result = false;
break;
}
}
/* Unmap transform feedback buffer */
gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
GLU_EXPECT_NO_ERROR(gl.getError(), "UnmapBuffer");
if (false == test_result)
{
const glw::GLuint argument_stride = function_object.getArgumentStride();
const glw::GLuint arguments_offset = vertex * argument_stride;
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Error. Invalid result."
<< tcu::TestLog::EndMessage;
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Function: " << function_object.getName()
<< tcu::TestLog::EndMessage;
for (glw::GLuint result = 0; result < n_results; ++result)
{
const Utils::_variable_type result_type = function_object.getResultType(result);
const glw::GLuint result_offset = function_object.getResultOffset(result);
const glw::GLvoid* expected_result_src = expected_results + result_offset;
const glw::GLvoid* result_src = feedback_data + result_offset;
logVariableType(result_src, "Result", result_type);
logVariableType(expected_result_src, "Expected result", result_type);
}
for (glw::GLuint argument = 0; argument < function_object.getArgumentCount(); ++argument)
{
const glw::GLuint argument_offset = function_object.getArgumentOffset(argument);
const glw::GLubyte* argument_src = &m_argument_data[arguments_offset + argument_offset];
logVariableType(argument_src, "Argument", function_object.getArgumentType(argument));
}
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Shader:\n"
<< m_vertex_shader_code << tcu::TestLog::EndMessage;
}
return test_result;
}
/** Constructor.
*
* @param context Rendering context.
**/
GPUShaderFP64Tests::GPUShaderFP64Tests(deqp::Context& context)
: TestCaseGroup(context, "gpu_shader_fp64", "Verifies \"gpu_shader_fp64\" functionality")
{
/* Left blank on purpose */
}
/** Initializes a texture_storage_multisample test group.
*
**/
void GPUShaderFP64Tests::init(void)
{
TestCaseGroup* fp64 = new TestCaseGroup(m_context, "fp64", "");
fp64->addChild(new GPUShaderFP64Test1(m_context));
fp64->addChild(new GPUShaderFP64Test2(m_context));
fp64->addChild(new GPUShaderFP64Test3(m_context));
fp64->addChild(new GPUShaderFP64Test4(m_context));
fp64->addChild(new GPUShaderFP64Test5(m_context));
fp64->addChild(new GPUShaderFP64Test6(m_context));
fp64->addChild(new GPUShaderFP64Test7(m_context));
fp64->addChild(new GPUShaderFP64Test8(m_context));
fp64->addChild(new GPUShaderFP64Test9(m_context));
addChild(fp64);
TypeDefinition typeDefinition[] =
{
{ "double", 1, 1 },
{ "dvec2", 1, 2 },
{ "dvec3", 1, 3 },
{ "dvec4", 1, 4 },
{ "dmat2", 2, 2 },
{ "dmat2x3", 2, 3 },
{ "dmat2x4", 2, 4 },
{ "dmat3x2", 3, 2 },
{ "dmat3", 3, 3 },
{ "dmat3x4", 3, 4 },
{ "dmat4x2", 4, 2 },
{ "dmat4x3", 4, 3 },
{ "dmat4", 4, 4 }
};
struct BuiltinFunctions
{
std::string name;
FunctionEnum function;
} builtinFunctions[] = {
{ "abs", FUNCTION_ABS },
{ "ceil", FUNCTION_CEIL },
{ "clamp", FUNCTION_CLAMP },
{ "clamp_against_scalar", FUNCTION_CLAMP_AGAINST_SCALAR },
{ "cross", FUNCTION_CROSS },
{ "determinant", FUNCTION_DETERMINANT },
{ "distance", FUNCTION_DISTANCE },
{ "dot", FUNCTION_DOT },
{ "equal", FUNCTION_EQUAL },
{ "faceforward", FUNCTION_FACEFORWARD },
{ "floor", FUNCTION_FLOOR },
{ "fma", FUNCTION_FMA },
{ "fract", FUNCTION_FRACT },
{ "frexp", FUNCTION_FREXP },
{ "greaterthan", FUNCTION_GREATERTHAN },
{ "greaterthanequal", FUNCTION_GREATERTHANEQUAL },
{ "inverse", FUNCTION_INVERSE },
{ "inversesqrt", FUNCTION_INVERSESQRT },
{ "ldexp", FUNCTION_LDEXP },
{ "lessthan", FUNCTION_LESSTHAN },
{ "lessthanequal", FUNCTION_LESSTHANEQUAL },
{ "length", FUNCTION_LENGTH },
{ "matrixcompmult", FUNCTION_MATRIXCOMPMULT },
{ "max", FUNCTION_MAX },
{ "max_against_scalar", FUNCTION_MAX_AGAINST_SCALAR },
{ "min", FUNCTION_MIN },
{ "min_against_scalar", FUNCTION_MIN_AGAINST_SCALAR },
{ "mix", FUNCTION_MIX },
{ "mod", FUNCTION_MOD },
{ "mod_against_scalar", FUNCTION_MOD_AGAINST_SCALAR },
{ "modf", FUNCTION_MODF },
{ "normalize", FUNCTION_NORMALIZE },
{ "notequal", FUNCTION_NOTEQUAL },
{ "outerproduct", FUNCTION_OUTERPRODUCT },
{ "packdouble2x32", FUNCTION_PACKDOUBLE2X32 },
{ "reflect", FUNCTION_REFLECT },
{ "refract", FUNCTION_REFRACT },
{ "round", FUNCTION_ROUND },
{ "roundeven", FUNCTION_ROUNDEVEN },
{ "sign", FUNCTION_SIGN },
{ "smoothstep", FUNCTION_SMOOTHSTEP },
{ "smoothstep_against_scalar", FUNCTION_SMOOTHSTEP_AGAINST_SCALAR },
{ "sqrt", FUNCTION_SQRT },
{ "step", FUNCTION_STEP },
{ "step_against_scalar", FUNCTION_STEP_AGAINST_SCALAR },
{ "transpose", FUNCTION_TRANSPOSE },
{ "trunc", FUNCTION_TRUNC },
{ "unpackdouble2x32", FUNCTION_UNPACKDOUBLE2X32 },
{ "isnan", FUNCTION_ISNAN },
{ "isinf", FUNCTION_ISINF }
};
TestCaseGroup* builin = new TestCaseGroup(m_context, "builtin", "");
for (int i = 0; i < DE_LENGTH_OF_ARRAY(builtinFunctions); ++i)
{
const BuiltinFunctions& bf = builtinFunctions[i];
for (int j = 0; j < DE_LENGTH_OF_ARRAY(typeDefinition); ++j)
{
std::string caseName = bf.name + "_" + typeDefinition[j].name;
builin->addChild(new BuiltinFunctionTest(m_context, caseName, bf.function, typeDefinition[j]));
}
}
addChild(builin);
}
} /* glcts namespace */