#ifndef _GL3CCLIPDISTANCE_HPP #define _GL3CCLIPDISTANCE_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 gl3cClipDistance.hpp * \brief Conformance tests for Clip Distance feature functionality. */ /*-------------------------------------------------------------------*/ #include "glcTestCase.hpp" #include "gluDefs.hpp" #include "glwDefs.hpp" #include "tcuDefs.hpp" /* Includes. */ #include #include #include #include #include "glwEnums.hpp" #include "glwFunctions.hpp" namespace gl3cts { namespace ClipDistance { namespace Utility { /** @class Program * * @brief GLSL program encapsulation class. */ class Program { public: /* Public type definitions */ /** @struct CompilationStatus * * @brief GLSL shader encapsulation class. */ struct CompilationStatus { glw::GLuint shader_id; glw::GLint shader_compilation_status; std::string shader_log; }; /** @struct CompilationStatus * * @brief GLSL shader encapsulation class. */ struct LinkageStatus { glw::GLuint program_id; glw::GLint program_linkage_status; std::string program_linkage_log; }; /* Public member variables */ Program(const glw::Functions& gl, const std::string& vertex_shader_code, const std::string& fragment_shader_code, std::vector transform_feedback_varyings = std::vector()); ~Program(); const CompilationStatus& VertexShaderStatus() const; const CompilationStatus& FragmentShaderStatus() const; const LinkageStatus& ProgramStatus() const; void UseProgram() const; private: /* Private member variables */ CompilationStatus m_vertex_shader_status; CompilationStatus m_fragment_shader_status; LinkageStatus m_program_status; const glw::Functions& m_gl; /* Private member functions */ CompilationStatus compileShader(const glw::GLenum shader_type, const glw::GLchar* const* shader_code); LinkageStatus linkShaders(const CompilationStatus& vertex_shader, const CompilationStatus& fragment_shader, std::vector& transform_feedback_varyings); }; /* Program class */ /** @class Framebuffer * * @brief OpenGL's Framebuffer encapsulation class. * * @note Created framebuffer is red-color-only and float type. */ class Framebuffer { public: Framebuffer(const glw::Functions& gl, const glw::GLsizei size_x, const glw::GLsizei size_y); ~Framebuffer(); bool isValid(); void bind(); std::vector readPixels(); void clear(); private: const glw::Functions& m_gl; const glw::GLsizei m_size_x; const glw::GLsizei m_size_y; glw::GLuint m_framebuffer_id; glw::GLuint m_renderbuffer_id; }; /* Framebuffer class */ /** @class Vertex Array Object * * @brief OpenGL's Vertex Array Object encapsulation class. */ class VertexArrayObject { public: VertexArrayObject(const glw::Functions& gl, const glw::GLenum primitive_type); // create empty vao ~VertexArrayObject(); void bind(); void draw(glw::GLuint first, glw::GLuint count); void drawWithTransformFeedback(glw::GLuint first, glw::GLuint count, bool discard_rasterizer); private: const glw::Functions& m_gl; glw::GLuint m_vertex_array_object_id; glw::GLenum m_primitive_type; }; /* VertexArrayObject class */ /** @class Vertex Buffer Object * * @brief OpenGL's Vertex Buffer Object encapsulation template class. * * @note Input data type is a template parameter. */ template class VertexBufferObject { public: VertexBufferObject(const glw::Functions& gl, const glw::GLenum target, std::vector data); ~VertexBufferObject(); bool bind(); bool useAsShaderInput(Program program, std::string input_attribute_name, glw::GLint number_of_components); std::vector readBuffer(); private: const glw::Functions& m_gl; glw::GLuint m_vertex_buffer_object_id; glw::GLenum m_target; glw::GLsizei m_size; std::vector m_enabled_arrays; }; /* VertexBufferObject template class */ std::string preprocessCode(std::string source, std::string key, std::string value); std::string itoa(glw::GLint i); } /* Utility namespace */ /** @class Tests * * @brief Clip distance test group. */ class Tests : public deqp::TestCaseGroup { public: /* Public member functions */ Tests(deqp::Context& context); void init(); private: /* Private member functions */ Tests(const Tests& other); Tests& operator=(const Tests& other); }; /** @class CoverageTest * * @brief Clip distance API Coverage test cases. */ class CoverageTest : public deqp::TestCase { public: /* Public member functions */ CoverageTest(deqp::Context& context); virtual tcu::TestNode::IterateResult iterate(); private: /* Private member functions */ CoverageTest(const CoverageTest& other); CoverageTest& operator=(const CoverageTest& other); bool MaxClipDistancesValueTest(const glw::Functions& gl); bool EnableDisableTest(const glw::Functions& gl); bool MaxClipDistancesValueInVertexShaderTest(const glw::Functions& gl); bool MaxClipDistancesValueInFragmentShaderTest(const glw::Functions& gl); bool ClipDistancesValuePassing(const glw::Functions& gl); /* Private member variables */ glw::GLint m_gl_max_clip_distances_value; /* Private static constants */ static const glw::GLchar* m_vertex_shader_code_case_0; static const glw::GLchar* m_fragment_shader_code_case_0; static const glw::GLchar* m_vertex_shader_code_case_1; static const glw::GLchar* m_fragment_shader_code_case_1; static const glw::GLchar* m_vertex_shader_code_case_2; static const glw::GLchar* m_fragment_shader_code_case_2; }; /** @class FunctionalTest * * @brief Clip distance Functional test cases. */ class FunctionalTest : public deqp::TestCase { public: /* Public member functions */ FunctionalTest(deqp::Context& context); virtual void init(); virtual tcu::TestNode::IterateResult iterate(); private: /* Private member functions */ FunctionalTest(const FunctionalTest& other); FunctionalTest& operator=(const FunctionalTest& other); std::string prepareVertexShaderCode(bool explicit_redeclaration, bool dynamic_setter, glw::GLuint clip_count, glw::GLuint clip_function, glw::GLenum primitive_type); gl3cts::ClipDistance::Utility::VertexBufferObject* prepareGeometry(const glw::Functions& gl, const glw::GLenum primitive_type); bool checkResults(glw::GLenum primitive_type, glw::GLuint clip_function, std::vector& results); /* Private member variables */ glw::GLint m_gl_max_clip_distances_value; /* Private static constants */ static const glw::GLchar* m_vertex_shader_code; static const glw::GLchar* m_fragment_shader_code; static const glw::GLchar* m_dynamic_array_setter; static const glw::GLchar* m_static_array_setter; static const glw::GLchar* m_explicit_redeclaration; static const glw::GLchar* m_clip_function[]; static const glw::GLuint m_clip_function_count; static const glw::GLenum m_primitive_types[]; static const glw::GLenum m_primitive_indices[]; static const glw::GLuint m_primitive_types_count; static const glw::GLfloat m_expected_integral[]; }; /** @class NegativeTest * * @brief Clip distance API Negative test cases. */ class NegativeTest : public deqp::TestCase { public: /* Public member functions */ NegativeTest(deqp::Context& context); virtual tcu::TestNode::IterateResult iterate(); private: /* Private member functions */ NegativeTest(const NegativeTest& other); NegativeTest& operator=(const NegativeTest& other); bool testClipVertexBuildingErrors(const glw::Functions& gl); bool testMaxClipDistancesBuildingErrors(const glw::Functions& gl); bool testClipDistancesRedeclarationBuildingErrors(const glw::Functions& gl); /* Private static constants */ static const glw::GLchar* m_vertex_shader_code_case_0; static const glw::GLchar* m_vertex_shader_code_case_1; static const glw::GLchar* m_vertex_shader_code_case_2; static const glw::GLchar* m_fragment_shader_code; }; } /* ClipDistance namespace */ } /* gl3cts namespace */ /* Template classes' implementation */ /** @brief Vertex Buffer Object constructor. * * @note It silently binds VAO to OpenGL. * * @param [in] gl OpenGL functions access. * @param [in] target Binding target of the VBO. * @param [in] data Data of the buffer (may be empty). */ template gl3cts::ClipDistance::Utility::VertexBufferObject::VertexBufferObject(const glw::Functions& gl, const glw::GLenum target, std::vector data) : m_gl(gl), m_vertex_buffer_object_id(0), m_target(target), m_size(0) { m_gl.genBuffers(1, &m_vertex_buffer_object_id); GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers call failed."); if (m_vertex_buffer_object_id) { m_size = (glw::GLsizei)(sizeof(T) * data.size()); bind(); m_gl.bufferData(m_target, m_size, &data[0], GL_STATIC_DRAW); GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferData call failed."); } } /** @brief Vertex Buffer Object destructor. */ template gl3cts::ClipDistance::Utility::VertexBufferObject::~VertexBufferObject() { m_gl.deleteBuffers(1, &m_vertex_buffer_object_id); /* Delete silently unbinds the buffer. */ GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDeleteBuffers call failed."); for (std::vector::iterator i_enabled_array = m_enabled_arrays.begin(); i_enabled_array != m_enabled_arrays.end(); ++i_enabled_array) { m_gl.disableVertexAttribArray(*i_enabled_array); } } /** @brief Bind Vertex Buffer Object to its target. * * @note It binds also to indexed binding point for GL_TRANSFORM_FEEDBACK_BUFFER target. */ template bool gl3cts::ClipDistance::Utility::VertexBufferObject::bind() { if (m_vertex_buffer_object_id) { m_gl.bindBuffer(m_target, m_vertex_buffer_object_id); GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer call failed."); if (m_target == GL_TRANSFORM_FEEDBACK_BUFFER) { m_gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_vertex_buffer_object_id); GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBufferBase call failed."); } return true; } return false; } /** @brief Use VBO as attribute vertex array. * * @note It silently binds VBO. * * @param [in] program GLSL Program to which VBO shall be bound. * @param [in] input_attribute_name Name of GLSL asttribute. * @param [in] number_of_components Number of attribute's components. * * @return True on success, false otherwise. */ template bool gl3cts::ClipDistance::Utility::VertexBufferObject::useAsShaderInput(Program program, std::string input_attribute_name, glw::GLint number_of_components) { if (program.ProgramStatus().program_id) { glw::GLint location = m_gl.getAttribLocation(program.ProgramStatus().program_id, input_attribute_name.c_str()); GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetAttribLocation call failed."); if (location >= 0) { const std::type_info& buffer_type = typeid(T); const std::type_info& float_type = typeid(glw::GLfloat); const std::type_info& int_type = typeid(glw::GLint); m_gl.enableVertexAttribArray(location); GLU_EXPECT_NO_ERROR(m_gl.getError(), "glEnableVertexAttribArray call failed."); m_enabled_arrays.push_back(location); bind(); if (buffer_type == float_type) { m_gl.vertexAttribPointer(location, number_of_components, GL_FLOAT, false, 0, NULL); GLU_EXPECT_NO_ERROR(m_gl.getError(), "glVertexAttribPointer call failed."); } else if (buffer_type == int_type) { m_gl.vertexAttribIPointer(location, number_of_components, GL_FLOAT, 0, NULL); GLU_EXPECT_NO_ERROR(m_gl.getError(), "glVertexAttribIPointer call failed."); } else { return false; } return true; } } return false; } /** @brief Read VBO content (potentially set by transform feedback). * * @return Content of VBO. */ template std::vector gl3cts::ClipDistance::Utility::VertexBufferObject::readBuffer() { std::vector buffer_data(m_size / sizeof(T)); bind(); glw::GLvoid* results = m_gl.mapBuffer(m_target, GL_READ_ONLY); if (results) { memcpy(&buffer_data[0], results, m_size); } m_gl.unmapBuffer(m_target); return buffer_data; } #endif // _GL3CCLIPDISTANCE_HPP