#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 #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& binary, glw::GLenum binary_format); void getBinary(std::vector& 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 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 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 and 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 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 input_data[3], const Utils::vec4& first_routine_result, const Utils::vec4& second_routine_result, const Utils::vec4& third_routine_result, const Utils::vec4& fourth_routine_result, const Utils::vec4& first_routine_expected_result, const Utils::vec4& second_routine_expected_result, const Utils::vec4& third_routine_expected_result, const Utils::vec4& fourth_routine_expected_result) const; void testDraw(const glw::GLuint subroutine_combination[4], const Utils::vec4 input_data[3], Utils::vec4& out_first_routine_result, Utils::vec4& out_second_routine_result, Utils::vec4& out_third_routine_result, Utils::vec4& out_fourth_routine_result) const; bool verify(const Utils::vec4& first_routine_result, const Utils::vec4& second_routine_result, const Utils::vec4& third_routine_result, const Utils::vec4& fourth_routine_result, const Utils::vec4& first_routine_expected_result, const Utils::vec4& second_routine_expected_result, const Utils::vec4& third_routine_expected_result, const Utils::vec4& 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& left, const Utils::vec4& right, Utils::vec4& out) const; void calculate(const glw::GLuint combination[4], const Utils::vec4& left, const Utils::vec4& right, const Utils::vec4& indices, Utils::vec4& out_combined, Utils::vec4& out_combined_inversed, Utils::vec4& out_constant, Utils::vec4& out_constant_inversed, Utils::vec4& out_dynamic, Utils::vec4& out_dynamic_inversed, Utils::vec4& out_loop) const; void logError(const glw::GLuint combination[4], const Utils::vec4& left, const Utils::vec4& right, const Utils::vec4& indices, const Utils::vec4 vec4_expected[7], const Utils::vec4 vec4_result[7], glw::GLuint array_length, bool result[7]) const; bool testDraw(const glw::GLuint combination[4], const Utils::vec4& left, const Utils::vec4& right, const Utils::vec4& 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& uni_input, const Utils::vec4 expected_routine_1_result[2], const Utils::vec4 expected_routine_2_result[2]) const; bool testDraw(glw::GLuint routine_configuration, const Utils::vec4& uni_input, const Utils::vec4& expected_routine_1_result, const Utils::vec4& 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