#ifndef _GL3CTRANSFORMFEEDBACKTESTS_HPP #define _GL3CTRANSFORMFEEDBACKTESTS_HPP /*------------------------------------------------------------------------- * OpenGL Conformance Test Suite * ----------------------------- * * Copyright (c) 2015-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 gl3cTransformFeedback.hpp * \brief Transform Feedback Test Suite Interface */ /*-------------------------------------------------------------------*/ #include "glcTestCase.hpp" #include "glwDefs.hpp" #include "tcuDefs.hpp" /* Includes. */ #include #include #include #include #include "glwEnums.hpp" #include "glwFunctions.hpp" namespace gl3cts { namespace TransformFeedback { class Tests : public deqp::TestCaseGroup { public: Tests(deqp::Context& context); ~Tests(void); virtual void init(void); private: Tests(const Tests& other); Tests& operator=(const Tests& other); }; /** APIErrors * * Verifies if errors are generated as specified. * Four test shall be run: * - Test api errors defined in GL_EXT_transform_feedback. * - Test api errors defined in GL_ARB_transform_feedback2. * - Test api errors defined in GL_ARB_transform_feedback3. * - Test api errors defined in GL_ARB_transform_feedback_instanced. */ class APIErrors : public deqp::TestCase { public: APIErrors(deqp::Context& context); ~APIErrors(void); IterateResult iterate(void); private: deqp::Context& m_context; static const glw::GLchar* m_tessellation_control_shader; static const glw::GLchar* m_tessellation_evaluation_shader; static const glw::GLchar* m_geometry_shader; static const glw::GLchar* s_vertex_shader_with_input_output; static const glw::GLchar* s_vertex_shader_with_output; static const glw::GLchar* s_vertex_shader_without_output; static const glw::GLchar* s_fragment_shader; static const glw::GLchar* m_varying_name; static const glw::GLfloat m_buffer_1_data[]; static const glw::GLsizei m_buffer_1_size; glw::GLuint m_buffer_0; glw::GLuint m_buffer_1; glw::GLuint m_vertex_array_object; glw::GLuint m_transform_feedback_object_0; glw::GLuint m_transform_feedback_object_1; glw::GLuint m_query_object; glw::GLuint m_program_id_with_input_output; glw::GLuint m_program_id_with_output; glw::GLuint m_program_id_without_output; glw::GLuint m_program_id_with_geometry_shader; glw::GLuint m_program_id_with_tessellation_shaders; /** Check the following if EXT_transform_feedback is supported or context is * at least 3.0: * * - INVALID_VALUE is generated by BindBufferRange, BindBufferOffset and * BindBufferBase when is greater or equal to * MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS; * - INVALID_VALUE is generated by BindBufferRange and BindBufferOffset * when is less or equal to zero; * - INVALID_VALUE is generated by BindBufferRange and BindBufferOffset * when is not word-aligned; * - INVALID_VALUE is generated by BindBufferRange and BindBufferOffset * when is not word-aligned; * - INVALID_OPERATION is generated by BindBufferRange, BindBufferOffset and * BindBufferBase when is TRANSFORM_FEEDBACK_BUFFER and transform * feedback is active; * - INVALID_OPERATION is generated by UseProgram when transform feedback is * active; * - INVALID_OPERATION is generated by LinkProgram when is currently * active and transform feedback is active; * - INVALID_OPERATION is generated by BeginTransformFeedback when transform * feedback is active; * - INVALID_OPERATION is generated by EndTransformFeedback when transform * feedback is inactive; * - INVALID_OPERATION is generated by draw command when generated primitives * type does not match ; * - INVALID_OPERATION is generated by BeginTransformFeedback when any binding * point used by XFB does not have buffer bound; * - INVALID_OPERATION is generated by BeginTransformFeedback when no program * is active; * - INVALID_OPERATION is generated by BeginTransformFeedback when no variable * are specified to be captured in the active program; * - INVALID_VALUE is generated by TransformFeedbackVaryings when is * not id of the program object; * - INVALID_VALUE is generated by TransformFeedbackVaryings when * is SEPARATE_ATTRIBS and is exceeds limits; * - IVALID_VALUE is generated by GetTransformFeedbackVarying when is * greater than or equal to TRANSFORM_FEEDBACK_VARYINGS; * - INVALID_VALUE is generated by GetIntegerIndexdv when exceeds the * limits of MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS and is one of the * following: * * TRANSFORM_FEEDBACK_BUFFER_BINDING, * * TRANSFORM_FEEDBACK_BUFFER_START, * * TRANSFORM_FEEDBACK_BUFFER_SIZE; * - INVALID_VALUE is generated by GetBooleanIndexedv when exceeds the * limits of MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS and is * TRANSFORM_FEEDBACK_BUFFER_BINDING. */ bool testExtension1(void); /** Check the following if ARB_transform_feedback2 is supported or context is * at least 4.0: * * - INVALID_OPERATION is generated by BindTransformFeedback if current * transform feedback is active and not paused; * - INVALID_OPERATION is generated by DeleteTransformFeedbacks if any of * is active; * - INVALID_OPERATION is generated by PauseTransformFeedback if current * transform feedback is not active or paused; * - INVALID_OPERATION is generated by ResumeTransformFeedback if current * transform feedback is not active or not paused; * - No error is generated by draw command when transform feedback is paused * and primitive modes do not match; * - No error is generated by UseProgram when transform feedback is paused; * - INVALID_OPERATION is generated by LinkProgram when is used by * some transform feedback object that is currently not active; * - INVALID_VALUE is generated by DrawTransformFeedback if is not name of * transform feedback object; * - INVALID_OPERATION is generated by DrawTransformFeedback when * EndTransformFeedback was never called for the object named . */ bool testExtension2(void); /** Check the following if ARB_transform_feedback3 is supported or context is * at least 4.0: * * - INVALID_VALUE is generated by BeginQueryIndexed, EndQueryIndexed and * GetQueryIndexediv when is TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN and * exceeds limits of MAX_VERTEX_STREAMS; * - INVALID_VALUE is generated by BeginQueryIndexed, EndQueryIndexed and * GetQueryIndexediv when is PRIMITIVES_GENERATED and exceeds * limits of MAX_VERTEX_STREAMS; * - INVALID_OPERATION is generated by EndQueryIndexed when name of active * query at of is zero; * - INVALID_VALUE is generated by DrawTransformFeedbackStream when * exceeds limits of MAX_VERTEX_STREAMS; * - INVALID_OPERATION is generated by TransformFeedbackVaryings when * contains any of the special names while is not * INTERLEAVED_ATTRIBS; * - INVALID_OPERATION is generated by TransformFeedbackVaryings when * contains more "gl_NextBuffer" entries than allowed limit of * MAX_TRANSFORM_FEEDBACK_BUFFERS; */ bool testExtension3(void); /** Check the following if ARB_transform_feedback_instanced is supported or * context is at least 4.2: * * - INVALID_ENUM is generated by DrawTransformFeedbackInstanced and * DrawTransformFeedbackStreamInstanced if is invalid; * - INVALID_OPERATION is generated by DrawTransformFeedbackInstanced and * DrawTransformFeedbackStreamInstanced if does not match geometry * shader; * - INVALID_OPERATION is generated by DrawTransformFeedbackInstanced and * DrawTransformFeedbackStreamInstanced if does not match tessellation; * - INVALID_VALUE is generated by DrawTransformFeedbackStreamInstanced if * is greater than or equal to MAX_VERTEX_STREAMS; * - INVALID_VALUE is generated by DrawTransformFeedbackInstanced and * DrawTransformFeedbackStreamInstanced if is not name of transform * feedback object; * - INVALID_OPERATION is generated by DrawTransformFeedbackInstanced and * DrawTransformFeedbackStreamInstanced if a non-zero buffer object name is * bound to an enabled array and the buffer object's data store is currently * mapped; * - INVALID_OPERATION is generated if by DrawTransformFeedbackStreamInstanced * if EndTransformFeedback was never called for the object named . */ bool testInstanced(void); typedef GLW_APICALL void (GLW_APIENTRY *BindBufferOffsetEXT_ProcAddress)(glw::GLenum target, glw::GLuint index, glw::GLuint buffer, glw::GLintptr offset); typedef GLW_APICALL void (GLW_APIENTRY *GetIntegerIndexedvEXT_ProcAddress)(glw::GLenum param, glw::GLuint index, glw::GLint* values); typedef GLW_APICALL void (GLW_APIENTRY *GetBooleanIndexedvEXT_ProcAddress)(glw::GLenum param, glw::GLuint index, glw::GLboolean* values); BindBufferOffsetEXT_ProcAddress m_glBindBufferOffsetEXT; GetIntegerIndexedvEXT_ProcAddress m_glGetIntegerIndexedvEXT; GetBooleanIndexedvEXT_ProcAddress m_glGetBooleanIndexedvEXT; }; /** LinkingErrors * * Verifies that linker reports errors as specified. * * Test should be run if EXT_transform_feedback is supported or context is * at least 3.0. * * Check if link process fails under the following conditions: * - specified by TransformFeedbackVaryings is non-zero and program has * neither vertex nor geometry shader; * - specified by TransformFeedbackVaryings contains name of * variable that is not available for capture; * - specified by TransformFeedbackVaryings contains name of * variable more than once; * - number of components specified to capture exceeds limits * MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS or * MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS. */ class LinkingErrors : public deqp::TestCase { public: LinkingErrors(deqp::Context& context); ~LinkingErrors(void); IterateResult iterate(void); private: deqp::Context& m_context; static const glw::GLchar* s_fragment_shader; static const glw::GLchar* s_vertex_shader_template; static const glw::GLchar* s_valid_transform_feedback_varying; static const glw::GLchar* s_invalid_transform_feedback_varying; static const glw::GLchar* s_repeated_transform_feedback_varying[]; static const glw::GLsizei s_repeated_transform_feedback_varying_count; bool testNoVertexNoGeometry(void); bool testInvalidVarying(void); bool testRepeatedVarying(void); bool testTooManyVaryings(void); }; /** Limits * * Verifies that limits reported by API are as expected. * * Check the following if EXT_transform_feedback is supported or context is at * least 3.0: * - MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS is at least 64, * - MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS is at least 4, * - MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS is at least 4. * * Check the following if ARB_transform_feedback3 is supported or context is at * least 4.0: * - MAX_TRANSFORM_FEEDBACK_BUFFERS is at least 4, * - MAX_VERTEX_STREAMS is at least 1. */ class Limits : public deqp::TestCase { public: Limits(deqp::Context& context); ~Limits(void); IterateResult iterate(void); private: deqp::Context& m_context; static const glw::GLchar* s_fragment_shader; static const glw::GLchar* s_vertex_shader; static const glw::GLint s_min_value_of_max_transform_feedback_interleaved_components; static const glw::GLint s_min_value_of_max_transform_feedback_separate_attribs; static const glw::GLint s_min_value_of_max_transform_feedback_separate_components; static const glw::GLint s_min_value_of_max_transform_feedback_buffers; static const glw::GLint s_min_value_of_max_vertex_streams; bool test_max_transform_feedback_interleaved_components(void); bool test_max_transform_feedback_separate_attribs(void); bool test_max_transform_feedback_separate_components(void); bool test_max_transform_feedback_buffers(void); bool test_max_vertex_streams(void); }; /** CaptureVertexInterleaved * * Verifies if geometry processed with vertex shader is captured as expected in * interleaved mode. * * Test should be run if EXT_transform_feedback is supported or context is * at least 3.0. * * Steps: * - prepare program consisting of vertex and fragment shader; Vertex shader * should assign all MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS components; * One of the variables must be a position; Position should be set to one of * corners, based on gl_VertexID: 0 - top left, 1 - top right, 2 - bottom left * and 3 - bottom right; Rest of components should be covered with output * variables of type vec4; Fragment shader should accept all outputs from * vertex shader as inputs and use them to calculate non-black output color; * - instruct implementation to capture all outputs defined by vertex shader; * Use interleaved mode; * - prepare and set buffer to store captured geometry; * - prepare, set and clean frame-buffer with black color; * - execute BeginTransformFeedback; * - execute DrawElements; * - execute EndTransformFeedback; * - inspect contents of frame-buffer to check if rasterization was done * correctly; * - inspect TRANSFORM_FEEDBACK_BUFFER_START and * TRANSFORM_FEEDBACK_BUFFER_SIZE; * - inspect contents of the buffer to check if geometry was captured * correctly. * * Test the following BindBuffer routines: * - BindBufferRange - use non-zero offset, * - BindBufferOffset - use non-zero offset, * - BindBufferBase. * * Test the following primitive types: * - GL_POINTS - use these indices: [0, 1, 2, 3]; All corner pixels should be * set to specific colors; XFB should contain four vertices; * - GL_LINES - use these indices: [0, 1, 2, 3]; Top and bottom edges should be * drawn; XFB should contain four vertices; * - GL_LINE_LOOP - use these indices: [0, 1, 3, 2]; All four edges should be * drawn; XFB should contain eight vertices; * - GL_LINE_STRIP - use these indices: [0, 1, 3, 2]; Top, right and bottom * edge should be drawn; XFB should contain six vertices; * - GL_TRIANGLES - use these indices: [2, 0, 1, 2, 1, 3]; Whole image should * be drawn; XFB should contain six vertices; * - GL_TRIANGLE_STRIP - use these indices: [0, 1, 2, 3]; Whole image should * be drawn; XFB should contain six vertices; * - GL_TRIANGLE_FAN - use these indices: [2, 0, 1, 3]; Whole image should * be drawn; XFB should contain six vertices. * * Number of components that can be passed to rasterization must not exceed * MAX_VARYING_COMPONENTS. */ class CaptureVertexInterleaved : public deqp::TestCase { public: CaptureVertexInterleaved(deqp::Context& context, const char* test_name, const char* test_description); ~CaptureVertexInterleaved(void); virtual IterateResult iterate(void); protected: deqp::Context& m_context; glw::GLuint m_program; glw::GLuint m_framebuffer; glw::GLuint m_renderbuffer; glw::GLuint m_buffer; glw::GLuint m_buffer_size; glw::GLuint m_vertex_array_object; glw::GLint m_max_transform_feedback_components; glw::GLenum m_attrib_type; glw::GLuint m_max_vertices_drawn; typedef GLW_APICALL void (GLW_APIENTRY *BindBufferOffsetEXT_ProcAddress)(glw::GLenum target, glw::GLuint index, glw::GLuint buffer, glw::GLintptr offset); BindBufferOffsetEXT_ProcAddress m_glBindBufferOffsetEXT; static const glw::GLchar* s_vertex_shader_source_code_template; static const glw::GLchar* s_fragment_shader_source_code; static const glw::GLuint s_max_element_indices_count = 6; static const glw::GLuint s_element_indices[][s_max_element_indices_count]; static const glw::GLuint s_primitive_cases_count; static const glw::GLuint s_element_indices_counts[]; static const glw::GLenum s_primitive_cases[]; static const glw::GLenum s_primitive_cases_xfb[]; static const glw::GLuint s_framebuffer_size; static const glw::GLfloat s_rasterization_epsilon; static const glw::GLuint s_max_vertex_id = 4; enum BindBufferCase { BIND_BUFFER_BASE_CASE, BIND_BUFFER_RANGE_CASE, BIND_BUFFER_OFFSET_CASE, BIND_BUFFER_CASES_COUNT }; virtual void fetchLimits(void); virtual void buildProgram(void); void createFramebuffer(void); virtual void createTransformFeedbackBuffer(void); void createVertexArrayObject(void); virtual void draw(glw::GLuint primitive_case); virtual bool checkFramebuffer(glw::GLuint primitive_case); virtual bool checkTransformFeedbackBuffer(BindBufferCase bind_case, glw::GLenum primitive_type); virtual void bindBuffer(BindBufferCase bind_case); virtual void clean(void); virtual void cleanBuffer(void); }; /** CaptureGeometryInterleaved * * Verifies if geometry processed with geometry shader is captured as expected * in interleaved mode. * * Test should be run if either EXT_transform_feedback is supported or context * is at least 3.0 and either ARB_geometry_shader4 is supported or context is * at least 3.2. * * Modify CaptureVertexInterleaved test in the following aspects: * - outputs definition and assignment is done in geometry instead of * vertex shader; * - vertex shader can be blank; * - use DrawArrays instead of DrawElements, draw single vertex with GL_POINTS. * * Test the following output primitive types for geometry shader: * - points - emit vertices as in GL_POINTS case; * - line_strip - emit vertices as in GL_LINE_STRIP case; * - triangle_strip - emit vertices as in GL_TRIANGLE_STRIP case. * * Number of components written by geometry shader must not exceed * MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS. */ class CaptureGeometryInterleaved : virtual public CaptureVertexInterleaved { public: CaptureGeometryInterleaved(deqp::Context& context, const char* test_name, const char* test_description); ~CaptureGeometryInterleaved(void); virtual IterateResult iterate(void); protected: virtual void fetchLimits(void); using CaptureVertexInterleaved::buildProgram; virtual void buildProgram(glw::GLuint primitive_case); virtual void draw(glw::GLuint primitive_case); static const glw::GLchar* s_geometry_shader_source_code_template; static const glw::GLchar* s_blank_vertex_shader_source_code; static const glw::GLchar* s_geometry_interleaved_primitive_cases[]; static const glw::GLenum s_geometry_interleaved_primitive_cases_xfb[]; static const glw::GLuint s_geometry_interleaved_primitive_cases_count; }; /** CaptureVertexSeparate * * Verifies if geometry processed with vertex shader is captured as expected in * separate mode. * * Test should be run if EXT_transform_feedback is supported or context is * at least 3.0. * * Modify CaptureVertexInterleaved test in the following aspects: * - use transform feedback in separate mode. * * Separate mode require one buffer per captured variable. * * Number of attributes and components that can be captured is limited by: * - MAX TRANSFORM FEEDBACK SEPARATE ATTRIBS, * - MAX TRANSFORM FEEDBACK SEPARATE COMPONENTS. */ class CaptureVertexSeparate : virtual public CaptureVertexInterleaved { public: CaptureVertexSeparate(deqp::Context& context, const char* test_name, const char* test_description); protected: glw::GLuint* m_buffers; glw::GLint m_max_transform_feedback_separate_attribs; virtual void fetchLimits(void); virtual void createTransformFeedbackBuffer(void); virtual void bindBuffer(BindBufferCase bind_case); virtual void cleanBuffer(void); virtual bool checkTransformFeedbackBuffer(BindBufferCase bind_case, glw::GLenum primitive_type); }; /** CaptureGeometrySeparate * * Verifies if geometry processed with geometry shader is captured as expected * in separate mode. * * Test should be run if either EXT_transform_feedback is supported or context * is at least 3.0 and either ARB_geometry_shader4 is supported or context is * at least 3.2. * * Modify CaptureGeometryInterleaved test in the following aspects: * - use transform feedback in separate mode. * * Separate mode require one buffer per captured variable. * * Number of attributes and components that can be captured is limited by: * - MAX TRANSFORM FEEDBACK SEPARATE ATTRIBS, * - MAX TRANSFORM FEEDBACK SEPARATE COMPONENTS. */ class CaptureGeometrySeparate : public CaptureGeometryInterleaved, virtual public CaptureVertexSeparate { public: CaptureGeometrySeparate(deqp::Context& context, const char* test_name, const char* test_description); virtual IterateResult iterate(void) { return CaptureGeometryInterleaved::iterate(); } protected: glw::GLuint* m_buffers; glw::GLint m_max_transform_feedback_separate_attribs; virtual void draw(glw::GLenum primitive_type) { CaptureGeometryInterleaved::draw(primitive_type); } virtual void fetchLimits(void) { CaptureVertexSeparate::fetchLimits(); } virtual void createTransformFeedbackBuffer(void) { CaptureVertexSeparate::createTransformFeedbackBuffer(); } virtual void bindBuffer(BindBufferCase bind_case) { CaptureVertexSeparate::bindBuffer(bind_case); } virtual void cleanBuffer(void) { CaptureVertexSeparate::cleanBuffer(); } virtual bool checkTransformFeedbackBuffer(BindBufferCase bind_case, glw::GLenum primitive_type) { return CaptureVertexSeparate::checkTransformFeedbackBuffer(bind_case, primitive_type); } }; /** GetXFBVaryingVertexInterleaved * * Verifies if varyings captured from vertex stage are correctly reported in * interleaved mode. * * Test should be run if EXT_transform_feedback is supported or context is * at least 3.0. * * Steps: * - prepare program consisting of vertex and fragment shader; Vertex shader * should define and assign maximum allowed number of varyings of tested type; * Fragment shader can be blank; * - instruct implementation to capture all outputs defined by vertex shader; * Use interleaved mode; * - inspect all captured varying with GetTransformFeedbackVarying; * - inspect TRANSFORM_FEEDBACK_VARYINGS; * - inspect TRANSFORM_FEEDBACK_BUFFER_MODE; * - inspect TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH. * * Test all valid types. * * * GetXFBVaryingGeometryInterleaved * * Verifies if varyings captured from geometry stage are correctly reported in * interleaved mode. * * Test should be run if either EXT_transform_feedback is supported or context * is at least 3.0 and either ARB_geometry_shader4 is supported or context is * at least 3.2. * * Modify GetXFBVaryingVertexInterleaved test in the following aspects: * - outputs definition and assignment is done in geometry instead of * vertex shader; * - vertex shader can be blank; * * * GetXFBVaryingVertexSeparate * * Verifies if varyings captured from vertex stage are correctly reported in * separate mode. * * Test should be run if EXT_transform_feedback is supported or context is * at least 3.0. * * Modify CaptureGeometryInterleaved test in the following aspects: * - use transform feedback in separate mode. * * Separate mode require one buffer per captured variable. * * * GetXFBVaryingGeometrySeparate * * Verifies if varyings captured from geometry stage are correctly reported in * separate mode. * * Test should be run if either EXT_transform_feedback is supported or context * is at least 3.0 and either ARB_geometry_shader4 is supported or context is * at least 3.2. * * Modify GetXFBVaryingGeometryInterleaved test in the following aspects: * - use transform feedback in separate mode. * * Separate mode require one buffer per captured variable. */ class CheckGetXFBVarying : public deqp::TestCase { public: CheckGetXFBVarying(deqp::Context& context, const char* test_name, const char* test_description); ~CheckGetXFBVarying(void); virtual IterateResult iterate(void); private: deqp::Context& m_context; glw::GLint m_max_xfb_interleaved_components; glw::GLint m_max_xfb_separate_attributes; glw::GLint m_max_xfb_separate_components; glw::GLint m_max_varying_components; glw::GLint m_max_varying_vectors; glw::GLint m_max_geometry_total_output_components; void fetchLimits(void); glw::GLuint numberOfAttributes(glw::GLuint capture_way, glw::GLuint shader_case, glw::GLuint varying_type); glw::GLuint buildProgram(glw::GLuint capture_way, glw::GLuint shader_case, glw::GLuint varying_type, glw::GLuint number_of_attributes); bool check(glw::GLuint program, glw::GLuint capture_way, glw::GLuint shader_case, glw::GLuint varying_type, glw::GLuint number_of_attributes); static const glw::GLchar* s_generic_fragment_shader; static const struct ShaderCase { const glw::GLchar* vertex_shader; const glw::GLchar* geometry_shader; } s_shader_cases[]; static const glw::GLuint s_shader_cases_count; static const struct VaryingType { const glw::GLenum type; const glw::GLchar* name; const glw::GLuint components_count; const bool float_component; } s_varying_types[]; static const glw::GLuint s_varying_types_count; static const glw::GLenum s_capture_ways[]; static const glw::GLuint s_capture_ways_count; }; /** QueryVertexInterleaved * * Verifies if queries are performed as expected when geometry is captured from * vertex stage in interleaved mode. * * Test should be run if EXT_transform_feedback is supported or context is * at least 3.0. * * Modify CaptureVertexInterleaved test in the following aspects: * - buffer used as storage for captured geometry should be too small to fit * all emitted vertices; * - execute BeginQuery for PRIMITIVES_GENERATED and * TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN before draw is executed; End queries * after draw call. * * Test pass if results of queries are correct. */ class QueryVertexInterleaved : public CaptureVertexInterleaved { public: QueryVertexInterleaved(deqp::Context& context, const char* test_name, const char* test_description); protected: glw::GLuint m_query_object; virtual void createTransformFeedbackBuffer(void); virtual void draw(glw::GLuint primitive_case); virtual bool checkTransformFeedbackBuffer(BindBufferCase bind_case, glw::GLenum primitive_type); virtual void clean(void); }; /** QueryGeometryInterleaved * * Verifies if queries are performed as expected when geometry is captured from * geometry stage in interleaved mode. * * Test should be run if either EXT_transform_feedback is supported or context * is at least 3.0 and either ARB_geometry_shader4 is supported or context is * at least 3.2. * * Modify CaptureGeometryInterleaved test in the following aspects: * - buffer used as storage for captured geometry should be too small to fit * all emitted vertices; * - execute BeginQuery for PRIMITIVES_GENERATED and * TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN before draw is executed; End queries * after draw call. * * Test pass if results of queries are correct. */ class QueryGeometryInterleaved : public CaptureGeometryInterleaved { public: QueryGeometryInterleaved(deqp::Context& context, const char* test_name, const char* test_description); protected: glw::GLuint m_query_object; virtual void createTransformFeedbackBuffer(void); virtual void draw(glw::GLuint primitive_case); virtual bool checkTransformFeedbackBuffer(BindBufferCase bind_case, glw::GLenum primitive_type); virtual void clean(void); }; /** QueryVertexSeparate * * Verifies if queries are performed as expected when geometry is captured from * vertex stage in separate mode. * * Test should be run if EXT_transform_feedback is supported or context is * at least 3.0. * * Modify CaptureVertexSeparate test in the following aspects: * - buffers used as storage for captured geometry should be too small to fit * all emitted vertices; * - execute BeginQuery for PRIMITIVES_GENERATED and * TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN before draw is executed; End queries * after draw call; * - use transform feedback in separate mode. * * Separate mode require one buffer per captured variable. * * Test pass if results of queries are correct. */ class QueryVertexSeparate : public CaptureVertexSeparate { public: QueryVertexSeparate(deqp::Context& context, const char* test_name, const char* test_description); protected: glw::GLuint m_query_object; virtual void createTransformFeedbackBuffer(void); virtual void draw(glw::GLuint primitive_case); virtual bool checkTransformFeedbackBuffer(BindBufferCase bind_case, glw::GLenum primitive_type); virtual void clean(void); }; /** QueryGeometrySeparate * * Verifies if queries are performed as expected when geometry is captured from * geometry stage in separate mode. * * Test should be run if either EXT_transform_feedback is supported or context * is at least 3.0 and either ARB_geometry_shader4 is supported or context is * at least 3.2. * * Modify CaptureGeometrySeparate test in the following aspects: * - buffers used as storage for captured geometry should be too small to fit * all emitted vertices; * - execute BeginQuery for PRIMITIVES_GENERATED and * TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN before draw is executed; End queries * after draw call; * - use transform feedback in separate mode. * * Separate mode require one buffer per captured variable. * * Test pass if results of queries are correct. */ class QueryGeometrySeparate : public CaptureGeometrySeparate { public: QueryGeometrySeparate(deqp::Context& context, const char* test_name, const char* test_description); protected: glw::GLuint m_query_object; virtual void createTransformFeedbackBuffer(void); virtual void draw(glw::GLuint primitive_case); virtual bool checkTransformFeedbackBuffer(BindBufferCase bind_case, glw::GLenum primitive_type); virtual void clean(void); }; /** DiscardVertex * * Verifies if rasterization is discarded when geometry is captured from vertex * stage. * * Test should be run if EXT_transform_feedback is supported or context is * at least 3.0. * * Modify CaptureVertexInterleaved test in the following aspects: * - disable rasterization before draw call; * - it is expected that framebuffer contents will not change, while XFB buffer * is modified. */ class DiscardVertex : public CaptureVertexInterleaved { public: DiscardVertex(deqp::Context& context, const char* test_name, const char* test_description); protected: virtual void draw(glw::GLuint primitive_case); virtual bool checkFramebuffer(glw::GLuint primitive_case); }; /** DiscardGeometry * * Verifies if rasterization is discarded when geometry is captured from * geometry stage. * * Test should be run if EXT_transform_feedback is supported or context is at least 3.0. * Test should be run if ARB_geometry_shader4 is supported or context is at least 3.2. * * Modify CaptureGeometryInterleaved test in the following aspects: * - disable rasterization before draw call; * - it is expected that framebuffer contents will not change, while XFB buffer * is modified. */ class DiscardGeometry : public CaptureGeometryInterleaved { public: DiscardGeometry(deqp::Context& context, const char* test_name, const char* test_description); protected: virtual void draw(glw::GLuint primitive_case); virtual bool checkFramebuffer(glw::GLuint primitive_case); }; /** DrawXFB * * Verifies that transform feedback objects can be used to draw. * * Test should be executed if ARB_transform_feedback2 is supported or context * is at least 4.0. * * Steps: * - prepare two programs consisting of vertex shader which will: * * output position based on gl_VertexID: * * output color by passing value of uniform; * First program should use the following positions: * ID | X | Y * 0 | -1 | -1 * 1 | -1 | 1 * 2 | 1 | 1 * Second program should use the following positions: * 0 | -1 | -1 * 1 | 1 | 1 * 2 | 1 | -1 * - prepare three XFB objects and corresponding buffers for captured geometry; * Each XFB should capture position and color from both programs; * - activate first program; * - for each XFB object: * * set uniform to color corresponding with XFB; * * activate XFB; * * execute DrawArrays to draw three points starting at 0; * * pause XFB; * - inspect TRANSFORM_FEEDBACK_BUFFER_PAUSED and * TRANSFORM_FEEDBACK_BUFFER_ACTIVE; * - activate second program; * - for each XFB object: * * set uniform to color corresponding with XFB; * * resume XFB; * * execute DrawArrays to draw three points starting at 0; * * end XFB; * - inspect TRANSFORM_FEEDBACK_BUFFER_PAUSED and * TRANSFORM_FEEDBACK_BUFFER_ACTIVE; * - prepare program consisting of vertex and fragment stage; Vertex shader * should pass position and color; Fragment stage should pass color; * - set program; * - set vertex array to match layout of XFB; * - for each XFB: * * prepare and clean framebuffer; * * execute DrawTransformFeedback to draw triangles; * * inspect contents of framebuffer; * * It is expected that drawn images will be filled with color set via uniform * variables. * * Repeat steps for both interleaved and separate modes. */ class DrawXFB : public deqp::TestCase { public: DrawXFB(deqp::Context& context, const char* test_name, const char* test_description); ~DrawXFB(void); virtual IterateResult iterate(void); protected: static const glw::GLchar* s_vertex_shader_xfb; static const glw::GLchar* s_vertex_shader_draw; static const glw::GLchar* s_fragment_shader; static const glw::GLuint s_xfb_varyings_count = 2; static const glw::GLchar* s_xfb_varyings[s_xfb_varyings_count]; static const glw::GLuint s_vertex_count = 3; static const glw::GLenum s_capture_modes[]; static const glw::GLuint s_capture_modes_count; static const glw::GLuint s_capture_size = s_vertex_count * sizeof(glw::GLfloat) * 4 /* number of components */ * s_xfb_varyings_count * 2 /* number of programs */; static const glw::GLuint s_view_size = 2; static const glw::GLuint s_xfb_count = 3; static const glw::GLfloat s_colours[s_xfb_count][4]; deqp::Context& m_context; glw::GLuint m_program_id_xfb; glw::GLuint m_program_id_draw; glw::GLuint m_xfb_id[s_xfb_count]; glw::GLuint m_bo_id[s_xfb_count]; glw::GLuint m_fbo_id; glw::GLuint m_rbo_id; glw::GLuint m_vao_id; void prepare(glw::GLenum capture_mode); void bindXFB(glw::GLuint xfb_id); void bindVAO(glw::GLuint vao_id); void bindBOForXFB(glw::GLenum capture_mode, glw::GLuint bo_id); void bindBOForDraw(glw::GLuint program_id, glw::GLenum capture_mode, glw::GLuint bo_id); void useProgram(glw::GLuint program_id); void useColour(glw::GLuint program_id, glw::GLfloat r, glw::GLfloat g, glw::GLfloat b, glw::GLfloat a); void useGeometrySet(glw::GLuint program_id, bool invert_sign); void drawForCapture(bool begin_xfb, bool pause_xfb, bool resume_xfb, bool end_xfb); void drawToFramebuffer(glw::GLuint xfb_id); bool checkFramebuffer(glw::GLfloat r, glw::GLfloat g, glw::GLfloat b, glw::GLfloat a); bool inspectXFBState(bool shall_be_paused, bool shall_be_active); void clean(); }; /** DrawXFBFeedback * * Verifies that data captured with XFB can be used as source for next capture. * * Test should be executed if ARB_transform_feedback2 is supported or context * is at least 4.0. * * Steps: * - prepare program consisting of vertex shader which pass position from input * attribute to gl_Position multiplying it by 2.0; * - instruct implementation to capture geometry in interleaved mode; * - prepare source buffer; * - prepare buffer to capture geometry; * - begin transform feedback; * - draw one vertex using DrawArrays; * - end transform feedback; * - swap buffer * - begin transform feedback; * - draw using DrawTransformFeedback; * - end transform feedback; * - swap buffer * - begin transform feedback; * - draw using DrawTransformFeedback; * - end transform feedback; * - map last captured buffer, expect position vector multiplied by value 8; */ class DrawXFBFeedback : public deqp::TestCase { public: DrawXFBFeedback(deqp::Context& context, const char* test_name, const char* test_description); ~DrawXFBFeedback(void); virtual IterateResult iterate(void); protected: static const glw::GLchar* s_vertex_shader; static const glw::GLchar* s_fragment_shader; static const glw::GLchar* s_xfb_varying; static const glw::GLchar* s_attrib; static const glw::GLuint s_draw_vertex_count; static const glw::GLfloat s_initial_data[]; static const glw::GLuint s_bo_count = 2; static const glw::GLuint s_bo_size; deqp::Context& m_context; glw::GLuint m_program_id; glw::GLuint m_vao_id[s_bo_count]; glw::GLuint m_xfb_id; glw::GLuint m_bo_id[s_bo_count]; glw::GLuint m_source_bo_index; void prepareAndBind(); void draw(bool is_first_draw); void swapBuffers(); bool check(); void clean(); }; /** DrawXFBStream * * Verifies that vertex stream captured with transform feedback can be used to * draw. * * Test should be executed if both ARB_transform_feedback3 and ARB_gpu_shader5 * are supported or context is at least 4.0. * This test is not supported if MAX_VERTEX_STREAMS is less than 2. * * Steps: * - prepare program consisting of vertex and geometry shaders; Geometry shader * should output full-screen quad made of two triangles; First triangle should * be emitted to first vertex stream; Second triangle should be emitted to the * second vertex stream; Vertex shader can be blank; * - prepare buffers to capture geometry; * - instruct implementation to capture geometry in interleaved mode; * - begin XFB; * - begin indexed query for PRIMITIVES_GENERATED and * TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN for both vertex streams; * - draw single vertex; * - end queries; * - end XFB; * - inspect results of queries; * - prepare program consisting of vertex and fragment shaders; Vertex stage * should pass position from input to output; Fragment shader should output * white color; * - prepare and clean framebuffer; * - set vertex array layout to match data captured by XFB; * - execute DrawTransformFeedbackStream to draw triangle from first stream; * - execute DrawTransformFeedbackStream to draw triangle from second stream; * - inspect contents of framebuffer, it is expected to be filled with white * color. */ class DrawXFBStream : public deqp::TestCase { public: DrawXFBStream(deqp::Context& context, const char* test_name, const char* test_description); ~DrawXFBStream(void); virtual IterateResult iterate(void); private: static const glw::GLchar* s_vertex_shader_pass; static const glw::GLchar* s_vertex_shader_blank; static const glw::GLchar* s_geometry_shader; static const glw::GLchar* s_fragment_shader; static const glw::GLchar* s_xfb_varyings[]; static const glw::GLuint s_xfb_varyings_count; static const glw::GLuint s_bo_ids_count = 2; static const glw::GLuint s_qo_ids_count = 4; static const glw::GLuint s_bo_size; static const glw::GLuint s_view_size; deqp::Context& m_context; glw::GLuint m_program_id_generate; glw::GLuint m_program_id_draw; glw::GLuint m_vao_id; glw::GLuint m_xfb_id; glw::GLuint m_bo_id[s_bo_ids_count]; glw::GLuint m_fbo_id; glw::GLuint m_rbo_id; glw::GLuint m_qo_id[s_qo_ids_count]; void prepareObjects(); void setupVertexArray(glw::GLuint bo_id); void useProgram(glw::GLuint program_id); void drawForXFB(); bool inspectQueries(); void drawForFramebuffer(glw::GLuint stream); bool check(); void clean(); }; /** CaptureSpecialInterleaved * * Verifies that special variable names are respected. * * Test should be executed if ARB_transform_feedback3 is supported or context * is at least 4.0. * * Steps: * - prepare program consisting of vertex shader which outputs four variables; * - set up XFB to capture the following : * * variable_1, * * gl_SkipComponents4, * * variable_2, * * gl_NextBuffer, * * variable_3, * * gl_SkipComponents4, * * variable_4; * - begin XFB; * - draw two vertices; * - end XFB; * - verify that captured geometry is correct. */ class CaptureSpecialInterleaved : public deqp::TestCase { public: CaptureSpecialInterleaved(deqp::Context& context, const char* test_name, const char* test_description); ~CaptureSpecialInterleaved(void); virtual IterateResult iterate(void); private: static const glw::GLchar* s_vertex_shader; static const glw::GLchar* s_fragment_shader; static const glw::GLchar* s_xfb_varyings[]; static const glw::GLuint s_xfb_varyings_count; static const glw::GLuint s_bo_ids_count = 2; static const glw::GLuint s_bo_size; deqp::Context& m_context; glw::GLuint m_program_id; glw::GLuint m_vao_id; glw::GLuint m_xfb_id; glw::GLuint m_bo_id[s_bo_ids_count]; void prepareAndBind(); void draw(); bool check(); void clean(); }; /** DrawXFBInstanced * * Verifies that transform feedback objects can used with instanced draws. * * Test should be executed if context is at least 3.1 and either * ARB_transform_feedback_instanced is supported or context is at least 4.2. * * Steps: * - prepare program consisting of vertex shader which outputs positions of * full-screen quad made of triangle strip based on gl_VertexID; * - instruct implementation to capture geometry in interleaved mode; * - prepare buffer to capture geometry; * - begin transform feedback; * - draw four vertices; * - end transform feedback; * - prepare program consisting of vertex and fragment shaders; Vertex stage * should calculate position as follows: * * gl_Position = in_position * uni_matrices[gl_InstanceID]; * * Fragment shader should output white color; * - prepare UNIFORM_BUFFER filled with four mat4; Select data so matrices * transforms quad [-1, -1] : [1, 1] as follows: * * 0 - [-1, 0] : [0, 1] - left top, * * 1 - [ 0, 0] : [1, 1] - right top, * * 2 - [-1, -1] : [0, 0] - left bottom, * * 3 - [ 0, -1] : [1, 0] - right bottom; * - prepare and clean framebuffer; * - set up layout of vertex data in XFB; * - execute DrawTransformFeedbackInstanced to draw four instances of quad from XFB; * - it is expected that framebuffer is filled with white color; */ class DrawXFBInstanced : public deqp::TestCase { public: DrawXFBInstanced(deqp::Context& context, const char* test_name, const char* test_description); ~DrawXFBInstanced(void); virtual IterateResult iterate(void); private: static const glw::GLchar* s_vertex_shader_generate; static const glw::GLchar* s_vertex_shader_draw; static const glw::GLchar* s_fragment_shader; static const glw::GLchar* s_xfb_varying; static const glw::GLchar* s_uniform; static const glw::GLuint s_bo_xfb_size; static const glw::GLfloat s_bo_uniform_data[]; static const glw::GLuint s_bo_uniform_size; static const glw::GLuint s_view_size; deqp::Context& m_context; glw::GLuint m_program_id_generate; glw::GLuint m_program_id_draw; glw::GLuint m_vao_id; glw::GLuint m_xfb_id; glw::GLuint m_bo_id_xfb; glw::GLuint m_bo_id_uniform; glw::GLuint m_fbo_id; glw::GLuint m_rbo_id; void prepareObjects(); void drawForXFB(); void drawInstanced(); bool check(); void clean(); typedef GLW_APICALL glw::GLuint (GLW_APIENTRY *GetUniformBlockIndex_ProcAddress)(glw::GLuint program, const glw::GLchar* uniformBlockName); typedef GLW_APICALL void (GLW_APIENTRY *UniformBlockBinding_ProcAddress)(glw::GLuint program, glw::GLuint uniformIndex, glw::GLuint uniformBlockBinding); GetUniformBlockIndex_ProcAddress m_glGetUniformBlockIndex; UniformBlockBinding_ProcAddress m_glUniformBlockBinding; }; /** DrawXFBStreamInstanced * * Verifies that transform feedback objects can used with instanced draws. * * Test should be executed if context is at least 3.1 and either * ARB_gpu_shader5 is supported or context is at least 4.0 and either * ARB_transform_feedback_instanced is supported or context is at least 4.2. * * Steps: * - prepare program consisting of vertex shader which based on gl_VertexID * outputs: * * to stream 0 - color, * * to stream 1 - positions * for a full-screen quad made of triangle strip; * - instruct implementation to capture geometry in interleaved mode; * - prepare buffers to capture geometry; * - begin transform feedback; * - draw four vertices; * - end transform feedback; * - prepare program consisting of vertex and fragment shaders; Vertex stage * should calculate position as follows: * * gl_Position = in_position * uni_matrices[gl_InstanceID]; * * Fragment shader should output white color; * - prepare UNIFORM_BUFFER filled with four mat4; Select data so matrices * transforms quad [-1, -1] : [1, 1] as follows: * * 0 - [-1, 0] : [0, 1] - left top, * * 1 - [ 0, 0] : [1, 1] - right top, * * 2 - [-1, -1] : [0, 0] - left bottom, * * 3 - [ 0, -1] : [1, 0] - right bottom; * - prepare and clean framebuffer; * - set up layout of vertex data in XFB; * - execute DrawTransformFeedbackStreamInstanced to draw four instances of * quad from XFB, stream 1; * - it is expected that framebuffer is filled with white color; */ class DrawXFBStreamInstanced : public deqp::TestCase { public: DrawXFBStreamInstanced(deqp::Context& context, const char* test_name, const char* test_description); ~DrawXFBStreamInstanced(void); virtual IterateResult iterate(void); private: static const glw::GLchar* s_vertex_shader_blank; static const glw::GLchar* s_geometry_shader_generate; static const glw::GLchar* s_vertex_shader_draw; static const glw::GLchar* s_fragment_shader_blank; static const glw::GLchar* s_fragment_shader_draw; static const glw::GLchar* s_xfb_varyings[]; static const glw::GLuint s_xfb_varyings_count; static const glw::GLchar* s_uniform; static const glw::GLuint s_bo_xfb_size; static const glw::GLfloat s_bo_uniform_data[]; static const glw::GLuint s_bo_uniform_size; static const glw::GLuint s_view_size; deqp::Context& m_context; glw::GLuint m_program_id_generate; glw::GLuint m_program_id_draw; glw::GLuint m_vao_id; glw::GLuint m_xfb_id; glw::GLuint m_bo_id_xfb_position; glw::GLuint m_bo_id_xfb_color; glw::GLuint m_bo_id_uniform; glw::GLuint m_fbo_id; glw::GLuint m_rbo_id; void prepareObjects(); void drawForXFB(); void drawStreamInstanced(); bool check(); void clean(); typedef GLW_APICALL glw::GLuint (GLW_APIENTRY *GetUniformBlockIndex_ProcAddress)(glw::GLuint program, const glw::GLchar* uniformBlockName); typedef GLW_APICALL void (GLW_APIENTRY *UniformBlockBinding_ProcAddress)(glw::GLuint program, glw::GLuint uniformIndex, glw::GLuint uniformBlockBinding); GetUniformBlockIndex_ProcAddress m_glGetUniformBlockIndex; UniformBlockBinding_ProcAddress m_glUniformBlockBinding; }; namespace Utilities { /** Build a GLSL program * * @param [in] gl OpenGL Functions Access. * @param [in] log Log outut. * @param [in] geometry_shader_source Pointer to C string of the geometry shader or NULL if not used. * @param [in] tessellation_control_shader_source Pointer to C string of the tessellation control shader or NULL if not used. * @param [in] tessellation_evaluation_shader_source Pointer to C string of the tessellation evaluation shader or NULL if not used. * @param [in] vertex_shader_source Pointer to C string of the vertex shader or NULL if not used. * @param [in] geometry_shader_source Pointer to C string of the fragment shader or NULL if not used. * @param [in] transform_feedback_varyings C array of transform feedback varyings names. * @param [in] transform_feedback_varyings_count Count of transform feedback varyings names. * @param [in] transform_feedback_varyings_mode Transform feedback capture mode - GL_SEPARATE_ATTRIBS or GL_INTERLEAVED_ATTRIBS. * @param [in] do_not_detach Do not detach shaders - default is faulse. * @param [out] linking_status Return pointer to store linking status or NULL if not needed. * * @return OpenGL program shader ID or zero if error had occured. */ glw::GLuint buildProgram(glw::Functions const& gl, tcu::TestLog& log, glw::GLchar const* const geometry_shader_source, glw::GLchar const* const tessellation_control_shader_source, glw::GLchar const* const tessellation_evaluation_shader_source, glw::GLchar const* const vertex_shader_source, glw::GLchar const* const fragment_shader_source, glw::GLchar const* const* const transform_feedback_varyings, glw::GLsizei const transform_feedback_varyings_count, glw::GLenum const transform_feedback_varyings_mode, bool const do_not_detach = false, glw::GLint* linking_status = DE_NULL); /** Preprocess source string by replacing key tokens with new values. * * @param [in] source Source string. * @param [in] key Key, substring to be replaced. * @param [in] value Value, substring to be substituted in place of key. * * @return Preprocessed string. */ std::string preprocessCode(std::string source, std::string key, std::string value); /** Change integer number to string * * @param [in] i Integer number. * * @return String represnting integer number. */ std::string itoa(glw::GLint i); /** Change floating point number to string * * @param [in] f Floating point number. * * @return String represnting floating point number. */ std::string ftoa(glw::GLfloat f); } /* Utilities namespace */ } /* TransformFeedback namespace */ } /* gl3cts namespace */ #endif // _GL3CTRANSFORMFEEDBACKTESTS_HPP