blob: 67806b82b7cadaabfe3fafec6c0aa57b1403cfd9 [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 gl4cShaderSubroutineTests.cpp
* \brief Implements conformance tests for "Shader Subroutine" functionality.
*/ /*-------------------------------------------------------------------*/
#include "gl4cShaderSubroutineTests.hpp"
#include "gluContextInfo.hpp"
#include "glwEnums.hpp"
#include "glwFunctions.hpp"
#include "tcuMatrix.hpp"
#include <cmath>
#include <cstring>
#include <deMath.h>
using namespace glw;
namespace gl4cts
{
namespace ShaderSubroutine
{
/** Constructor.
*
* @param context CTS context.
**/
Utils::buffer::buffer(deqp::Context& context) : m_id(0), m_context(context)
{
}
/** Destructor
*
**/
Utils::buffer::~buffer()
{
if (0 != m_id)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.deleteBuffers(1, &m_id);
m_id = 0;
}
}
/** Execute BindBufferRange
*
* @param target <target> parameter
* @param index <index> parameter
* @param offset <offset> parameter
* @param size <size> parameter
**/
void Utils::buffer::bindRange(glw::GLenum target, glw::GLuint index, glw::GLintptr offset, glw::GLsizeiptr size)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.bindBufferRange(target, index, m_id, offset, size);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindBufferRange");
}
/** Execute GenBuffer
*
**/
void Utils::buffer::generate()
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.genBuffers(1, &m_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "GenBuffers");
}
/** Execute BufferData
*
* @param target <target> parameter
* @param size <size> parameter
* @param data <data> parameter
* @param usage <usage> parameter
**/
void Utils::buffer::update(glw::GLenum target, glw::GLsizeiptr size, glw::GLvoid* data, glw::GLenum usage)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.bindBuffer(target, m_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "bindBuffer");
gl.bufferData(target, size, data, usage);
GLU_EXPECT_NO_ERROR(gl.getError(), "bufferData");
}
/** Constructor
*
* @param context CTS context
**/
Utils::framebuffer::framebuffer(deqp::Context& context) : m_id(0), m_context(context)
{
/* Nothing to be done here */
}
/** Destructor
*
**/
Utils::framebuffer::~framebuffer()
{
if (0 != m_id)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.deleteFramebuffers(1, &m_id);
m_id = 0;
}
}
/** Attach texture to specified attachment
*
* @param attachment Attachment
* @param texture_id Texture id
* @param width Texture width
* @param height Texture height
**/
void Utils::framebuffer::attachTexture(glw::GLenum attachment, glw::GLuint texture_id, glw::GLuint width,
glw::GLuint height)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
bind();
gl.bindTexture(GL_TEXTURE_2D, texture_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture");
gl.framebufferTexture2D(GL_DRAW_FRAMEBUFFER, attachment, GL_TEXTURE_2D, texture_id, 0 /* level */);
GLU_EXPECT_NO_ERROR(gl.getError(), "FramebufferTexture2D");
gl.viewport(0 /* x */, 0 /* y */, width, height);
GLU_EXPECT_NO_ERROR(gl.getError(), "Viewport");
}
/** Binds framebuffer to DRAW_FRAMEBUFFER
*
**/
void Utils::framebuffer::bind()
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, m_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindFramebuffer");
}
/** Clear framebuffer
*
* @param mask <mask> parameter of glClear. Decides which shall be cleared
**/
void Utils::framebuffer::clear(glw::GLenum mask)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.clear(mask);
GLU_EXPECT_NO_ERROR(gl.getError(), "Clear");
}
/** Specifie clear color
*
* @param red Red channel
* @param green Green channel
* @param blue Blue channel
* @param alpha Alpha channel
**/
void Utils::framebuffer::clearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.clearColor(red, green, blue, alpha);
GLU_EXPECT_NO_ERROR(gl.getError(), "ClearColor");
}
/** Generate framebuffer
*
**/
void Utils::framebuffer::generate()
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.genFramebuffers(1, &m_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "GenFramebuffers");
}
const glw::GLenum Utils::program::ARB_COMPUTE_SHADER = 0x91B9;
/** Constructor.
*
* @param context CTS context.
**/
Utils::program::program(deqp::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)
, m_context(context)
{
/* Nothing to be done here */
}
/** Destructor
*
**/
Utils::program::~program()
{
remove();
}
/** 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
* @param is_separable Selects if monolithis or separable program should be built. Defaults to false
**/
void Utils::program::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, bool is_separable)
{
/* 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");
}
/* Set separable parameter */
if (true == is_separable)
{
gl.programParameteri(m_program_object_id, GL_PROGRAM_SEPARABLE, GL_TRUE);
GLU_EXPECT_NO_ERROR(gl.getError(), "ProgramParameteri");
}
/* Link program */
link();
}
/** Compile shader
*
* @param shader_id Shader object id
* @param shader_code Shader source code
**/
void Utils::program::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");
}
}
/** Checks whether the tested driver supports GL_ARB_get_program_binary
*
* @return true if the extension is supported and, also, at least one binary format.
**/
bool Utils::program::isProgramBinarySupported() const
{
glw::GLint n_program_binary_formats = 0;
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
if (m_context.getContextInfo().isExtensionSupported("GL_ARB_get_program_binary"))
{
gl.getIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &n_program_binary_formats);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() call failed.");
}
return n_program_binary_formats > 0;
}
/** Create program from provided binary
*
* @param binary Buffer with binary form of program
* @param binary_format Format of <binary> data
**/
void Utils::program::createFromBinary(const std::vector<GLubyte>& binary, GLenum binary_format)
{
/* GL entry points */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Create program object */
m_program_object_id = gl.createProgram();
GLU_EXPECT_NO_ERROR(gl.getError(), "CreateProgram");
gl.programBinary(m_program_object_id, binary_format, &binary[0], (GLsizei)binary.size());
GLU_EXPECT_NO_ERROR(gl.getError(), "ProgramBinary");
}
/** Get binary form of program
*
* @param binary Buffer for binary data
* @param binary_format Format of binary data
**/
void Utils::program::getBinary(std::vector<GLubyte>& binary, GLenum& binary_format) const
{
/* GL entry points */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Get binary size */
GLint length = 0;
gl.getProgramiv(m_program_object_id, GL_PROGRAM_BINARY_LENGTH, &length);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramiv");
/* Allocate storage */
binary.resize(length);
/* Get binary */
gl.getProgramBinary(m_program_object_id, (GLsizei)binary.size(), &length, &binary_format, &binary[0]);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramBinary");
}
/** Get subroutine index
*
* @param subroutine_name Subroutine name
*
* @return Index of subroutine
**/
GLuint Utils::program::getSubroutineIndex(const glw::GLchar* subroutine_name, glw::GLenum shader_stage) const
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
GLuint index = -1;
index = gl.getSubroutineIndex(m_program_object_id, shader_stage, subroutine_name);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetSubroutineIndex");
if (GL_INVALID_INDEX == index)
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Subroutine: " << subroutine_name
<< " is not available" << tcu::TestLog::EndMessage;
TCU_FAIL("Subroutine is not available");
}
return index;
}
/** Get subroutine uniform location
*
* @param uniform_name Subroutine uniform name
*
* @return Location of subroutine uniform
**/
GLint Utils::program::getSubroutineUniformLocation(const glw::GLchar* uniform_name, glw::GLenum shader_stage) const
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
GLint location = -1;
location = gl.getSubroutineUniformLocation(m_program_object_id, shader_stage, uniform_name);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetSubroutineUniformLocation");
if (-1 == location)
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Subroutine uniform: " << uniform_name
<< " is not available" << tcu::TestLog::EndMessage;
TCU_FAIL("Subroutine uniform is not available");
}
return location;
}
/** Get uniform location
*
* @param uniform_name Subroutine uniform name
*
* @return Location of uniform
**/
GLint Utils::program::getUniformLocation(const glw::GLchar* uniform_name) const
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
GLint location = -1;
location = gl.getUniformLocation(m_program_object_id, uniform_name);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetUniformLocation");
if (-1 == location)
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Uniform: " << uniform_name
<< " is not available" << tcu::TestLog::EndMessage;
TCU_FAIL("Uniform is not available");
}
return location;
}
/** Attach shaders and link program
*
**/
void Utils::program::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");
}
}
/** Delete program object and all attached shaders
*
**/
void Utils::program::remove()
{
/* 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;
}
}
/** Execute UseProgram
*
**/
void Utils::program::use() const
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.useProgram(m_program_object_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "UseProgram");
}
/** Constructor.
*
* @param context CTS context.
**/
Utils::texture::texture(deqp::Context& context) : m_id(0), m_context(context)
{
/* Nothing to done here */
}
/** Destructor
*
**/
Utils::texture::~texture()
{
if (0 != m_id)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.deleteTextures(1, &m_id);
m_id = 0;
}
}
/** Bind texture to GL_TEXTURE_2D
*
**/
void Utils::texture::bind()
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.bindTexture(GL_TEXTURE_2D, m_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindTexture");
}
/** Create 2d texture
*
* @param width Width of texture
* @param height Height of texture
* @param internal_format Internal format of texture
**/
void Utils::texture::create(glw::GLuint width, glw::GLuint height, glw::GLenum internal_format)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.genTextures(1, &m_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "GenTextures");
bind();
gl.texStorage2D(GL_TEXTURE_2D, 1 /* levels */, internal_format, width, height);
GLU_EXPECT_NO_ERROR(gl.getError(), "TexStorage2D");
}
/** Get contents of texture
*
* @param format Format of image
* @param type Type of image
* @param out_data Buffer for image
**/
void Utils::texture::get(glw::GLenum format, glw::GLenum type, glw::GLvoid* out_data)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
bind();
gl.getTexImage(GL_TEXTURE_2D, 0, format, type, out_data);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetTexImage");
}
/** Update contents of texture
*
* @param width Width of texture
* @param height Height of texture
* @param format Format of data
* @param type Type of data
* @param data Buffer with image
**/
void Utils::texture::update(glw::GLuint width, glw::GLuint height, glw::GLenum format, glw::GLenum type,
glw::GLvoid* data)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
bind();
gl.texSubImage2D(GL_TEXTURE_2D, 0 /* level */, 0 /* x */, 0 /* y */, width, height, format, type, data);
GLU_EXPECT_NO_ERROR(gl.getError(), "TexSubImage2D");
}
/** Constructor.
*
* @param context CTS context.
**/
Utils::vertexArray::vertexArray(deqp::Context& context) : m_id(0), m_context(context)
{
}
/** Destructor
*
**/
Utils::vertexArray::~vertexArray()
{
if (0 != m_id)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.deleteVertexArrays(1, &m_id);
m_id = 0;
}
}
/** Execute BindVertexArray
*
**/
void Utils::vertexArray::bind()
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.bindVertexArray(m_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "BindVertexArray");
}
/** Execute GenVertexArrays
*
**/
void Utils::vertexArray::generate()
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
gl.genVertexArrays(1, &m_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "GenVertexArrays");
}
/** Builds a program object consisting of up to 5 shader stages
* (vertex/tessellation control/tessellation evaluation/geometry/fragment).
* The shaders are attached to the program object, then compiled. Finally,
* the program object is linked.
*
* XFB can be optionally configured for the program object.
*
* Should an error be reported by GL implementation, a TestError
* exception will be thrown.
*
* @param gl OpenGL functions from the active rendering context.
* @param vs_body Body to use for the vertex shader. Can be an empty string.
* @param tc_body Body to use for the tessellation control shader. Can be
* an empty string.
* @param te_body Body to use for the tessellation evaluation shader. Can be
* an empty string.
* @param gs_body Body to use for the geometry shader. Can be an empty string.
* @param fs_body Body to use for the fragment shader. Can be an empty string.
* @param xfb_varyings An array of names of varyings to use for XFB. Can be NULL.
* @param n_xfb_varyings Amount of XFB varyings defined in @param xfb_varyings.Can be 0.
* @param out_vs_id Deref will be used to store GL id of a generated vertex shader.
* Can be NULL in which case no vertex shader will be used for the
* program object.
* @param out_tc_id Deref will be used to store GL id of a generated tess control shader.
* Can be NULL in which case no tess control shader will be used for the
* program object.
* @param out_te_id Deref will be used to store GL id of a generated tess evaluation shader.
* Can be NULL in which case no tess evaluation shader will be used for the
* program object.
* @param out_gs_id Deref will be used to store GL id of a generated geometry shader.
* Can be NULL in which case no geometry shader will be used for the
* program object.
* @param out_fs_id Deref will be used to store GL id of a generated fragment shader.
* Can be NULL in which case no fragment shader will be used for the
* program object.
* @param out_po_id Deref will be used to store GL id of a generated program object.
* Must not be NULL.
*
* @return true if the program was built successfully, false otherwise.
* */
bool Utils::buildProgram(const glw::Functions& gl, const std::string& vs_body, const std::string& tc_body,
const std::string& te_body, const std::string& gs_body, const std::string& fs_body,
const glw::GLchar** xfb_varyings, const unsigned int& n_xfb_varyings, glw::GLuint* out_vs_id,
glw::GLuint* out_tc_id, glw::GLuint* out_te_id, glw::GLuint* out_gs_id, glw::GLuint* out_fs_id,
glw::GLuint* out_po_id)
{
bool result = false;
/* Link the program object */
glw::GLint link_status = GL_FALSE;
/* Create objects, set up shader bodies and attach all requested shaders to the program object */
*out_po_id = gl.createProgram();
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed.");
if (out_vs_id != DE_NULL)
{
const char* vs_body_raw_ptr = vs_body.c_str();
*out_vs_id = gl.createShader(GL_VERTEX_SHADER);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed.");
gl.attachShader(*out_po_id, *out_vs_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call failed.");
gl.shaderSource(*out_vs_id, 1 /* count */, &vs_body_raw_ptr, DE_NULL /* length */);
GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed.");
}
if (out_tc_id != DE_NULL)
{
const char* tc_body_raw_ptr = tc_body.c_str();
*out_tc_id = gl.createShader(GL_TESS_CONTROL_SHADER);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed.");
gl.attachShader(*out_po_id, *out_tc_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call failed.");
gl.shaderSource(*out_tc_id, 1 /* count */, &tc_body_raw_ptr, DE_NULL /* length */);
GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed.");
}
if (out_te_id != DE_NULL)
{
const char* te_body_raw_ptr = te_body.c_str();
*out_te_id = gl.createShader(GL_TESS_EVALUATION_SHADER);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed.");
gl.attachShader(*out_po_id, *out_te_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call failed.");
gl.shaderSource(*out_te_id, 1 /* count */, &te_body_raw_ptr, DE_NULL /* length */);
GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed.");
}
if (out_gs_id != DE_NULL)
{
const char* gs_body_raw_ptr = gs_body.c_str();
*out_gs_id = gl.createShader(GL_GEOMETRY_SHADER);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed.");
gl.attachShader(*out_po_id, *out_gs_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call failed.");
gl.shaderSource(*out_gs_id, 1 /* count */, &gs_body_raw_ptr, DE_NULL /* length */);
GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed.");
}
if (out_fs_id != DE_NULL)
{
const char* fs_body_raw_ptr = fs_body.c_str();
*out_fs_id = gl.createShader(GL_FRAGMENT_SHADER);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed.");
gl.attachShader(*out_po_id, *out_fs_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call failed.");
gl.shaderSource(*out_fs_id, 1 /* count */, &fs_body_raw_ptr, DE_NULL /* length */);
GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed.");
}
/* Compile all shaders */
const glw::GLuint so_ids[] = { (out_vs_id != DE_NULL) ? *out_vs_id : 0, (out_tc_id != DE_NULL) ? *out_tc_id : 0,
(out_te_id != DE_NULL) ? *out_te_id : 0, (out_gs_id != DE_NULL) ? *out_gs_id : 0,
(out_fs_id != DE_NULL) ? *out_fs_id : 0 };
const unsigned int n_so_ids = sizeof(so_ids) / sizeof(so_ids[0]);
for (unsigned int n_so_id = 0; n_so_id < n_so_ids; ++n_so_id)
{
glw::GLuint so_id = so_ids[n_so_id];
if (so_id != 0)
{
glw::GLint compile_status = GL_FALSE;
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)
{
goto end;
}
} /* if (so_id != 0) */
} /* for (all shader objects) */
/* Set up XFB */
if (xfb_varyings != NULL)
{
gl.transformFeedbackVaryings(*out_po_id, n_xfb_varyings, xfb_varyings, GL_INTERLEAVED_ATTRIBS);
GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() call failed.");
}
gl.linkProgram(*out_po_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed.");
gl.getProgramiv(*out_po_id, GL_LINK_STATUS, &link_status);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed.");
if (link_status != GL_TRUE)
{
goto end;
}
/* All done */
result = true;
end:
return result;
}
/** Retrieves base variable type for user-specified variable type
* (eg. float for vec4)
*
* @param variable_type Variable type to use for the query.
*
* @return As per description.
**/
Utils::_variable_type Utils::getBaseVariableType(const _variable_type& variable_type)
{
_variable_type result = VARIABLE_TYPE_UNKNOWN;
switch (variable_type)
{
case VARIABLE_TYPE_BOOL:
case VARIABLE_TYPE_BVEC2:
case VARIABLE_TYPE_BVEC3:
case VARIABLE_TYPE_BVEC4:
{
result = VARIABLE_TYPE_BOOL;
break;
}
case VARIABLE_TYPE_DOUBLE:
case VARIABLE_TYPE_DVEC2:
case VARIABLE_TYPE_DVEC3:
case VARIABLE_TYPE_DVEC4:
{
result = VARIABLE_TYPE_DOUBLE;
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;
}
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;
}
default:
{
TCU_FAIL("Unrecognized variable type");
}
} /* switch (variable_type) */
return result;
}
/** Retrieves size of a single component (in bytes) for user-specified
* variable type.
*
* @param variable_type Variable type to use for the query.
*
* @return As per description.
**/
unsigned int Utils::getComponentSizeForVariableType(const _variable_type& variable_type)
{
_variable_type base_variable_type = getBaseVariableType(variable_type);
unsigned int result = 0;
switch (base_variable_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 base variable type");
}
} /* switch (variable_type) */
return result;
}
/** Retrieves a GLenum value corresponding to internal shader stage
* representation.
*
* @param shader_stage Shader stage to user for the query.
*
* @return Requested value or GL_NONE if the stage was not recognized.
**/
glw::GLenum Utils::getGLenumForShaderStage(const _shader_stage& shader_stage)
{
glw::GLenum result = GL_NONE;
switch (shader_stage)
{
case SHADER_STAGE_VERTEX:
result = GL_VERTEX_SHADER;
break;
case SHADER_STAGE_TESSELLATION_CONTROL:
result = GL_TESS_CONTROL_SHADER;
break;
case SHADER_STAGE_TESSELLATION_EVALUATION:
result = GL_TESS_EVALUATION_SHADER;
break;
case SHADER_STAGE_GEOMETRY:
result = GL_GEOMETRY_SHADER;
break;
case SHADER_STAGE_FRAGMENT:
result = GL_FRAGMENT_SHADER;
break;
default:
{
TCU_FAIL("Unrecognized shader stage requested");
}
} /* switch (shader_stage) */
return result;
}
/** Retrieves number of components that user-specified variable type supports.
*
* @param variable_type GLSL variable type to use for the query.
*
* @return As per description.
**/
unsigned int Utils::getNumberOfComponentsForVariableType(const _variable_type& variable_type)
{
unsigned int result = 0;
switch (variable_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_BVEC2:
case VARIABLE_TYPE_DVEC2:
case VARIABLE_TYPE_IVEC2:
case VARIABLE_TYPE_UVEC2:
case VARIABLE_TYPE_VEC2:
{
result = 2;
break;
}
case VARIABLE_TYPE_BVEC3:
case VARIABLE_TYPE_DVEC3:
case VARIABLE_TYPE_IVEC3:
case VARIABLE_TYPE_UVEC3:
case VARIABLE_TYPE_VEC3:
{
result = 3;
break;
}
case VARIABLE_TYPE_BVEC4:
case VARIABLE_TYPE_DVEC4:
case VARIABLE_TYPE_IVEC4:
case VARIABLE_TYPE_MAT2:
case VARIABLE_TYPE_UVEC4:
case VARIABLE_TYPE_VEC4:
{
result = 4;
break;
}
case VARIABLE_TYPE_MAT2X3:
case VARIABLE_TYPE_MAT3X2:
{
result = 6;
break;
}
case VARIABLE_TYPE_MAT2X4:
case VARIABLE_TYPE_MAT4X2:
{
result = 8;
break;
}
case VARIABLE_TYPE_MAT3:
{
result = 9;
break;
}
case VARIABLE_TYPE_MAT3X4:
case VARIABLE_TYPE_MAT4X3:
{
result = 12;
break;
}
case VARIABLE_TYPE_MAT4:
{
result = 16;
break;
}
default:
break;
} /* switch (variable_type) */
return result;
}
/** Retrieves a literal defining user-specified shader stage enum.
*
* @param shader_stage Shader stage to use for the query.
*
* @return Requested string or "?" if the stage was not recognized.
**/
std::string Utils::getShaderStageString(const _shader_stage& shader_stage)
{
std::string result = "?";
switch (shader_stage)
{
case SHADER_STAGE_FRAGMENT:
result = "Fragment Shader";
break;
case SHADER_STAGE_GEOMETRY:
result = "Geometry Shader";
break;
case SHADER_STAGE_TESSELLATION_CONTROL:
result = "Tessellation Control Shader";
break;
case SHADER_STAGE_TESSELLATION_EVALUATION:
result = "Tessellation Evaluation Shader";
break;
case SHADER_STAGE_VERTEX:
result = "Vertex Shader";
break;
default:
{
TCU_FAIL("Unrecognized shader stage");
}
} /* switch (shader_stage) */
return result;
}
/** Retrieves a literal defining user-specified shader stage enum.
*
* @param shader_stage_glenum Shader stage to use for the query.
*
* @return Requested string or "?" if the stage was not recognized.
**/
std::string Utils::getShaderStageStringFromGLEnum(const glw::GLenum shader_stage_glenum)
{
std::string result = "?";
switch (shader_stage_glenum)
{
case GL_FRAGMENT_SHADER:
result = "Fragment Shader";
break;
case GL_GEOMETRY_SHADER:
result = "Geometry Shader";
break;
case GL_TESS_CONTROL_SHADER:
result = "Tessellation Control Shader";
break;
case GL_TESS_EVALUATION_SHADER:
result = "Tessellation Evaluation Shader";
break;
case GL_VERTEX_SHADER:
result = "Vertex Shader";
break;
default:
{
TCU_FAIL("Unrecognized shader string");
}
} /* switch (shader_stage_glenum) */
return result;
}
/** Returns string that represents program interface name
*
* @param program_interface Program interface
*
* @return String representation of known program interface
**/
const GLchar* Utils::programInterfaceToStr(glw::GLenum program_interface)
{
const GLchar* string = "Unknown program interface";
switch (program_interface)
{
case GL_VERTEX_SUBROUTINE:
string = "GL_VERTEX_SUBROUTINE";
break;
case GL_VERTEX_SUBROUTINE_UNIFORM:
string = "GL_VERTEX_SUBROUTINE_UNIFORM";
break;
default:
TCU_FAIL("Not implemented");
break;
};
return string;
}
/** Returns string that represents pname's name
*
* @param pname pname
*
* @return String representation of known pnames
**/
const GLchar* Utils::pnameToStr(glw::GLenum pname)
{
const GLchar* string = "Unknown pname";
switch (pname)
{
case GL_ACTIVE_SUBROUTINE_UNIFORMS:
string = "GL_ACTIVE_SUBROUTINE_UNIFORMS";
break;
case GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS:
string = "GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS";
break;
case GL_ACTIVE_SUBROUTINES:
string = "GL_ACTIVE_SUBROUTINES";
break;
case GL_ACTIVE_SUBROUTINE_UNIFORM_MAX_LENGTH:
string = "GL_ACTIVE_SUBROUTINE_UNIFORM_MAX_LENGTH";
break;
case GL_ACTIVE_SUBROUTINE_MAX_LENGTH:
string = "GL_ACTIVE_SUBROUTINE_MAX_LENGTH";
break;
case GL_NUM_COMPATIBLE_SUBROUTINES:
string = "GL_NUM_COMPATIBLE_SUBROUTINES";
break;
case GL_UNIFORM_SIZE:
string = "GL_UNIFORM_SIZE";
break;
case GL_COMPATIBLE_SUBROUTINES:
string = "GL_COMPATIBLE_SUBROUTINES";
break;
case GL_UNIFORM_NAME_LENGTH:
string = "GL_UNIFORM_NAME_LENGTH";
break;
case GL_ACTIVE_RESOURCES:
string = "GL_ACTIVE_RESOURCES";
break;
case GL_MAX_NAME_LENGTH:
string = "GL_MAX_NAME_LENGTH";
break;
case GL_MAX_NUM_COMPATIBLE_SUBROUTINES:
string = "GL_MAX_NUM_COMPATIBLE_SUBROUTINES";
break;
case GL_NAME_LENGTH:
string = "GL_NAME_LENGTH";
break;
case GL_ARRAY_SIZE:
string = "GL_ARRAY_SIZE";
break;
case GL_LOCATION:
string = "GL_LOCATION";
break;
default:
TCU_FAIL("Not implemented");
break;
};
return string;
}
bool Utils::compare(const glw::GLfloat& left, const glw::GLfloat& right)
{
static const glw::GLfloat m_epsilon = 0.00001f;
if (m_epsilon < std::abs(right - left))
{
return false;
}
else
{
return true;
}
}
/** Returns a variable type enum corresponding to user-specified base variable type
* and the number of components it should support.
*
* @param base_variable_type Base variable type to use for the query.
* @param n_components Number of components to consider for the query.
*
* @return As per description.
**/
Utils::_variable_type Utils::getVariableTypeFromProperties(const _variable_type& base_variable_type,
const unsigned int& n_components)
{
_variable_type result = VARIABLE_TYPE_UNKNOWN;
switch (base_variable_type)
{
case VARIABLE_TYPE_BOOL:
{
switch (n_components)
{
case 1:
result = VARIABLE_TYPE_BOOL;
break;
case 2:
result = VARIABLE_TYPE_BVEC2;
break;
case 3:
result = VARIABLE_TYPE_BVEC3;
break;
case 4:
result = VARIABLE_TYPE_BVEC4;
break;
default:
{
TCU_FAIL("Unsupported number of components requested");
}
} /* switch (n_components) */
break;
}
case VARIABLE_TYPE_DOUBLE:
{
switch (n_components)
{
case 1:
result = VARIABLE_TYPE_DOUBLE;
break;
case 2:
result = VARIABLE_TYPE_DVEC2;
break;
case 3:
result = VARIABLE_TYPE_DVEC3;
break;
case 4:
result = VARIABLE_TYPE_DVEC4;
break;
default:
{
TCU_FAIL("Unsupported number of components requested");
}
} /* switch (n_components) */
break;
}
case VARIABLE_TYPE_FLOAT:
{
switch (n_components)
{
case 1:
result = VARIABLE_TYPE_FLOAT;
break;
case 2:
result = VARIABLE_TYPE_VEC2;
break;
case 3:
result = VARIABLE_TYPE_VEC3;
break;
case 4:
result = VARIABLE_TYPE_VEC4;
break;
default:
{
TCU_FAIL("Unsupported number of components requested");
}
} /* switch (n_components) */
break;
}
case VARIABLE_TYPE_INT:
{
switch (n_components)
{
case 1:
result = VARIABLE_TYPE_INT;
break;
case 2:
result = VARIABLE_TYPE_IVEC2;
break;
case 3:
result = VARIABLE_TYPE_IVEC3;
break;
case 4:
result = VARIABLE_TYPE_IVEC4;
break;
default:
{
TCU_FAIL("Unsupported number of components requested");
}
} /* switch (n_components) */
break;
}
case VARIABLE_TYPE_UINT:
{
switch (n_components)
{
case 1:
result = VARIABLE_TYPE_UINT;
break;
case 2:
result = VARIABLE_TYPE_UVEC2;
break;
case 3:
result = VARIABLE_TYPE_UVEC3;
break;
case 4:
result = VARIABLE_TYPE_UVEC4;
break;
default:
{
TCU_FAIL("Unsupported number of components requested");
}
} /* switch (n_components) */
break;
}
default:
{
TCU_FAIL("Unrecognized base variable type");
}
} /* switch (base_variable_type) */
return result;
}
/** Returns a GLSL literal corresponding to user-specified variable type.
*
* @param variable_type Variable type to use for the query.
*
* @return As per description or [?] if @param variable_type was not
* recognized.
**/
std::string Utils::getVariableTypeGLSLString(const _variable_type& variable_type)
{
std::string result = "[?]";
switch (variable_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_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 (variable_type) */
return result;
}
/** Constructor.
*
* @param context Rendering context.
*
**/
APITest1::APITest1(deqp::Context& context)
: TestCase(context, "min_maxes", "Verifies the implementation returns valid GL_MAX_SUBROUTINE* pnames "
"which meet the minimum maximum requirements enforced by the spec.")
, m_has_test_passed(true)
{
/* Left blank intentionally */
}
/** Executes test iteration.
*
* @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
*/
tcu::TestNode::IterateResult APITest1::iterate()
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Do not execute the test if GL_ARB_shader_subroutine is not supported */
if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
{
throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
}
/* Iterate over all pnames */
const struct
{
glw::GLenum pname;
const char* pname_string;
glw::GLint min_value;
} pnames[] = { { GL_MAX_SUBROUTINES, "GL_MAX_SUBROUTINES", 256 },
{ GL_MAX_SUBROUTINE_UNIFORM_LOCATIONS, "GL_MAX_SUBROUTINE_UNIFORM_LOCATIONS", 1024 } };
const unsigned int n_pnames = sizeof(pnames) / sizeof(pnames[0]);
for (unsigned int n_pname = 0; n_pname < n_pnames; ++n_pname)
{
glw::GLboolean bool_value = GL_FALSE;
glw::GLdouble double_value = 0.0;
glw::GLfloat float_value = 0.0f;
glw::GLint int_value = 0;
glw::GLint64 int64_value = 0;
const glw::GLint min_value = pnames[n_pname].min_value;
const glw::GLenum& pname = pnames[n_pname].pname;
const char* pname_string = pnames[n_pname].pname_string;
/* Retrieve the pname values */
gl.getBooleanv(pname, &bool_value);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetBooleanv() call failed.");
gl.getDoublev(pname, &double_value);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetDoublev() call failed.");
gl.getFloatv(pname, &float_value);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetFloatv() call failed.");
gl.getIntegerv(pname, &int_value);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() call failed.");
gl.getInteger64v(pname, &int64_value);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetInteger64v() call failed.");
/* Make sure the value reported meets the min max requirement */
if (int_value < min_value)
{
m_testCtx.getLog() << tcu::TestLog::Message << "GL implementation reports a value of [" << int_value
<< "]"
" for property ["
<< pname_string << "]"
", whereas the min max for the property is ["
<< min_value << "]." << tcu::TestLog::EndMessage;
m_has_test_passed = false;
}
/* Verify the other getters reported valid values */
const float epsilon = 1e-5f;
if (((int_value == 0) && (bool_value == GL_TRUE)) || ((int_value != 0) && (bool_value != GL_TRUE)))
{
m_testCtx.getLog() << tcu::TestLog::Message << "Invalid boolean value [" << bool_value
<< "]"
" reported for property ["
<< pname_string << "]"
" (int value:["
<< int_value << "])" << tcu::TestLog::EndMessage;
m_has_test_passed = false;
}
if (de::abs(double_value - (double)int_value) > epsilon)
{
m_testCtx.getLog() << tcu::TestLog::Message << "Invalid double value [" << double_value
<< "]"
" reported for property ["
<< pname_string << "]"
" (int value:["
<< int_value << "])" << tcu::TestLog::EndMessage;
m_has_test_passed = false;
}
if (de::abs(float_value - (float)int_value) > epsilon)
{
m_testCtx.getLog() << tcu::TestLog::Message << "Invalid float value [" << float_value
<< "]"
" reported for property ["
<< pname_string << "]"
" (int value:["
<< int_value << "])" << tcu::TestLog::EndMessage;
m_has_test_passed = false;
}
if (int64_value != int_value)
{
m_testCtx.getLog() << tcu::TestLog::Message << "Invalid 64-bit integer value [" << float_value
<< "]"
" reported for property ["
<< pname_string << "]"
" (int value:["
<< int_value << "])" << tcu::TestLog::EndMessage;
m_has_test_passed = false;
}
} /* for (all pnames) */
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.
*
**/
APITest2::APITest2(deqp::Context& context)
: TestCase(context, "name_getters", "Verifies glGetActiveSubroutineName() and glGetActiveSubroutineUniformName() "
"functions work correctly.")
, m_buffer(DE_NULL)
, m_has_test_passed(true)
, m_po_id(0)
, m_subroutine_name1("subroutine1")
, m_subroutine_name2("subroutine2")
, m_subroutine_uniform_name("data_provider")
, m_vs_id(0)
{
/* Left blank intentionally */
}
/** Destroys all ES objects that may have been created during test initialization,
* as well as releases any buffers that may have been allocated during the process.
*/
void APITest2::deinit()
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
if (m_buffer != DE_NULL)
{
delete[] m_buffer;
m_buffer = DE_NULL;
}
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 body of a vertex shader that should be used for the test.
*
* @return As per description.
**/
std::string APITest2::getVertexShaderBody()
{
return "#version 400\n"
"\n"
"#extension GL_ARB_shader_subroutine : require\n"
"\n"
"subroutine int ExampleSubroutineType(int example_argument);\n"
"\n"
"subroutine(ExampleSubroutineType) int subroutine1(int example_argument)\n"
"{\n"
" return 1;\n"
"}\n"
"\n"
"subroutine(ExampleSubroutineType) int subroutine2(int example_argument)\n"
"{\n"
" return 2;\n"
"}\n"
"\n"
"subroutine uniform ExampleSubroutineType data_provider;\n"
"\n"
"void main()\n"
"{\n"
" gl_Position = vec4(float(data_provider(0)), vec3(1) );\n"
"}\n";
}
/** Initializes all ES objects required to run the test. */
void APITest2::initTest()
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Generate program & 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(s) failed.");
/* Attach the shader to the program object */
gl.attachShader(m_po_id, m_vs_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call failed.");
/* Compile the shader */
glw::GLint compile_status = GL_FALSE;
std::string vs_body = getVertexShaderBody();
const char* vs_body_raw_ptr = vs_body.c_str();
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("Shader compilation failed.");
}
/* Try to 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.");
}
/* Perform a few sanity checks */
glw::GLint n_active_subroutines = 0;
glw::GLint n_active_subroutine_uniforms = 0;
gl.getProgramStageiv(m_po_id, GL_VERTEX_SHADER, GL_ACTIVE_SUBROUTINES, &n_active_subroutines);
gl.getProgramStageiv(m_po_id, GL_VERTEX_SHADER, GL_ACTIVE_SUBROUTINE_UNIFORMS, &n_active_subroutine_uniforms);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramStageiv() call failed.");
if (n_active_subroutines != 2 /* subroutines declared in vertex shader */)
{
m_testCtx.getLog() << tcu::TestLog::Message << "Invalid amount of active subroutines reported; expected: 2,"
" reported:"
<< n_active_subroutines << tcu::TestLog::EndMessage;
TCU_FAIL("Invalid GL_ACTIVE_SUBROUTINES property value.");
}
if (n_active_subroutine_uniforms != 1)
{
m_testCtx.getLog() << tcu::TestLog::Message
<< "Invalid amount of active subroutine uniforms reported: expected: 1,"
" reported: "
<< n_active_subroutine_uniforms << tcu::TestLog::EndMessage;
TCU_FAIL("Invalid GL_ACTIVE_SUBROUTINE_UNIFORMS property value.");
}
}
/** Executes test iteration.
*
* @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed.
*/
tcu::TestNode::IterateResult APITest2::iterate()
{
/* Do not execute the test if GL_ARB_shader_subroutine is not supported */
if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
{
throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
}
/* Initialize a test program object */
initTest();
/* Verify glGetActiveSubroutineName() works correctly */
verifyGLGetActiveSubroutineNameFunctionality();
/* Verify glGetActiveSubroutineUniformName() works correctly */
verifyGLGetActiveSubroutineUniformNameFunctionality();
/* 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 glGetActiveSubroutineName() behaves as per GL_ARB_shader_subroutine
* specification.
**/
void APITest2::verifyGLGetActiveSubroutineNameFunctionality()
{
GLsizei expected_length1 = (GLsizei)strlen(m_subroutine_name1) + 1;
GLsizei expected_length2 = (GLsizei)strlen(m_subroutine_name1) + 1;
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
GLsizei reported_length = 0;
gl.getActiveSubroutineName(m_po_id, GL_VERTEX_SHADER, 0, /* index */
0, /* bufsize */
DE_NULL, /* length */
DE_NULL); /* name */
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetActiveSubroutineName() call failed.");
gl.getProgramInterfaceiv(m_po_id, GL_VERTEX_SUBROUTINE, GL_MAX_NAME_LENGTH, &reported_length);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetActiveSubroutineName() call failed.");
if ((reported_length != expected_length1) && (reported_length != expected_length2))
{
m_testCtx.getLog() << tcu::TestLog::Message
<< "Invalid active subroutine name length reported:" << reported_length
<< ", instead of: " << expected_length1 << " or " << expected_length2
<< tcu::TestLog::EndMessage;
TCU_FAIL("Incorrect length of active subroutine name");
}
m_buffer = new glw::GLchar[reported_length];
memset(m_buffer, 0, reported_length);
gl.getActiveSubroutineName(m_po_id, GL_VERTEX_SHADER, 0, reported_length, DE_NULL, /* length */
m_buffer);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetActiveSubroutineName() call failed.");
if (strcmp(m_buffer, m_subroutine_name1) != 0 && strcmp(m_buffer, m_subroutine_name2) != 0)
{
m_testCtx.getLog() << tcu::TestLog::Message << "Invalid active subroutine name reported:[" << m_buffer
<< "]"
" instead of:["
<< m_subroutine_name1 << "]"
" or:["
<< m_subroutine_name2 << "]." << tcu::TestLog::EndMessage;
TCU_FAIL("Invalid active subroutine name reported.");
}
delete[] m_buffer;
m_buffer = DE_NULL;
}
/** Verifies glGetActiveSubroutineUniformName() behaves as per GL_ARB_shader_subroutine
* specification.
**/
void APITest2::verifyGLGetActiveSubroutineUniformNameFunctionality()
{
GLsizei expected_length = (GLsizei)strlen(m_subroutine_uniform_name);
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
GLsizei reported_length = 0;
gl.getActiveSubroutineUniformName(m_po_id, GL_VERTEX_SHADER, 0, /* index */
0, /* bufsize */
DE_NULL, /* length */
DE_NULL); /* name */
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetActiveSubroutineUniformName() call failed.");
gl.getActiveSubroutineUniformName(m_po_id, GL_VERTEX_SHADER, 0, /* index */
0, /* bufsize */
&reported_length, DE_NULL); /* name */
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetActiveSubroutineUniformName() call failed.");
// reported_length is the actual number of characters written into <name>
// If <bufSize> is 0, reported_length should be 0
if (reported_length != 0)
{
m_testCtx.getLog() << tcu::TestLog::Message
<< "Invalid active subroutine uniform name length reported:" << reported_length
<< ", instead of: " << 0 << tcu::TestLog::EndMessage;
TCU_FAIL("Incorrect length of active subroutine uniform name");
}
m_buffer = new glw::GLchar[expected_length + 1];
memset(m_buffer, 0, expected_length + 1);
gl.getActiveSubroutineUniformName(m_po_id, GL_VERTEX_SHADER, 0, expected_length + 1, &reported_length, m_buffer);
GLU_EXPECT_NO_ERROR(gl.getError(), "getActiveSubroutineUniformName() call failed.");
if (reported_length != expected_length)
{
m_testCtx.getLog() << tcu::TestLog::Message
<< "Invalid active subroutine uniform name length reported:" << reported_length
<< ", instead of: " << expected_length << tcu::TestLog::EndMessage;
TCU_FAIL("Incorrect length of active subroutine uniform name");
}
if (strcmp(m_buffer, m_subroutine_uniform_name) != 0)
{
m_testCtx.getLog() << tcu::TestLog::Message << "Invalid active subroutine uniform name reported:[" << m_buffer
<< "]"
" instead of:["
<< m_subroutine_uniform_name << "]" << tcu::TestLog::EndMessage;
TCU_FAIL("Invalid active subroutine uniform name reported.");
}
delete[] m_buffer;
m_buffer = DE_NULL;
}
/** Constructor.
*
* @param context Rendering context.
*
**/
FunctionalTest1_2::FunctionalTest1_2(deqp::Context& context)
: TestCase(context, "two_subroutines_single_subroutine_uniform",
"Verifies the subroutines work correctly in a vertex shader for"
" bool/float/int/uint/double/*vec*/*mat* argument and return types")
, m_has_test_passed(true)
, m_po_id(0)
, m_po_getter0_subroutine_index(GL_INVALID_INDEX)
, m_po_getter1_subroutine_index(GL_INVALID_INDEX)
, m_po_subroutine_uniform_index(-1)
, m_xfb_bo_id(0)
, m_vao_id(0)
, m_vs_id(0)
{
/* Left blank intentionally */
}
/** Destroys all ES objects that may have been created during test initialization,
* as well as releases any buffers that may have been allocated during the process.
*/
void FunctionalTest1_2::deinit()
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
deinitTestIteration();
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);
m_vao_id = 0;
}
}
/** Deinitializes GL objects that are iteration-specific */
void FunctionalTest1_2::deinitTestIteration()
{
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 iteration using user-specified test case propertiesz.
*
* @param test-case Test case descriptor.
*
* @return true if the test iteration passed, false otherwise.
**/
bool FunctionalTest1_2::executeTestIteration(const _test_case& test_case)
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
bool result = true;
/* Build the test program */
std::string empty_body;
std::string vs_body = getVertexShaderBody(test_case.variable_type, test_case.array_size);
const glw::GLchar* xfb_varyings[] = { "result" };
const unsigned int n_xfb_varyings = sizeof(xfb_varyings) / sizeof(xfb_varyings[0]);
if (!Utils::buildProgram(gl, vs_body, empty_body, empty_body, empty_body, empty_body, xfb_varyings, n_xfb_varyings,
&m_vs_id, NULL, /* out_tc_id */
NULL, /* out_te_id */
NULL, /* out_gs_id */
NULL, &m_po_id))
{
TCU_FAIL("Test program failed to build.");
}
/* Retrieve subroutine locations */
m_po_getter0_subroutine_index = gl.getSubroutineIndex(m_po_id, GL_VERTEX_SHADER, "getter0");
m_po_getter1_subroutine_index = gl.getSubroutineIndex(m_po_id, GL_VERTEX_SHADER, "getter1");
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetSubroutineIndex() call(s) failed.");
if (m_po_getter0_subroutine_index == GL_INVALID_INDEX || m_po_getter1_subroutine_index == GL_INVALID_INDEX)
{
TCU_FAIL("At least one subroutine is considered inactive which is invalid.");
}
/* Retrieve subroutine uniform location */
m_po_subroutine_uniform_index = gl.getSubroutineUniformLocation(m_po_id, GL_VERTEX_SHADER, "colorGetterUniform");
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetSubroutineUniformLocation() call failed.");
if (m_po_subroutine_uniform_index == -1)
{
TCU_FAIL("Subroutine uniform is considered inactive which is invalid.");
}
/* Set up XFB BO storage */
const Utils::_variable_type base_variable_type = Utils::getBaseVariableType(test_case.variable_type);
unsigned int iteration_xfb_bo_size = Utils::getComponentSizeForVariableType(base_variable_type) *
Utils::getNumberOfComponentsForVariableType(test_case.variable_type);
unsigned int total_xfb_bo_size = 0;
if (base_variable_type == Utils::VARIABLE_TYPE_BOOL)
{
/* Boolean varyings are not supported by OpenGL. Instead, we use ints to output
* boolean values. */
iteration_xfb_bo_size = static_cast<unsigned int>(iteration_xfb_bo_size * sizeof(int));
}
total_xfb_bo_size = iteration_xfb_bo_size * 2 /* subroutines we will be testing */;
gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, total_xfb_bo_size, DE_NULL /* data */, GL_STATIC_DRAW);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call failed.");
/* Activate test program object */
gl.useProgram(m_po_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed.");
/* Run two iterations. Each iteration should invoke different subroutine. */
const glw::GLuint subroutine_indices[] = { m_po_getter0_subroutine_index, m_po_getter1_subroutine_index };
const unsigned int n_subroutine_indices = sizeof(subroutine_indices) / sizeof(subroutine_indices[0]);
for (unsigned int n_subroutine_index = 0; n_subroutine_index < n_subroutine_indices; ++n_subroutine_index)
{
/* Configure which subroutine should be used for the draw call */
glw::GLuint current_subroutine_index = subroutine_indices[n_subroutine_index];
gl.uniformSubroutinesuiv(GL_VERTEX_SHADER, 1 /* count */, &current_subroutine_index);
GLU_EXPECT_NO_ERROR(gl.getError(), "glUniformSubroutinesuiv() call failed.");
/* Update XFB binding so that we do not overwrite data XFBed in previous iterations */
gl.bindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* index */
m_xfb_bo_id, iteration_xfb_bo_size * n_subroutine_index, iteration_xfb_bo_size);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferRange() call failed.");
/* Draw a single point */
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.");
} /* for (all subroutine indices) */
/* Map the BO storage 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(xfb_data_ptr, test_case.variable_type);
gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffeR() call failed.");
return result;
}
/** Retrieves body of a vertex shader that should be used to verify
* subroutine support, given user-specified test iteration properties.
*
* @param variable_type GLSL type that should be used for argument and
* return type definition in a subroutine. This setting
* also affects type of the only output variable in the shader.
* @param array_size 1 if non-arrayed arguments/return types should be tested;
* 2 if arrayed arguments/return types should be tested.
*
* @return Requested string.
**/
std::string FunctionalTest1_2::getVertexShaderBody(const Utils::_variable_type& variable_type, unsigned int array_size)
{
Utils::_variable_type base_variable_type = Utils::getBaseVariableType(variable_type);
unsigned int n_variable_type_components = Utils::getNumberOfComponentsForVariableType(variable_type);
std::stringstream result_sstream;
std::string variable_type_glsl = Utils::getVariableTypeGLSLString(variable_type);
std::stringstream variable_type_glsl_array_sstream;
std::stringstream variable_type_glsl_arrayed_sstream;
variable_type_glsl_arrayed_sstream << variable_type_glsl;
if (array_size > 1)
{
variable_type_glsl_array_sstream << "[" << array_size << "]";
variable_type_glsl_arrayed_sstream << variable_type_glsl_array_sstream.str();
}
/* Form pre-amble */
result_sstream << "#version 400\n"
"\n"
"#extension GL_ARB_shader_subroutine : require\n";
if (variable_type == Utils::VARIABLE_TYPE_DOUBLE)
{
result_sstream << "#extension GL_ARB_gpu_shader_fp64 : require\n";
}
/* Form subroutine type declaration */
result_sstream << "\n"
"subroutine "
<< variable_type_glsl_arrayed_sstream.str() << " colorGetter(in " << variable_type_glsl
<< " in_value" << variable_type_glsl_array_sstream.str() << ");\n"
"\n";
/* Declare getter functions */
for (int n_getter = 0; n_getter < 2; ++n_getter)
{
result_sstream << "subroutine(colorGetter) " << variable_type_glsl_arrayed_sstream.str() << " getter"
<< n_getter << "(in " << variable_type_glsl << " in_value"
<< variable_type_glsl_array_sstream.str() << ")\n"
"{\n";
if (array_size > 1)
{
result_sstream << variable_type_glsl << " temp" << variable_type_glsl_array_sstream.str() << ";\n";
}
if (base_variable_type == Utils::VARIABLE_TYPE_BOOL)
{
if (array_size > 1)
{
for (unsigned int array_index = 0; array_index < array_size; ++array_index)
{
result_sstream << " temp[" << array_index << "]"
" = "
<< ((n_getter == 0) ? ((variable_type_glsl == "bool") ? "!" : "not") : "")
<< "(in_value[" << array_index << "]);\n";
}
result_sstream << " return temp;\n";
}
else
{
result_sstream << " return "
<< ((n_getter == 0) ? ((variable_type_glsl == "bool") ? "!" : "not") : "")
<< "(in_value);\n";
}
} /* if (base_variable_type == Utils::VARIABLE_TYPE_BOOL) */
else
{
if (array_size > 1)
{
for (unsigned int array_index = 0; array_index < array_size; ++array_index)
{
result_sstream << " temp[" << array_index << "]"
" = in_value["
<< array_index << "] + " << (n_getter + 1) << ";\n";
}
result_sstream << " return temp;\n";
}
else
{
result_sstream << " return (in_value + " << (n_getter + 1) << ");\n";
}
}
result_sstream << "}\n";
} /* for (both getter functions) */
/* Declare subroutine uniform */
result_sstream << "subroutine uniform colorGetter colorGetterUniform;\n"
"\n";
/* Declare output variable */
result_sstream << "out ";
if (base_variable_type == Utils::VARIABLE_TYPE_BOOL)
{
Utils::_variable_type result_as_int_variable_type =
Utils::getVariableTypeFromProperties(Utils::VARIABLE_TYPE_INT, n_variable_type_components);
std::string variable_type_glsl_as_int = Utils::getVariableTypeGLSLString(result_as_int_variable_type);
result_sstream << variable_type_glsl_as_int;
}
else
{
result_sstream << variable_type_glsl;
}
result_sstream << " result;\n"
"\n";
/* Declare main(): prepare input argument for the subroutine function */
result_sstream << "void main()\n"
"{\n"
" "
<< variable_type_glsl << " temp";
if (array_size > 1)
{
result_sstream << "[" << array_size << "]";
};
result_sstream << ";\n";
for (unsigned int array_index = 0; array_index < array_size; ++array_index)
{
result_sstream << " temp";
if (array_size > 1)
{
result_sstream << "[" << array_index << "]";
}
result_sstream << " = " << variable_type_glsl << "(";
if (base_variable_type == Utils::VARIABLE_TYPE_BOOL)
{
result_sstream << "true";
}
else
{
for (unsigned int n_component = 0; n_component < n_variable_type_components; ++n_component)
{
result_sstream << "3";
if (n_component != (n_variable_type_components - 1))
{
result_sstream << ", ";
}
} /* for (all components) */
}
result_sstream << ");\n";
} /* for (all array indices) */
/* Declare main(): call the subroutine. Verify the input and write the result
* to the output variable.
**/
if (base_variable_type == Utils::VARIABLE_TYPE_BOOL)
{
Utils::_variable_type result_as_int_variable_type =
Utils::getVariableTypeFromProperties(Utils::VARIABLE_TYPE_INT, n_variable_type_components);
std::string variable_type_glsl_as_int = Utils::getVariableTypeGLSLString(result_as_int_variable_type);
result_sstream << variable_type_glsl_arrayed_sstream.str() << " subroutine_result = colorGetterUniform(temp);\n"
"result = ";
for (unsigned int array_index = 0; array_index < array_size; ++array_index)
{
if (variable_type_glsl == "bool")
result_sstream << "bool(subroutine_result";
else
result_sstream << "all(subroutine_result";
if (array_size > 1)
{
result_sstream << "[" << array_index << "]";
}
result_sstream << ")";
if (array_index != (array_size - 1))
{
result_sstream << "&& ";
}
}
result_sstream << " == true ? " << variable_type_glsl_as_int << "(1) : " << variable_type_glsl_as_int << "(0);";
}
else
{
if (array_size > 1)
{
DE_ASSERT(array_size == 2);
result_sstream << variable_type_glsl << " subroutine_result" << variable_type_glsl_array_sstream.str()
<< " = colorGetterUniform(temp);\n"
"\n"
"if (subroutine_result[0] == subroutine_result[1]) result = subroutine_result[0];\n"
"else\n"
"result = "
<< variable_type_glsl << "(-1);\n";
}
else
{
result_sstream << "result = colorGetterUniform(temp);\n";
}
}
/* All done */
result_sstream << "}\n";
return result_sstream.str();
}
/** Initializes all GL objects required to run the test. */
void FunctionalTest1_2::initTest()
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Generate buffer object to hold result XFB data */
gl.genBuffers(1, &m_xfb_bo_id);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed.");
/* Set up XFB BO bindings */
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.");
/* Generate VAO 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 FunctionalTest1_2::iterate()
{
/* Do not execute the test if GL_ARB_shader_subroutine is not supported */
if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
{
throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
}
/* Initialize a test program object */
initTest();
/* Construct test case descriptors: first, iIerate over all
* variable types we want to cover */
const Utils::_variable_type variable_types[] = {
Utils::VARIABLE_TYPE_BOOL, Utils::VARIABLE_TYPE_BVEC2, Utils::VARIABLE_TYPE_BVEC3,
Utils::VARIABLE_TYPE_BVEC4, Utils::VARIABLE_TYPE_DOUBLE, Utils::VARIABLE_TYPE_FLOAT,
Utils::VARIABLE_TYPE_INT, Utils::VARIABLE_TYPE_IVEC2, Utils::VARIABLE_TYPE_IVEC3,
Utils::VARIABLE_TYPE_IVEC4, Utils::VARIABLE_TYPE_MAT2, Utils::VARIABLE_TYPE_MAT2X3,
Utils::VARIABLE_TYPE_MAT2X4, Utils::VARIABLE_TYPE_MAT3, Utils::VARIABLE_TYPE_MAT3X2,
Utils::VARIABLE_TYPE_MAT3X4, Utils::VARIABLE_TYPE_MAT4, Utils::VARIABLE_TYPE_MAT4X2,
Utils::VARIABLE_TYPE_MAT4X3, Utils::VARIABLE_TYPE_UINT, Utils::VARIABLE_TYPE_UVEC2,
Utils::VARIABLE_TYPE_UVEC3, Utils::VARIABLE_TYPE_UVEC4, Utils::VARIABLE_TYPE_VEC2,
Utils::VARIABLE_TYPE_VEC3, Utils::VARIABLE_TYPE_VEC4
};
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)
{
Utils::_variable_type current_variable_type = variable_types[n_variable_type];
/* We need to test both arrayed and non-arrayed arguments */
for (unsigned int array_size = 1; array_size < 3; ++array_size)
{
/* Exclude double variables if the relevant extension is unavailable */
if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_gpu_shader_fp64") &&
current_variable_type == Utils::VARIABLE_TYPE_DOUBLE)
{
continue;
}
/* Form the descriptor */
_test_case test_case;
test_case.array_size = array_size;
test_case.variable_type = current_variable_type;
/* Store the test case descriptor */
m_test_cases.push_back(test_case);
} /* for (both arrayed and non-arrayed arguments) */
} /* for (all variable types) */
/* Iterate over all test cases and execute the test */
for (_test_cases_const_iterator test_case_iterator = m_test_cases.begin(); test_case_iterator != m_test_cases.end();
++test_case_iterator)
{
const _test_case& test_case = *test_case_iterator;
m_has_test_passed &= executeTestIteration(test_case);
/* Release GL objects that were created during the execution */
deinitTestIteration();
} /* for (all test cases) */
/* 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 that has been XFBed out by the vertex shader.
*
* @param xfb_data Buffer holding the data.
* @param variable_type GLSL type used for the test iteration
* that generated the data at @param xfb_data.
*
* @return true if the data was found to be valid, false if it
* was detected to be incorrect.
**/
bool FunctionalTest1_2::verifyXFBData(const void* xfb_data, const Utils::_variable_type& variable_type)
{
const Utils::_variable_type base_variable_type = Utils::getBaseVariableType(variable_type);
const float epsilon = 1e-5f;
const unsigned int n_variable_type_components = Utils::getNumberOfComponentsForVariableType(variable_type);
bool result = true;
const unsigned char* traveller_ptr = (const unsigned char*)xfb_data;
/* Boolean arguments/return types are tested with a slightly different shader so we
* need to test them in a separate code-path.
*/
if (base_variable_type == Utils::VARIABLE_TYPE_BOOL)
{
/* 0 should be returned when getter0 is used, 1 otherwise */
const unsigned int ref_values[] = { 0, 1 };
const unsigned int n_ref_values = sizeof(ref_values) / sizeof(ref_values[0]);
for (unsigned int n_ref_value = 0; n_ref_value < n_ref_values; ++n_ref_value)
{
const unsigned int ref_value = ref_values[n_ref_value];
for (unsigned int n_component = 0; n_component < n_variable_type_components; ++n_component)
{
int* result_value_ptr = (int*)(traveller_ptr);
if (*result_value_ptr != (int)ref_value)
{
m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value reported by subroutine using "
"["
<< Utils::getVariableTypeGLSLString(variable_type) << "]"
<< " argument/return types ("
"expected:["
<< ref_value << "], found:[" << *result_value_ptr << "])"
<< tcu::TestLog::EndMessage;
result = false;
break;
}
traveller_ptr += sizeof(int);
} /* for (all components) */
} /* for (all reference values) */
} /* if (base_variable_type == Utils::VARIABLE_TYPE_BOOL) */
else
{
/* 4 should be returned when getter0 is used, 5 otherwise */
const unsigned int ref_values[] = { 4, 5 };
const unsigned int n_ref_values = sizeof(ref_values) / sizeof(ref_values[0]);
for (unsigned int n_ref_value = 0; n_ref_value < n_ref_values; ++n_ref_value)
{
const unsigned int ref_value = ref_values[n_ref_value];
DE_ASSERT(
base_variable_type == Utils::VARIABLE_TYPE_DOUBLE || base_variable_type == Utils::VARIABLE_TYPE_FLOAT ||
base_variable_type == Utils::VARIABLE_TYPE_INT || base_variable_type == Utils::VARIABLE_TYPE_UINT);
for (unsigned int n_component = 0; n_component < n_variable_type_components; ++n_component)
{
const double* double_value_ptr = (double*)traveller_ptr;
const float* float_value_ptr = (float*)traveller_ptr;
const int* int_value_ptr = (int*)traveller_ptr;
switch (base_variable_type)
{
case Utils::VARIABLE_TYPE_DOUBLE:
{
if (de::abs(*double_value_ptr - (double)ref_value) > epsilon)
{
m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value reported by subroutine using "
"["
<< Utils::getVariableTypeGLSLString(variable_type) << "]"
<< " argument/return types ("
"expected:["
<< ref_value << "], found:[" << *double_value_ptr << "])"
<< tcu::TestLog::EndMessage;
result = false;
}
traveller_ptr += sizeof(double);
break;
}
case Utils::VARIABLE_TYPE_FLOAT:
{
if (de::abs(*float_value_ptr - (float)ref_value) > epsilon)
{
m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value reported by subroutine using "
"["
<< Utils::getVariableTypeGLSLString(variable_type) << "]"
<< " argument/return types ("
"expected:["
<< ref_value << "], found:[" << *float_value_ptr << "])"
<< tcu::TestLog::EndMessage;
result = false;
}
traveller_ptr += sizeof(float);
break;
}
case Utils::VARIABLE_TYPE_INT:
case Utils::VARIABLE_TYPE_UINT:
{
if (*int_value_ptr != (int)ref_value)
{
m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value reported by subroutine using "
"["
<< Utils::getVariableTypeGLSLString(variable_type) << "]"
<< " argument/return types ("
"expected:["
<< ref_value << "], found:[" << *int_value_ptr << "])"
<< tcu::TestLog::EndMessage;
result = false;
}
traveller_ptr += sizeof(int);
break;
}
default:
break;
} /* switch (base_variable_type) */
} /* for (all components) */
} /* for (all reference values) */
}
return result;
}
/** Constructor
*
* @param context CTS context
**/
FunctionalTest3_4::FunctionalTest3_4(deqp::Context& context)
: TestCase(context, "four_subroutines_with_two_uniforms", "Verify Get* API and draw calls")
, m_n_active_subroutine_uniforms(0)
, m_n_active_subroutine_uniform_locations(0)
, m_n_active_subroutines(0)
, m_n_active_subroutine_uniform_name_length(0)
, m_n_active_subroutine_name_length(0)
, m_n_active_subroutine_uniform_size(0)
{
/* Nothing to be done here */
}
/** Execute test
*
* @return tcu::TestNode::STOP
**/
tcu::TestNode::IterateResult FunctionalTest3_4::iterate()
{
static const glw::GLchar* vertex_shader_code =
"#version 400 core\n"
"#extension GL_ARB_shader_subroutine : require\n"
"\n"
"precision highp float;\n"
"\n"
"// Sub routine type declaration\n"
"subroutine vec4 routine_type(in vec4 iparam);\n"
"\n"
"// Sub routine definitions\n"
"subroutine(routine_type) vec4 inverse_order(in vec4 iparam)\n"
"{\n"
" return iparam.wzyx;\n"
"}\n"
"\n"
"subroutine(routine_type) vec4 negate(in vec4 iparam)\n"
"{\n"
" return -iparam;\n"
"}\n"
"\n"
"subroutine(routine_type) vec4 inverse(in vec4 iparam)\n"
"{\n"
" return 1 / iparam;\n"
"}\n"
"\n"
"subroutine(routine_type) vec4 square(in vec4 iparam)\n"
"{\n"
" return iparam * iparam;\n"
"}\n"
"\n"
"// Sub routine uniforms\n"
"subroutine uniform routine_type first_routine;\n"
"subroutine uniform routine_type second_routine;\n"
"\n"
"// Input data\n"
"uniform vec4 input_data;\n"
"\n"
"// Output\n"
"out vec4 out_input_data;\n"
"out vec4 out_result_from_first_routine;\n"
"out vec4 out_result_from_second_routine;\n"
"out vec4 out_result_from_combined_routines;\n"
"out vec4 out_result_from_routines_combined_in_reveresed_order;\n"
"\n"
"void main()\n"
"{\n"
" out_input_data = input_data;\n"
" out_result_from_first_routine = first_routine(input_data);\n"
" out_result_from_second_routine = second_routine(input_data);\n"
" out_result_from_combined_routines = second_routine(first_routine(input_data));\n"
" out_result_from_routines_combined_in_reveresed_order = first_routine(second_routine(input_data));\n"
"}\n"
"\n";
static const GLchar* varying_names[] = {
"out_input_data",
"out_result_from_first_routine",
"out_result_from_second_routine",
"out_result_from_combined_routines",
"out_result_from_routines_combined_in_reveresed_order",
};
static const GLchar* subroutine_uniform_names[] = { "first_routine", "second_routine" };
static const GLchar* subroutine_names[] = { "inverse_order", "negate", "inverse", "square" };
static const GLuint n_varyings = sizeof(varying_names) / sizeof(varying_names[0]);
static const GLuint transform_feedback_buffer_size = n_varyings * sizeof(GLfloat) * 4 /* vec4 */;
static const GLuint inverse_order_routine_index = 0;
static const GLuint negate_routine_index = 1;
static const GLuint inverse_routine_index = 2;
static const GLuint square_routine_index = 3;
/* Test data */
static const Utils::vec4<GLfloat> inverse_order_negate_data[5] = {
Utils::vec4<GLfloat>(-2.0f, -1.0f, 1.0f, 2.0f), Utils::vec4<GLfloat>(2.0f, 1.0f, -1.0f, -2.0f),
Utils::vec4<GLfloat>(2.0f, 1.0f, -1.0f, -2.0f), Utils::vec4<GLfloat>(-2.0f, -1.0f, 1.0f, 2.0f),
Utils::vec4<GLfloat>(-2.0f, -1.0f, 1.0f, 2.0f),
};
static const Utils::vec4<GLfloat> inverse_order_inverse_data[5] = {
Utils::vec4<GLfloat>(-2.0f, -1.0f, 1.0f, 2.0f), Utils::vec4<GLfloat>(2.0f, 1.0f, -1.0f, -2.0f),
Utils::vec4<GLfloat>(-0.5f, -1.0f, 1.0f, 0.5f), Utils::vec4<GLfloat>(0.5f, 1.0f, -1.0f, -0.5f),
Utils::vec4<GLfloat>(0.5f, 1.0f, -1.0f, -0.5f),
};
static const Utils::vec4<GLfloat> inverse_order_square_data[5] = {
Utils::vec4<GLfloat>(-2.0f, -1.0f, 1.0f, 2.0f), Utils::vec4<GLfloat>(2.0f, 1.0f, -1.0f, -2.0f),
Utils::vec4<GLfloat>(4.0f, 1.0f, 1.0f, 4.0f), Utils::vec4<GLfloat>(4.0f, 1.0f, 1.0f, 4.0f),
Utils::vec4<GLfloat>(4.0f, 1.0f, 1.0f, 4.0f),
};
static const Utils::vec4<GLfloat> negate_inverse_data[5] = {
Utils::vec4<GLfloat>(-2.0f, -1.0f, 1.0f, 2.0f), Utils::vec4<GLfloat>(2.0f, 1.0f, -1.0f, -2.0f),
Utils::vec4<GLfloat>(-0.5f, -1.0f, 1.0f, 0.5f), Utils::vec4<GLfloat>(0.5f, 1.0f, -1.0f, -0.5f),
Utils::vec4<GLfloat>(0.5f, 1.0f, -1.0f, -0.5f),
};
static const Utils::vec4<GLfloat> negate_square_data[5] = {
Utils::vec4<GLfloat>(-2.0f, -1.0f, 1.0f, 2.0f), Utils::vec4<GLfloat>(2.0f, 1.0f, -1.0f, -2.0f),
Utils::vec4<GLfloat>(4.0f, 1.0f, 1.0f, 4.0f), Utils::vec4<GLfloat>(4.0f, 1.0f, 1.0f, 4.0f),
Utils::vec4<GLfloat>(-4.0f, -1.0f, -1.0f, -4.0f),
};
static const Utils::vec4<GLfloat> inverse_square_data[5] = {
Utils::vec4<GLfloat>(-2.0f, -1.0f, 1.0f, 2.0f), Utils::vec4<GLfloat>(-0.5f, -1.0f, 1.0f, 0.5f),
Utils::vec4<GLfloat>(4.0f, 1.0f, 1.0f, 4.0f), Utils::vec4<GLfloat>(0.25f, 1.0f, 1.0f, 0.25f),
Utils::vec4<GLfloat>(0.25f, 1.0f, 1.0f, 0.25f),
};
/* Do not execute the test if GL_ARB_shader_subroutine is not supported */
if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_subroutine"))
{
throw tcu::NotSupportedError("GL_ARB_shader_subroutine is not supported.");
}
m_n_active_subroutine_uniforms = 2;
m_n_active_subroutine_uniform_locations = 2;
m_n_active_subroutines = 4;
m_n_active_subroutine_uniform_name_length = 0;
m_n_active_subroutine_name_length = 0;
m_n_active_subroutine_uniform_size = 1;
/* GL objects */
Utils::program program(m_context);
Utils::buffer transform_feedback_buffer(m_context);
Utils::vertexArray vao(m_context);
bool result = true;
/* Calculate max name lengths for subroutines and subroutine uniforms */
for (GLint i = 0; i < m_n_active_subroutine_uniforms; ++i)
{
const GLsizei length = (GLsizei)strlen(subroutine_uniform_names[i]);
if (length > m_n_active_subroutine_uniform_name_length)
{
m_n_active_subroutine_uniform_name_length = length;
}
}
for (GLint i = 0; i < m_n_active_subroutines; ++i)
{
const GLsizei length = (GLsizei)strlen(subroutine_names[i]);
if (length > m_n_active_subroutine_name_length)
{
m_n_active_subroutine_name_length = length;
}
}
/* Init */
program.build(0 /* cs */, 0 /* fs */, 0 /* gs */, 0 /* tcs */, 0 /* test */, vertex_shader_code, varying_names,
n_varyings);
vao.generate();
vao.bind();
transform_feedback_buffer.generate();
transform_feedback_buffer.update(GL_TRANSFORM_FEEDBACK_BUFFER, transform_feedback_buffer_size, 0 /* data */,
GL_DYNAMIC_COPY);
transform_feedback_buffer.bindRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0, transform_feedback_buffer_size);
program.use();
/* Inspect Get* API */
if ((false == inspectProgramStageiv(program.m_program_object_id)) ||
(false == inspectActiveSubroutineUniformiv(program.m_program_object_id, subroutine_uniform_names)) ||
(false == inspectActiveSubroutineUniformName(program.m_program_object_id, subroutine_uniform_names)) ||
(false == inspectActiveSubroutineName(program.m_program_object_id, subroutine_names)) ||
(false ==
inspectSubroutineBinding(program.m_program_object_id, subroutine_names, subroutine_uniform_names, false)))
{
result = false;
}
/* Inspect GetProgram* API */
if (true == m_context.getContextInfo().isExtensionSupported("GL_ARB_program_interface_query"))
{
if ((false == inspectProgramInterfaceiv(program.m_program_object_id)) ||
(false ==
inspectProgramResourceiv(program.m_program_object_id, subroutine_names, subroutine_uniform_names)) ||
(false ==
inspectSubroutineBinding(program.m_program_object_id, subroutine_names, subroutine_uniform_names, true)))
{
result = false;
}
}
/* Test shader execution */
if ((false == testDraw(program.m_program_object_id, subroutine_names[inverse_order_routine_index],
subroutine_names[negate_routine_index], subroutine_uniform_names, inverse_order_negate_data,
false)) ||
(false == testDraw(program.m_program_object_id, subroutine_names[inverse_order_routine_index],
subroutine_names[inverse_routine_index], subroutine_uniform_names,
inverse_order_inverse_data, false)) ||
(false == testDraw(program.m_program_object_id, subroutine_names[inverse_order_routine_index],
subroutine_names[square_routine_index], subroutine_uniform_names, inverse_order_square_data,
false)) ||
(false == testDraw(program.m_program_object_id, subroutine_names[negate_routine_index],
subroutine_names[inverse_routine_index], subroutine_uniform_names, negate_inverse_data,
false)) ||
(false == testDraw(program.m_program_object_id, subroutine_names[negate_routine_index],
subroutine_names[square_routine_index], subroutine_uniform_names, negate_square_data,
false)) ||
(false == testDraw(program.m_program_object_id, subroutine_names[inverse_routine_index],
subroutine_names[square_routine_index], subroutine_uniform_names, inverse_square_data,
false)))
{
result = false;
}
if (true == m_context.getContextInfo().isExtensionSupported("GL_ARB_program_interface_query"))
{
if ((false == testDraw(program.m_program_object_id, subroutine_names[inverse_order_routine_index],
subroutine_names[negate_routine_index], subroutine_uniform_names,
inverse_order_negate_data, true)) ||
(false == testDraw(program.m_program_object_id, subroutine_names[inverse_order_routine_index],
subroutine_names[inverse_routine_index], subroutine_uniform_names,
inverse_order_inverse_data, true)) ||
(false == testDraw(program.m_program_object_id, subroutine_names[inverse_order_routine_index],
subroutine_names[square_routine_index], subroutine_uniform_names,
inverse_order_square_data, true)) ||
(false == testDraw(program.m_program_object_id, subroutine_names[negate_routine_index],
subroutine_names[inverse_routine_index], subroutine_uniform_names, negate_inverse_data,
true)) ||
(false == testDraw(program.m_program_object_id, subroutine_names[negate_routine_index],
subroutine_names[square_routine_index], subroutine_uniform_names, negate_square_data,
true)) ||
(false == testDraw(program.m_program_object_id, subroutine_names[inverse_routine_index],
subroutine_names[square_routine_index], subroutine_uniform_names, inverse_square_data,
true)))
{
result = false;
}
}
/* Done */
if (true == result)
{
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
}
else
{
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
}
return tcu::TestNode::STOP;
}
/** Verify result of getProgramStageiv
*
* @param program_id Program object id
* @param pname <pname> parameter for getProgramStageiv
* @param expected Expected value
*
* @return true if result is equal to expected value, flase otherwise
**/
bool FunctionalTest3_4::checkProgramStageiv(glw::GLuint program_id, glw::GLenum pname, glw::GLint expected) const
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
GLint value = 0;
gl.getProgramStageiv(program_id, GL_VERTEX_SHADER, pname, &value);
GLU_EXPECT_NO_ERROR(gl.getError(), "GetProgramStageiv");
if (expected != value)
{
m_context.getTestContext().getLog() << tcu::TestLog::Message
<< "Error. Invalid result. Function: getProgramStageiv. "
<< "pname: " << Utils::pnameToStr(pname) << ". "
<< "Result: " << value << ". "
<< "Expected: " << expected << "." << tcu::TestLog::EndMessage;
return false;
}
else
{
return true;
}
}
/** Verify result of getProgramResourceiv
*
* @param program_id Program object id
* @param program_interface Program interface
* @param pname <pname> parameter for getProgramStageiv
* @param resource_name Resource name
* @param expected Expected value
*
* @return true if result is equal to expected value, false otherwise
**/
bool FunctionalTest3_4::checkProgramResourceiv(GLuint program_id, GLenum program_interface, GLenum pname,
const glw::GLchar* resource_name, GLint expected) const
{
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
GLuint index = gl.getProgramResourceIndex(program_id, program_interface, resource_name);
GLint value = 0;
if (GL_INVALID_INDEX == index)
{
return false;
}
gl.getProgramResourceiv(program_id, program_interface, index, 1, &pname, 1, 0, &value);
GLU_EXPECT_NO_ERROR(gl.getError(), "getProgramResourceiv");
if (expected != value)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "Error. Invalid result. Function: getProgramResourceiv. "
<< "Program interface: " << Utils::programInterfaceToStr(program_interface) << ". "
<< "Resource name: " << resource_name << ". "
<< "Property: " << Utils::pnameToStr(pname) << ". "
<< "Result: " << value << ". "
<< "Expected: " << expected << "." << tcu::TestLog::EndMessage;
return false;
}
else
{
return true;
}
}
/** Verify result of getProgramInterfaceiv
*
* @param program_id Program object id
* @param program_interface Program interface
* @param pname <pname> parameter for getProgramStageiv
* @param expected Expected value
*
* @return true if result is equal to expected value, flase otherwise
**/
bool FunctionalTest3_4::checkProgramInterfaceiv(GLuint program_id, GLenum program_interface, GLenum pname,
GLint expected) const
{
const glw::Functions& gl = m_context.