blob: 99ca8162f8d9ca5de3791fbba67234287e2a3c0b [file] [log] [blame]
#ifndef _GL4CSHADERSUBROUTINETESTS_HPP
#define _GL4CSHADERSUBROUTINETESTS_HPP
/*-------------------------------------------------------------------------
* 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.hpp
* \brief Declares test classes for "Shader Subroutine" functionality.
*/ /*-------------------------------------------------------------------*/
#include "glcTestCase.hpp"
#include "glwDefs.hpp"
#include <queue>
#include "tcuTestLog.hpp"
namespace gl4cts
{
namespace ShaderSubroutine
{
class Utils
{
public:
/* Public type definitions */
struct buffer
{
buffer(deqp::Context& context);
~buffer();
void bindRange(glw::GLenum target, glw::GLuint index, glw::GLintptr offset, glw::GLsizeiptr size);
void generate();
void update(glw::GLenum target, glw::GLsizeiptr size, glw::GLvoid* data, glw::GLenum usage);
glw::GLuint m_id;
private:
deqp::Context& m_context;
};
struct framebuffer
{
framebuffer(deqp::Context& context);
~framebuffer();
void attachTexture(glw::GLenum attachment, glw::GLuint texture_id, glw::GLuint width, glw::GLuint height);
void bind();
void clear(glw::GLenum mask);
void clearColor(glw::GLfloat red, glw::GLfloat green, glw::GLfloat blue, glw::GLfloat alpha);
void generate();
glw::GLuint m_id;
private:
deqp::Context& m_context;
};
/** Store information about program object
*
**/
struct program
{
program(deqp::Context& context);
~program();
void 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 = false);
void compile(glw::GLuint shader_id, const glw::GLchar* shader_code) const;
bool isProgramBinarySupported() const;
void createFromBinary(const std::vector<glw::GLubyte>& binary, glw::GLenum binary_format);
void getBinary(std::vector<glw::GLubyte>& binary, glw::GLenum& binary_format) const;
glw::GLuint getSubroutineIndex(const glw::GLchar* subroutine_name, glw::GLenum shader_stage) const;
glw::GLint getSubroutineUniformLocation(const glw::GLchar* uniform_name, glw::GLenum shader_stage) const;
glw::GLint getUniformLocation(const glw::GLchar* uniform_name) const;
void link() const;
void remove();
void use() const;
static const glw::GLenum ARB_COMPUTE_SHADER;
glw::GLuint m_compute_shader_id;
glw::GLuint m_fragment_shader_id;
glw::GLuint m_geometry_shader_id;
glw::GLuint m_program_object_id;
glw::GLuint m_tesselation_control_shader_id;
glw::GLuint m_tesselation_evaluation_shader_id;
glw::GLuint m_vertex_shader_id;
private:
deqp::Context& m_context;
};
struct texture
{
texture(deqp::Context& context);
~texture();
void bind();
void create(glw::GLuint width, glw::GLuint height, glw::GLenum internal_format);
void get(glw::GLenum format, glw::GLenum type, glw::GLvoid* out_data);
void update(glw::GLuint width, glw::GLuint height, glw::GLenum format, glw::GLenum type, glw::GLvoid* data);
glw::GLuint m_id;
private:
deqp::Context& m_context;
};
struct vertexArray
{
vertexArray(deqp::Context& Context);
~vertexArray();
void generate();
void bind();
glw::GLuint m_id;
private:
deqp::Context& m_context;
};
/** Storage for 4 element vector of T
*
**/
template <typename T>
struct vec4
{
vec4()
{
}
vec4(T x, T y, T z, T w) : m_x(x), m_y(y), m_z(z), m_w(w)
{
}
bool operator==(const vec4& val) const
{
bool result = true;
result = result && compare(m_x, val.m_x);
result = result && compare(m_y, val.m_y);
result = result && compare(m_z, val.m_z);
result = result && compare(m_w, val.m_w);
return result;
}
void log(tcu::MessageBuilder& message) const
{
message << "[ " << m_x << ", " << m_y << ", " << m_z << ", " << m_w << " ]";
}
T m_x;
T m_y;
T m_z;
T m_w;
};
enum _shader_stage
{
SHADER_STAGE_FIRST,
SHADER_STAGE_VERTEX = SHADER_STAGE_FIRST,
SHADER_STAGE_TESSELLATION_CONTROL,
SHADER_STAGE_TESSELLATION_EVALUATION,
SHADER_STAGE_GEOMETRY,
SHADER_STAGE_FRAGMENT,
SHADER_STAGE_COUNT
};
enum _variable_type
{
VARIABLE_TYPE_BOOL,
VARIABLE_TYPE_BVEC2,
VARIABLE_TYPE_BVEC3,
VARIABLE_TYPE_BVEC4,
VARIABLE_TYPE_DOUBLE,
VARIABLE_TYPE_DVEC2,
VARIABLE_TYPE_DVEC3,
VARIABLE_TYPE_DVEC4,
VARIABLE_TYPE_FLOAT,
VARIABLE_TYPE_INT,
VARIABLE_TYPE_IVEC2,
VARIABLE_TYPE_IVEC3,
VARIABLE_TYPE_IVEC4,
VARIABLE_TYPE_MAT2,
VARIABLE_TYPE_MAT2X3,
VARIABLE_TYPE_MAT2X4,
VARIABLE_TYPE_MAT3,
VARIABLE_TYPE_MAT3X2,
VARIABLE_TYPE_MAT3X4,
VARIABLE_TYPE_MAT4,
VARIABLE_TYPE_MAT4X2,
VARIABLE_TYPE_MAT4X3,
VARIABLE_TYPE_UINT,
VARIABLE_TYPE_UVEC2,
VARIABLE_TYPE_UVEC3,
VARIABLE_TYPE_UVEC4,
VARIABLE_TYPE_VEC2,
VARIABLE_TYPE_VEC3,
VARIABLE_TYPE_VEC4,
/* Always last */
VARIABLE_TYPE_UNKNOWN
};
/* Public methods */
static bool 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);
static _variable_type getBaseVariableType(const _variable_type& variable_type);
static unsigned int getComponentSizeForVariableType(const _variable_type& variable_type);
static glw::GLenum getGLenumForShaderStage(const _shader_stage& shader_stage);
static unsigned int getNumberOfComponentsForVariableType(const _variable_type& variable_type);
static std::string getShaderStageString(const _shader_stage& shader_stage);
static std::string getShaderStageStringFromGLEnum(const glw::GLenum shader_stage_glenum);
static _variable_type getVariableTypeFromProperties(const _variable_type& base_variable_type,
const unsigned int& n_components);
static std::string getVariableTypeGLSLString(const _variable_type& variable_type);
static const glw::GLchar* programInterfaceToStr(glw::GLenum program_interface);
static const glw::GLchar* pnameToStr(glw::GLenum pname);
private:
/* Private methods */
template <typename T>
static bool compare(const T& left, const T& right)
{
return left == right;
}
static bool compare(const glw::GLfloat& left, const glw::GLfloat& right);
};
/** Verify that Get* commands accept MAX_SUBROUTINES and
* MAX_SUBROUTINE_UNIFORM_LOCATIONS tokens and that the returned values
* are not lower than required by the specification.
**/
class APITest1 : public deqp::TestCase
{
public:
/* Public methods */
APITest1(deqp::Context& context);
virtual tcu::TestNode::IterateResult iterate();
private:
/* Private type definitions */
/* Private methods */
/* Private fields */
bool m_has_test_passed;
};
/** Check if <bufsize> and <length> parameters behave correctly in
* GetActiveSubroutineName and GetActiveSubroutineUniformName functions.
**/
class APITest2 : public deqp::TestCase
{
public:
/* Public methods */
APITest2(deqp::Context& context);
virtual void deinit();
virtual tcu::TestNode::IterateResult iterate();
private:
/* Private type definitions */
/* Private methods */
std::string getVertexShaderBody();
void initTest();
void verifyGLGetActiveSubroutineNameFunctionality();
void verifyGLGetActiveSubroutineUniformNameFunctionality();
/* Private fields */
glw::GLchar* m_buffer;
bool m_has_test_passed;
glw::GLuint m_po_id;
const char* m_subroutine_name1;
const char* m_subroutine_name2;
const char* m_subroutine_uniform_name;
glw::GLuint m_vs_id;
};
/** * Create program with 2 subroutines taking one parameter and 1 subroutine
* uniform. Select the first subroutine and make a draw. Verify the result
* and draw again with second subroutine selected then verify result again.
* Repeat for following subroutines return and argument types: bool, float,
* int, uint, double, *vec*, *mat*.
*
* * Same as above, but with return and argument types as arrays.
*
***/
class FunctionalTest1_2 : public deqp::TestCase
{
public:
/* Public methods */
FunctionalTest1_2(deqp::Context& context);
virtual void deinit();
virtual tcu::TestNode::IterateResult iterate();
private:
/* Private type definitions */
struct _test_case
{
unsigned int array_size;
Utils::_variable_type variable_type;
};
typedef std::vector<_test_case> _test_cases;
typedef _test_cases::const_iterator _test_cases_const_iterator;
/* Private methods */
void deinitTestIteration();
bool executeTestIteration(const _test_case& test_case);
std::string getVertexShaderBody(const Utils::_variable_type& variable_type, unsigned int array_size);
void initTest();
bool verifyXFBData(const void* xfb_data, const Utils::_variable_type& variable_type);
/* Private fields */
bool m_has_test_passed;
glw::GLuint m_po_id;
glw::GLuint m_po_getter0_subroutine_index;
glw::GLuint m_po_getter1_subroutine_index;
glw::GLint m_po_subroutine_uniform_index;
_test_cases m_test_cases;
glw::GLuint m_xfb_bo_id;
glw::GLuint m_vao_id;
glw::GLuint m_vs_id;
};
/** * Create a program with 4 subroutines and 2 subroutine uniforms and query
* it using: GetProgramStageiv, GetActiveSubroutineUniformiv,
* GetActiveSubroutineUniformName, GetActiveSubroutineName,
* GetUniformSubroutineuiv, GetSubroutineIndex and
* GetSubroutineUniformLocation. Verify the results and use them to select
* subroutines, then make a draw and select different set of subroutines.
* Draw again and verify the results.
*
* OpenGL 4.3 or ARB_program_interface_query support required
* * Same as above, but query the program using calls introduced in
* ARB_program_interface_query extension.
**/
class FunctionalTest3_4 : public deqp::TestCase
{
public:
/* Public methods */
FunctionalTest3_4(deqp::Context& context);
virtual tcu::TestNode::IterateResult iterate();
private:
/* Private types */
/** Connect pname with expected value. Used to check Get* API.
*
**/
struct inspectionDetails
{
glw::GLenum pname;
glw::GLint expected_value;
};
/* Private types */
/** Connect program_interface, pname and expected value. Used to check GetProgramInterface.
*
**/
struct inspectionDetailsForProgramInterface
{
glw::GLenum program_interface;
glw::GLenum pname;
glw::GLint expected_value;
};
/* Private methods */
bool checkProgramStageiv(glw::GLuint program_id, glw::GLenum pname, glw::GLint expected) const;
bool checkProgramResourceiv(glw::GLuint program_id, glw::GLenum program_interface, glw::GLenum prop,
const glw::GLchar* resource_name, glw::GLint expected) const;
bool checkProgramInterfaceiv(glw::GLuint program_id, glw::GLenum program_interface, glw::GLenum pname,
glw::GLint expected) const;
bool checkActiveSubroutineUniformiv(glw::GLuint program_id, glw::GLuint index, glw::GLenum pname,
glw::GLint expected) const;
glw::GLuint getProgramResourceIndex(glw::GLuint program_id, glw::GLenum program_interface,
const glw::GLchar* resource_name) const;
glw::GLuint getSubroutineIndex(glw::GLuint program_id, const glw::GLchar* subroutine_name,
bool use_program_query) const;
glw::GLint getSubroutineUniformLocation(glw::GLuint program_id, const glw::GLchar* uniform_name,
bool use_program_query) const;
bool inspectProgramStageiv(glw::GLuint program_id) const;
bool inspectProgramInterfaceiv(glw::GLuint program_id) const;
bool inspectProgramResourceiv(glw::GLuint program_id, const glw::GLchar** subroutine_names,
const glw::GLchar** uniform_names) const;
bool inspectActiveSubroutineUniformiv(glw::GLuint program_id, const glw::GLchar** uniform_names) const;
bool inspectActiveSubroutineUniformName(glw::GLuint program_id, const glw::GLchar** uniform_names) const;
bool inspectActiveSubroutineName(glw::GLuint program_id, const glw::GLchar** subroutine_names) const;
bool inspectSubroutineBinding(glw::GLuint program_id, const glw::GLchar** subroutine_names,
const glw::GLchar** uniform_names, bool use_program_query) const;
bool testDraw(glw::GLuint program_id, const glw::GLchar* first_routine_name, const glw::GLchar* second_routine_name,
const glw::GLchar** uniform_names, const Utils::vec4<glw::GLfloat> data[5],
bool use_program_query) const;
/* Private fields */
glw::GLint m_n_active_subroutine_uniforms;
glw::GLint m_n_active_subroutine_uniform_locations;
glw::GLint m_n_active_subroutines;
glw::GLint m_n_active_subroutine_uniform_name_length;
glw::GLint m_n_active_subroutine_name_length;
glw::GLint m_n_active_subroutine_uniform_size;
};
/**
* * Create a program with 8 subroutines and 4 subroutine uniforms. Each
* subroutine uniform should have different signature that should match 2
* subroutines. Go through all possible combinations of subroutine uniforms
* values and for each combination verify that it works as expected.
**/
class FunctionalTest5 : public deqp::TestCase
{
public:
/* Public methods */
FunctionalTest5(deqp::Context& context);
virtual tcu::TestNode::IterateResult iterate();
private:
/* Private methods */
void logError(const glw::GLchar* subroutine_names[4][2], const glw::GLuint subroutine_combination[4],
const Utils::vec4<glw::GLfloat> input_data[3], const Utils::vec4<glw::GLfloat>& first_routine_result,
const Utils::vec4<glw::GLfloat>& second_routine_result,
const Utils::vec4<glw::GLfloat>& third_routine_result,
const Utils::vec4<glw::GLuint>& fourth_routine_result,
const Utils::vec4<glw::GLfloat>& first_routine_expected_result,
const Utils::vec4<glw::GLfloat>& second_routine_expected_result,
const Utils::vec4<glw::GLfloat>& third_routine_expected_result,
const Utils::vec4<glw::GLuint>& fourth_routine_expected_result) const;
void testDraw(const glw::GLuint subroutine_combination[4], const Utils::vec4<glw::GLfloat> input_data[3],
Utils::vec4<glw::GLfloat>& out_first_routine_result,
Utils::vec4<glw::GLfloat>& out_second_routine_result,
Utils::vec4<glw::GLfloat>& out_third_routine_result,
Utils::vec4<glw::GLuint>& out_fourth_routine_result) const;
bool verify(const Utils::vec4<glw::GLfloat>& first_routine_result,
const Utils::vec4<glw::GLfloat>& second_routine_result,
const Utils::vec4<glw::GLfloat>& third_routine_result,
const Utils::vec4<glw::GLuint>& fourth_routine_result,
const Utils::vec4<glw::GLfloat>& first_routine_expected_result,
const Utils::vec4<glw::GLfloat>& second_routine_expected_result,
const Utils::vec4<glw::GLfloat>& third_routine_expected_result,
const Utils::vec4<glw::GLuint>& fourth_routine_expected_result) const;
/* Private fields */
glw::GLuint m_subroutine_uniform_locations[4][1];
glw::GLuint m_subroutine_indices[4][2];
glw::GLuint m_uniform_locations[3];
};
/**
* * Create a program with a subroutine and a subroutine uniform. Verify that
* subroutine can be called directly with a static use of subroutine's
* function name, as is done with non-subroutine function declarations and
* calls.
**/
class FunctionalTest6 : public deqp::TestCase
{
public:
/* Public methods */
FunctionalTest6(deqp::Context& context);
virtual tcu::TestNode::IterateResult iterate();
};
/**
* * Create a program with 2 subroutines and an array of 4 subroutine
* uniforms. Go through all possible combinations of subroutine uniforms
* values and for each combination verify that it works as expected by
* performing draw or dispatch call. Also verify that length() function
* works correctly when used on array of subroutine uniforms.
*
* * Verify that program which uses uniforms, constant expressions and
* dynamically uniform loop index to access subroutine uniform array
* compiles and works as expected.
**/
class FunctionalTest7_8 : public deqp::TestCase
{
public:
/* Public methods */
FunctionalTest7_8(deqp::Context& context);
virtual tcu::TestNode::IterateResult iterate();
private:
/* Private methods */
void calculate(glw::GLuint function, const Utils::vec4<glw::GLfloat>& left, const Utils::vec4<glw::GLfloat>& right,
Utils::vec4<glw::GLfloat>& out) const;
void calculate(const glw::GLuint combination[4], const Utils::vec4<glw::GLfloat>& left,
const Utils::vec4<glw::GLfloat>& right, const Utils::vec4<glw::GLuint>& indices,
Utils::vec4<glw::GLfloat>& out_combined, Utils::vec4<glw::GLfloat>& out_combined_inversed,
Utils::vec4<glw::GLfloat>& out_constant, Utils::vec4<glw::GLfloat>& out_constant_inversed,
Utils::vec4<glw::GLfloat>& out_dynamic, Utils::vec4<glw::GLfloat>& out_dynamic_inversed,
Utils::vec4<glw::GLfloat>& out_loop) const;
void logError(const glw::GLuint combination[4], const Utils::vec4<glw::GLfloat>& left,
const Utils::vec4<glw::GLfloat>& right, const Utils::vec4<glw::GLuint>& indices,
const Utils::vec4<glw::GLfloat> vec4_expected[7], const Utils::vec4<glw::GLfloat> vec4_result[7],
glw::GLuint array_length, bool result[7]) const;
bool testDraw(const glw::GLuint combination[4], const Utils::vec4<glw::GLfloat>& left,
const Utils::vec4<glw::GLfloat>& right, const Utils::vec4<glw::GLuint>& indices) const;
/* Private fields */
glw::GLuint m_subroutine_uniform_locations[4];
glw::GLuint m_subroutine_indices[2];
glw::GLuint m_uniform_locations[3];
};
/**
* Make sure that program with one function associated with 3 different
* subroutine types and 3 subroutine uniforms using that function compiles
* and works as expected.
*
**/
class FunctionalTest9 : public deqp::TestCase
{
public:
/* Public methods */
FunctionalTest9(deqp::Context& context);
virtual void deinit();
virtual tcu::TestNode::IterateResult iterate();
private:
/* Private methods */
std::string getVertexShaderBody() const;
void initTest();
void verifyXFBData(const glw::GLvoid* data_ptr);
/* Private fields */
bool m_has_test_passed;
const unsigned int m_n_points_to_draw;
glw::GLuint m_po_id;
glw::GLuint m_vao_id;
glw::GLuint m_vs_id;
glw::GLuint m_xfb_bo_id;
};
/**
* OpenGL 4.3 or ARB_arrays_of_arrays support required
* * Create a program that uses array of arrays for subroutine uniform type
* and verify that it works as expected.
**/
class FunctionalTest10 : public deqp::TestCase
{
public:
FunctionalTest10(deqp::Context& context);
virtual tcu::TestNode::IterateResult iterate();
private:
/* Private methods */
glw::GLint testDraw(const glw::GLuint routine_indices[16]) const;
/* Private fields */
glw::GLuint m_subroutine_uniform_locations[16];
glw::GLuint m_subroutine_indices[2];
};
/**
* * Verify that following operations work correctly when performed inside
* subroutine body: setting global variable, texture sampling, writing
* to fragment shader outputs, using discard function (fragment shader
* only), calling other functions and subroutines.
**/
class FunctionalTest11 : public deqp::TestCase
{
public:
/* Public methods */
FunctionalTest11(deqp::Context& context);
virtual tcu::TestNode::IterateResult iterate();
private:
/* Private types */
struct testConfiguration
{
testConfiguration(const glw::GLchar* description, const glw::GLubyte expected_color[4],
glw::GLuint discard_fragment, glw::GLuint set_global_colors, glw::GLuint sample_texture,
glw::GLuint compare, glw::GLuint test, glw::GLuint first_sampler, glw::GLuint second_sampler)
{
m_description = description;
m_expected_color[0] = expected_color[0];
m_expected_color[1] = expected_color[1];
m_expected_color[2] = expected_color[2];
m_expected_color[3] = expected_color[3];
m_routines[0] = discard_fragment;
m_routines[1] = set_global_colors;
m_routines[2] = sample_texture;
m_routines[3] = compare;
m_routines[4] = test;
m_samplers[0] = first_sampler;
m_samplers[1] = second_sampler;
}
const glw::GLchar* m_description;
glw::GLubyte m_expected_color[4];
glw::GLuint m_routines[5];
glw::GLuint m_samplers[2];
};
/* Private methods */
void fillTexture(Utils::texture& texture, const glw::GLubyte color[4]) const;
bool testDraw(const glw::GLuint routine_configuration[5], const glw::GLuint sampler_configuration[2],
const glw::GLubyte expected_color[4], Utils::texture& color_texture) const;
/* Private fields */
/* Constants */
static const glw::GLuint m_texture_height;
static const glw::GLuint m_texture_width;
/* Locations and indices */
glw::GLuint m_subroutine_uniform_locations[5];
glw::GLuint m_subroutine_indices[5][2];
glw::GLuint m_uniform_locations[2];
glw::GLuint m_source_textures[2];
};
/**
* OpenGL 4.3 or ARB_shader_storage_buffer_object, ARB_atomic_counters
* and ARB_shader_image_load_store support required
* * Same as above, but check writing/reading from storage buffer, performing
* operations on atomic counters and writing/reading from an image. This
* should be tested in a program stage which supports operations of these
* kind.
**/
class FunctionalTest12 : public deqp::TestCase
{
public:
FunctionalTest12(deqp::Context& context);
virtual tcu::TestNode::IterateResult iterate();
private:
/* Private methods */
void fillTexture(Utils::texture& texture, const glw::GLuint color[4]) const;
bool verifyTexture(Utils::texture& texture, const glw::GLuint color[4]) const;
bool testAtomic();
bool testAtomicDraw(glw::GLuint subourinte_index, const glw::GLuint expected_results[3]) const;
bool testImage();
bool testImageDraw(glw::GLuint subroutine_index, Utils::texture& left, Utils::texture& right,
const glw::GLuint expected_left_color[4], const glw::GLuint expected_right_color[4]) const;
bool testSSBO();
bool testSSBODraw(glw::GLuint subourinte_index, const glw::GLuint expected_results[4]) const;
/* Private fields */
/* Constatnts */
static const glw::GLuint m_texture_height;
static const glw::GLuint m_texture_width;
/* Locations */
glw::GLuint m_left_image;
glw::GLuint m_right_image;
};
/**
* Verify that subroutines work correctly when used in separate shader
* objects.
*
**/
class FunctionalTest13 : public deqp::TestCase
{
public:
/* Public methods */
FunctionalTest13(deqp::Context& context);
virtual void deinit();
virtual tcu::TestNode::IterateResult iterate();
private:
/* Private methods */
std::string getFragmentShaderBody(unsigned int n_id);
std::string getGeometryShaderBody(unsigned int n_id);
std::string getTessellationControlShaderBody(unsigned int n_id);
std::string getTessellationEvaluationShaderBody(unsigned int n_id);
std::string getVertexShaderBody(unsigned int n_id);
void initTest();
void verifyReadBuffer(unsigned int n_fs_id, unsigned int n_fs_subroutine, unsigned int n_gs_id,
unsigned int n_gs_subroutine, unsigned int n_tc_id, unsigned int n_tc_subroutine,
unsigned int n_te_id, unsigned int n_te_subroutine, unsigned int n_vs_id,
unsigned int n_vs_subroutine);
/* Private fields */
glw::GLuint m_fbo_id;
glw::GLuint m_fs_po_ids[2];
glw::GLuint m_gs_po_ids[2];
glw::GLuint m_pipeline_id;
unsigned char* m_read_buffer;
glw::GLuint m_tc_po_ids[2];
glw::GLuint m_te_po_ids[2];
const unsigned int m_to_height;
glw::GLuint m_to_id;
const unsigned int m_to_width;
glw::GLuint m_vao_id;
glw::GLuint m_vs_po_ids[2];
bool m_has_test_passed;
};
/**
* * Create program with subroutines that use structures as parameters and
* make sure it works correctly.
*
* OpenGL 4.1 or ARB_get_program_binary support required
* * Create a program with 4 subroutines and 2 subroutine uniforms. Query
* names and indices of all active subroutines and query names and
* locations of all active subroutine uniforms. Call GetProgramBinary on
* this program and delete it. Create new program from the binary using
* ProgramBinary. Verify that all active subroutine names and indices in
* this program match ones from the original program. Also verify that
* all active subroutine uniform names and locations match ones from
* original program. Make a draw, expect random but valid set of selected
* subroutines, then select arbitrary set of subroutines, make a draw and
* verify the results.
**/
class FunctionalTest14_15 : public deqp::TestCase
{
public:
FunctionalTest14_15(deqp::Context& context);
virtual tcu::TestNode::IterateResult iterate();
private:
/* Private methods */
bool testDefaultSubroutineSet(const Utils::vec4<glw::GLuint>& uni_input,
const Utils::vec4<glw::GLuint> expected_routine_1_result[2],
const Utils::vec4<glw::GLuint> expected_routine_2_result[2]) const;
bool testDraw(glw::GLuint routine_configuration, const Utils::vec4<glw::GLuint>& uni_input,
const Utils::vec4<glw::GLuint>& expected_routine_1_result,
const Utils::vec4<glw::GLuint>& expected_routine_2_result) const;
bool testIndicesAndLocations() const;
/* Private fields */
/* Locations and indices */
glw::GLuint m_subroutine_uniform_locations[2];
glw::GLuint m_subroutine_indices[2][2];
glw::GLuint m_uniform_location;
glw::GLuint m_initial_subroutine_uniform_locations[2];
glw::GLuint m_initial_subroutine_indices[2][2];
};
/**
* Check that when the active program for a shader stage is re-linked or
* changed by a call to UseProgram, BindProgramPipeline, or
* UseProgramStages, subroutine uniforms for that stage are reset to
* arbitrarily chosen default functions with compatible subroutine types.
*
**/
class FunctionalTest16 : public deqp::TestCase
{
public:
/* Public methods */
FunctionalTest16(deqp::Context& context);
virtual void deinit();
virtual tcu::TestNode::IterateResult iterate();
private:
/* Private type definitions */
/* Defines a specific use case that should be checked during particular
* test iteration.
*/
enum _test_case
{
TEST_CASE_FIRST,
TEST_CASE_SWITCH_TO_DIFFERENT_PROGRAM_OBJECT = TEST_CASE_FIRST,
TEST_CASE_SWITCH_TO_DIFFERENT_PROGRAM_PIPELINE_OBJECT,
TEST_CASE_SWITCH_TO_DIFFERENT_PIPELINE_FRAGMENT_STAGE,
TEST_CASE_SWITCH_TO_DIFFERENT_PIPELINE_GEOMETRY_STAGE,
TEST_CASE_SWITCH_TO_DIFFERENT_PIPELINE_TESS_CONTROL_STAGE,
TEST_CASE_SWITCH_TO_DIFFERENT_PIPELINE_TESS_EVALUATION_STAGE,
TEST_CASE_SWITCH_TO_DIFFERENT_PIPELINE_VERTEX_STAGE,
/* Always last */
TEST_CASE_COUNT
};
/** Defines a number of different subroutine-specific properties
* for a single shader stage.
**/
struct _shader_stage
{
glw::GLuint default_subroutine1_value;
glw::GLuint default_subroutine2_value;
glw::GLuint default_subroutine3_value;
glw::GLuint default_subroutine4_value;
glw::GLint subroutine1_uniform_location;
glw::GLint subroutine2_uniform_location;
glw::GLint subroutine3_uniform_location;
glw::GLint subroutine4_uniform_location;
glw::GLuint function1_index;
glw::GLuint function2_index;
glw::GLuint function3_index;
glw::GLuint function4_index;
glw::GLenum gl_stage;
};
/** Describes subroutine-specific properties for a program object */
struct _program
{
_shader_stage fragment;
_shader_stage geometry;
_shader_stage tess_control;
_shader_stage tess_evaluation;
_shader_stage vertex;
};
/** Describes modes that verify*() functions can run in */
enum _subroutine_uniform_value_verification
{
SUBROUTINE_UNIFORMS_SET_TO_DEFAULT_VALUES,
SUBROUTINE_UNIFORMS_SET_TO_NONDEFAULT_VALUES,
SUBROUTINE_UNIFORMS_SET_TO_VALID_VALUES,
};
/* Private methods */
std::string getShaderBody(const Utils::_shader_stage& shader_stage, const unsigned int& n_id) const;
void getShaderStages(bool retrieve_program_object_shader_ids, const unsigned int& n_id,
const _shader_stage** out_shader_stages) const;
void initTest();
void verifySubroutineUniformValues(const _test_case& test_case, const unsigned int& n_id,
const _subroutine_uniform_value_verification& verification);
void verifySubroutineUniformValuesForShaderStage(const _shader_stage& shader_stage,
const _subroutine_uniform_value_verification& verification);
/* Private fields */
bool m_are_pipeline_objects_supported;
bool m_has_test_passed;
glw::GLuint m_fs_ids[2];
glw::GLuint m_gs_ids[2];
glw::GLuint m_po_ids[2];
glw::GLuint m_tc_ids[2];
glw::GLuint m_te_ids[2];
glw::GLuint m_vs_ids[2];
glw::GLuint m_fs_po_ids[2];
glw::GLuint m_gs_po_ids[2];
glw::GLuint m_pipeline_object_ids[2];
glw::GLuint m_tc_po_ids[2];
glw::GLuint m_te_po_ids[2];
glw::GLuint m_vs_po_ids[2];
_shader_stage m_fs_po_descriptors[2];
_shader_stage m_gs_po_descriptors[2];
_shader_stage m_tc_po_descriptors[2];
_shader_stage m_te_po_descriptors[2];
_shader_stage m_vs_po_descriptors[2];
_program m_po_descriptors[2];
};
/**
* Create a program which uses the same subroutine and subroutine uniform
* names for every stage. Types of subroutines should be different in each
* stage. Make sure that such program compiles and works as expected.
**/
class FunctionalTest17 : public deqp::TestCase
{
public:
/* Public methods */
FunctionalTest17(deqp::Context& context);
virtual void deinit();
virtual tcu::TestNode::IterateResult iterate();
private:
/* Private methods */
std::string getFragmentShaderBody() const;
std::string getGeometryShaderBody() const;
std::string getTessellationControlShaderBody() const;
std::string getTessellationEvaluationShaderBody() const;
std::string getVertexShaderBody() const;
void initTest();
void verifyRenderedData();
/* Private fields */
glw::GLuint m_fbo_id;
glw::GLuint m_fs_id;
glw::GLuint m_gs_id;
bool m_has_test_passed;
glw::GLuint m_po_id;
glw::GLuint m_tc_id;
glw::GLuint m_te_id;
float* m_to_data;
const unsigned int m_to_height;
glw::GLuint m_to_id;
const unsigned int m_to_width;
glw::GLuint m_vao_id;
glw::GLuint m_vs_id;
};
/**
* Make sure that calling a subroutine with argument value returned by
* another subroutine works correctly.
*
* Verify that subroutines and subroutine uniforms work as expected when
* they are used in connection with control flow functions
* (if/else/case/while/for/break/continue).
*
**/
class FunctionalTest18_19 : public deqp::TestCase
{
public:
/* Public methods */
FunctionalTest18_19(deqp::Context& context);
virtual void deinit();
virtual tcu::TestNode::IterateResult iterate();
private:
/* Private type definitions */
typedef tcu::Vec4 (*PFNVEC4OPERATORPROC)(tcu::Vec4);
/* Private methods */
void executeTest(glw::GLuint bool_operator1_subroutine_location, glw::GLuint bool_operator2_subroutine_location,
glw::GLuint vec4_operator1_subroutine_location, glw::GLuint vec4_operator2_subroutine_location);
std::string getVertexShaderBody() const;
void initTest();
void verifyXFBData(const glw::GLvoid* data, glw::GLuint bool_operator1_subroutine_location,
glw::GLuint bool_operator2_subroutine_location, glw::GLuint vec4_operator1_subroutine_location,
glw::GLuint vec4_operator2_subroutine_location);
static tcu::Vec4 vec4operator_div2(tcu::Vec4 data);
static tcu::Vec4 vec4operator_mul4(tcu::Vec4 data);
/* Private fields */
bool m_has_test_passed;
const unsigned int m_n_points_to_draw;
glw::GLuint m_po_id;
glw::GLuint m_po_subroutine_divide_by_two_location;
glw::GLuint m_po_subroutine_multiply_by_four_location;
glw::GLuint m_po_subroutine_returns_false_location;
glw::GLuint m_po_subroutine_returns_true_location;
glw::GLint m_po_subroutine_uniform_bool_operator1;
glw::GLint m_po_subroutine_uniform_bool_operator2;
glw::GLint m_po_subroutine_uniform_vec4_processor1;
glw::GLint m_po_subroutine_uniform_vec4_processor2;
glw::GLuint m_xfb_bo_id;
glw::GLuint m_vao_id;
glw::GLuint m_vs_id;
};
/**
* Test whether all INVALID_OPERATION, INVALID_VALUE and INVALID_ENUM
* errors related to subroutines usage are properly generated.
**/
class NegativeTest1 : public deqp::TestCase
{
public:
/* Public methods */
NegativeTest1(deqp::Context& context);
virtual void deinit();
virtual tcu::TestNode::IterateResult iterate();
private:
/* Private methods */
void initTest();
/* Private fields */
bool m_has_test_passed;
glw::GLint m_po_active_subroutine_uniform_locations;
glw::GLint m_po_active_subroutine_uniforms;
glw::GLint m_po_active_subroutines;
glw::GLint m_po_subroutine_uniform_function_index;
glw::GLint m_po_subroutine_uniform_function2_index;
glw::GLuint m_po_subroutine_test1_index;
glw::GLuint m_po_subroutine_test2_index;
glw::GLuint m_po_subroutine_test3_index;
glw::GLuint m_po_not_linked_id;
glw::GLuint m_po_id;
glw::GLuint m_vs_id;
};
/** Make sure that subroutine uniform variables are scoped to the shader
* execution stage the variable is declared in. Referencing subroutine
* uniform from different stage should cause compile or link error
**/
class NegativeTest2 : public deqp::TestCase
{
public:
/* Public methods */
NegativeTest2(deqp::Context& context);
virtual void deinit();
virtual tcu::TestNode::IterateResult iterate();
private:
/* Private type definitions */
/* Private methods */
void deinitGLObjects();
void executeTestCase(const Utils::_shader_stage& referencing_stage);
std::string getFragmentShaderBody(const Utils::_shader_stage& referencing_stage) const;
std::string getGeometryShaderBody(const Utils::_shader_stage& referencing_stage) const;
std::string getSubroutineUniformName(const Utils::_shader_stage& stage) const;
std::string getTessellationControlShaderBody(const Utils::_shader_stage& referencing_stage) const;
std::string getTessellationEvaluationShaderBody(const Utils::_shader_stage& referencing_stage) const;
std::string getVertexShaderBody(const Utils::_shader_stage& referencing_stage) const;
/* Private fields */
glw::GLuint m_fs_id;
glw::GLuint m_gs_id;
bool m_has_test_passed;
glw::GLuint m_po_id;
glw::GLuint m_tc_id;
glw::GLuint m_te_id;
glw::GLuint m_vs_id;
};
/** Verify that "subroutine" keyword is necessary when declaring a
* subroutine uniform and a compilation error occurs without it.
**/
class NegativeTest3 : public deqp::TestCase
{
public:
/* Public methods */
NegativeTest3(deqp::Context& context);
virtual void deinit();
virtual tcu::TestNode::IterateResult iterate();
private:
/* Private methods */
void executeTest(const Utils::_shader_stage& shader_stage);
std::string getFragmentShaderBody() const;
std::string getGeometryShaderBody() const;
std::string getTessellationControlShaderBody() const;
std::string getTessellationEvaluationShaderBody() const;
std::string getVertexShaderBody() const;
/* Private fields */
bool m_has_test_passed;
glw::GLuint m_so_id;
};
/**
* Verify that compile-time error is present when arguments and return type
* do not match between the function and each associated subroutine type.
* In particular make sure that applies when there are multiple associated
* subroutine types and only one of them does not match.
*
**/
class NegativeTest4 : public deqp::TestCase
{
public:
/* Public methods */
NegativeTest4(deqp::Context& context);
virtual void deinit();
virtual tcu::TestNode::IterateResult iterate();
private:
/* Private type declarations */
enum _test_case
{
TEST_CASE_FIRST,
TEST_CASE_INCOMPATIBLE_RETURN_TYPE = TEST_CASE_FIRST,
TEST_CASE_INCOMPATIBLE_ARGUMENT_LIST,
/* Always last */
TEST_CASE_COUNT
};
/* Private methods */
std::string getShaderBody(const Utils::_shader_stage& shader_stage, const unsigned int& n_subroutine_types,
const _test_case& test_case) const;
/* Private fields */
bool m_has_test_passed;
glw::GLint m_so_id;
};
/** Verify that link or compile error occurs when trying to link a program
* with no subroutine for subroutine uniform variable.
**/
class NegativeTest5 : public deqp::TestCase
{
public:
/* Public methods */
NegativeTest5(deqp::Context& context);
virtual void deinit();
virtual tcu::TestNode::IterateResult iterate();
private:
/* Private type definitions */
/* Private methods */
void deinitIteration();
void executeIteration(const Utils::_shader_stage& shader_stage);
std::string getFragmentShaderBody(bool include_invalid_subroutine_uniform_declaration) const;
std::string getGeometryShaderBody(bool include_invalid_subroutine_uniform_declaration) const;
std::string getTessellationControlShaderBody(bool include_invalid_subroutine_uniform_declaration) const;
std::string getTessellationEvaluationShaderBody(bool include_invalid_subroutine_uniform_declaration) const;
std::string getVertexShaderBody(bool include_invalid_subroutine_uniform_declaration) const;
/* Private fields */
glw::GLuint m_fs_id;
glw::GLuint m_gs_id;
bool m_has_test_passed;
glw::GLuint m_po_id;
glw::GLuint m_tc_id;
glw::GLuint m_te_id;
glw::GLuint m_vs_id;
};
/** Check that link or compile error occurs if any shader in a program
* includes two or more functions with the same name and at least one of
* which is associated with a subroutine type.
**/
class NegativeTest6 : public deqp::TestCase
{
public:
/* Public methods */
NegativeTest6(deqp::Context& context);
virtual void deinit();
virtual tcu::TestNode::IterateResult iterate();
private:
/* Private type definitions */
/* Private methods */
void deinitIteration();
void executeIteration(const Utils::_shader_stage& shader_stage);
std::string getFragmentShaderBody(bool include_invalid_declaration) const;
std::string getGeometryShaderBody(bool include_invalid_declaration) const;
std::string getTessellationControlShaderBody(bool include_invalid_declaration) const;
std::string getTessellationEvaluationShaderBody(bool include_invalid_declaration) const;
std::string getVertexShaderBody(bool include_invalid_declaration) const;
/* Private fields */
glw::GLuint m_fs_id;
glw::GLuint m_gs_id;
bool m_has_test_passed;
glw::GLuint m_po_id;
glw::GLuint m_tc_id;
glw::GLuint m_te_id;
glw::GLuint m_vs_id;
};
/**
* * Verify that program fails to link if there is any possible combination
* of subroutine uniform values that would result in recursion.
**/
class NegativeTest7 : public deqp::TestCase
{
public:
NegativeTest7(deqp::Context& contex);
virtual void deinit();
virtual tcu::TestNode::IterateResult iterate();
private:
/* Private methods */
bool test(const glw::GLchar* vertex_shader_code, const glw::GLchar* name_of_recursive_routine);
/* Private fields */
glw::GLuint m_program_id;
glw::GLuint m_vertex_shader_id;
};
/** Test that either compile or link error occurs when function declared
* with subroutine does not include a body.
**/
class NegativeTest8 : public deqp::TestCase
{
public:
/* Public methods */
NegativeTest8(deqp::Context& context);
virtual void deinit();
virtual tcu::TestNode::IterateResult iterate();
private:
/* Private type definitions */
/* Private methods */
void deinitIteration();
void executeIteration(const Utils::_shader_stage& shader_stage);
std::string getFragmentShaderBody(bool include_invalid_declaration) const;
std::string getGeometryShaderBody(bool include_invalid_declaration) const;
std::string getTessellationControlShaderBody(bool include_invalid_declaration) const;
std::string getTessellationEvaluationShaderBody(bool include_invalid_declaration) const;
std::string getVertexShaderBody(bool include_invalid_declaration) const;
/* Private fields */
glw::GLuint m_fs_id;
glw::GLuint m_gs_id;
bool m_has_test_passed;
glw::GLuint m_po_id;
glw::GLuint m_tc_id;
glw::GLuint m_te_id;
glw::GLuint m_vs_id;
};
/**
* Make sure that it is not possible to assign float/int to subroutine
* uniform and that subroutine uniform values cannot be compared.
*
**/
class NegativeTest9 : public deqp::TestCase
{
public:
/* Public methods */
NegativeTest9(deqp::Context& context);
virtual void deinit();
virtual tcu::TestNode::IterateResult iterate();
private:
/* Private type definitions */
enum _test_case
{
TEST_CASE_FIRST,
TEST_CASE_INVALID_FLOAT_TO_SUBROUTINE_UNIFORM_ASSIGNMENT = TEST_CASE_FIRST,
TEST_CASE_INVALID_INT_TO_SUBROUTINE_UNIFORM_ASSIGNMENT,
TEST_CASE_INVALID_SUBROUTINE_UNIFORM_VALUE_COMPARISON,
/* Always last */
TEST_CASE_COUNT
};
/* Private methods */
std::string getTestCaseString(const _test_case& test_case);
std::string getVertexShader(const _test_case& test_case);
/* Private fields */
bool m_has_test_passed;
glw::GLuint m_po_id;
glw::GLuint m_vs_id;
};
/**
* Check that an overloaded function cannot be declared with subroutine and
* a program will fail to compile or link if any shader or stage contains
* two or more functions with the same name if the name is associated with
* a subroutine type.
*
**/
class NegativeTest10 : public deqp::TestCase
{
public:
/* Public methods */
NegativeTest10(deqp::Context& context);
virtual void deinit();
virtual tcu::TestNode::IterateResult iterate();
private:
/* Private type definitions */
struct _test_case
{
std::string name;
std::string fs_body;
std::string gs_body;
std::string tc_body;
std::string te_body;
std::string vs_body;
};
typedef std::vector<_test_case> _test_cases;
typedef _test_cases::const_iterator _test_cases_const_iterator;
/* Private methods */
std::string getFragmentShader(bool include_duplicate_function);
std::string getGeometryShader(bool include_duplicate_function);
std::string getTessellationControlShader(bool include_duplicate_function);
std::string getTessellationEvaluationShader(bool include_duplicate_function);
std::string getVertexShader(bool include_duplicate_function);
void initTestCases();
/* Private fields */
bool m_has_test_passed;
glw::GLuint m_fs_id;
glw::GLuint m_gs_id;
glw::GLuint m_po_id;
glw::GLuint m_tc_id;
glw::GLuint m_te_id;
_test_cases m_test_cases;
glw::GLuint m_vs_id;
};
/**
* Try to use subroutine uniform in invalid way in sampling, atomic and
* image functions. Verify that compile or link time error occurs.
*
**/
class NegativeTest11 : public deqp::TestCase
{
public:
/* Public methods */
NegativeTest11(deqp::Context& context);
virtual void deinit();
virtual tcu::TestNode::IterateResult iterate();
private:
/* Private type definitions */
enum _test_case
{
TEST_CASE_FIRST,
TEST_CASE_INVALID_TEXTURE_SAMPLING_ATTEMPT = TEST_CASE_FIRST,
TEST_CASE_INVALID_ATOMIC_COUNTER_USAGE_ATTEMPT,
TEST_CASE_INVALID_IMAGE_FUNCTION_USAGE_ATTEMPT,
/* Always last */
TEST_CASE_COUNT
};
/* Private methods */
std::string getTestCaseString(const _test_case& test_case);
std::string getVertexShader(const _test_case& test_case);
/* Private fields */
bool m_has_test_passed;
glw::GLuint m_po_id;
glw::GLuint m_vs_id;
};
/**
* Verify that it is not allowed to use subroutine type for local/global
* variables, constructors or argument/return type.
*
**/
class NegativeTest12 : public deqp::TestCase
{
public:
/* Public methods */
NegativeTest12(deqp::Context& context);
virtual void deinit();
virtual tcu::TestNode::IterateResult iterate();
private:
/* Private type definitions */
enum _test_case
{
TEST_CASE_FIRST,
TEST_CASE_INVALID_LOCAL_SUBROUTINE_VARIABLE = TEST_CASE_FIRST,
TEST_CASE_INVALID_GLOBAL_SUBROUTINE_VARIABLE,
TEST_CASE_SUBROUTINE_USED_AS_CONSTRUCTOR,
TEST_CASE_SUBROUTINE_USED_AS_CONSTRUCTOR_ARGUMENT,
TEST_CASE_SUBROUTINE_USED_AS_CONSTRUCTOR_RETURN_TYPE,
/* Always last */
TEST_CASE_COUNT
};
/* Private methods */
std::string getTestCaseString(const _test_case& test_case);
std::string getVertexShader(const _test_case& test_case);
/* Private fields */
bool m_has_test_passed;
glw::GLuint m_po_id;
glw::GLuint m_vs_id;
};
} /* ShaderSubroutine */
/** Group class for Shader Subroutine conformance tests */
class ShaderSubroutineTests : public deqp::TestCaseGroup
{
public:
/* Public methods */
ShaderSubroutineTests(deqp::Context& context);
virtual ~ShaderSubroutineTests()
{
}
virtual void init(void);
private:
/* Private methods */
ShaderSubroutineTests(const ShaderSubroutineTests&);
ShaderSubroutineTests& operator=(const ShaderSubroutineTests&);
};
} /* gl4cts namespace */
#endif // _GL4CSHADERSUBROUTINETESTS_HPP