/*------------------------------------------------------------------------- * 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 gl4cDirectStateAccessXFBTests.cpp * \brief Conformance tests for the Direct State Access feature functionality (Transform Feedbeck access part). */ /*-----------------------------------------------------------------------------------------------------------*/ /* Includes. */ #include "gl4cDirectStateAccessTests.hpp" #include "deSharedPtr.hpp" #include "gluContextInfo.hpp" #include "gluDefs.hpp" #include "gluPixelTransfer.hpp" #include "gluStrUtil.hpp" #include "tcuFuzzyImageCompare.hpp" #include "tcuImageCompare.hpp" #include "tcuRenderTarget.hpp" #include "tcuSurface.hpp" #include "tcuTestLog.hpp" #include "glw.h" #include "glwFunctions.hpp" namespace gl4cts { namespace DirectStateAccess { namespace TransformFeedback { /******************************** Creation Test Implementation ********************************/ /** @brief Creation Test constructor. * * @param [in] context OpenGL context. */ CreationTest::CreationTest(deqp::Context& context) : deqp::TestCase(context, "xfb_creation", "Transform Feedback Creation Test") { /* Intentionally left blank. */ } /** @brief Iterate Creation Test cases. * * @return Iteration result. */ tcu::TestNode::IterateResult CreationTest::iterate() { /* Shortcut for GL functionality */ const glw::Functions& gl = m_context.getRenderContext().getFunctions(); /* Get context setup. */ bool is_at_least_gl_45 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5))); bool is_arb_direct_state_access = m_context.getContextInfo().isExtensionSupported("GL_ARB_direct_state_access"); if ((!is_at_least_gl_45) && (!is_arb_direct_state_access)) { m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported"); return STOP; } /* Running tests. */ bool is_ok = true; bool is_error = false; /* Transform feedback objects */ static const glw::GLuint xfb_count = 2; glw::GLuint xfb_dsa[xfb_count] = {}; glw::GLuint xfb_legacy[xfb_count] = {}; try { /* Sanity default setup. */ gl.bindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTransformFeedback have failed"); /* Check legacy way. */ gl.genTransformFeedbacks(xfb_count, xfb_legacy); GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTransformFeedbacks have failed"); for (glw::GLuint i = 0; i < xfb_count; ++i) { if (gl.isTransformFeedback(xfb_legacy[i])) { is_ok = false; /* Log. */ m_context.getTestContext().getLog() << tcu::TestLog::Message << "GenTransformFeedbacks has created defualt objects, but only shall reserve names for them." << tcu::TestLog::EndMessage; } } /* Check direct state access way. */ gl.createTransformFeedbacks(xfb_count, xfb_dsa); GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateTransformFeedbacks have failed"); for (glw::GLuint i = 0; i < xfb_count; ++i) { if (!gl.isTransformFeedback(xfb_dsa[i])) { is_ok = false; /* Log. */ m_context.getTestContext().getLog() << tcu::TestLog::Message << "CreateTransformFeedbacks has not created defualt objects." << tcu::TestLog::EndMessage; } } /* Check binding point. */ glw::GLint xfb_binding_point = -1; gl.getIntegerv(GL_TRANSFORM_FEEDBACK_BINDING, &xfb_binding_point); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv have failed"); if (0 != xfb_binding_point) { if (-1 == xfb_binding_point) { m_context.getTestContext().getLog() << tcu::TestLog::Message << "glGetIntegerv used with GL_TRANSFORM_FEEDBACK_BINDING have not " "returned anything and did not generate error." << tcu::TestLog::EndMessage; throw 0; } else { m_context.getTestContext().getLog() << tcu::TestLog::Message << "The usage of glCreateTransformFeedbacks have changed " "GL_TRANSFORM_FEEDBACK_BINDING binding point." << tcu::TestLog::EndMessage; is_ok = false; } } } catch (...) { is_ok = false; is_error = true; } /* Cleanup. */ for (glw::GLuint i = 0; i < xfb_count; ++i) { if (xfb_legacy[i]) { gl.deleteTransformFeedbacks(1, &xfb_legacy[i]); xfb_legacy[i] = 0; } if (xfb_dsa[i]) { gl.deleteTransformFeedbacks(1, &xfb_dsa[i]); xfb_dsa[i] = 0; } } /* Result's setup. */ if (is_ok) { m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); } else { if (is_error) { m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error"); } else { m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); } } return STOP; } /******************************** Defaults Test Implementation ********************************/ /** @brief Defaults Test constructor. * * @param [in] context OpenGL context. */ DefaultsTest::DefaultsTest(deqp::Context& context) : deqp::TestCase(context, "xfb_defaults", "Transform Feedback Defaults Test") , m_gl_getTransformFeedbackiv(DE_NULL) , m_gl_getTransformFeedbacki_v(DE_NULL) , m_gl_getTransformFeedbacki64_v(DE_NULL) , m_xfb_dsa(0) , m_xfb_indexed_binding_points_count(0) { /* Intentionally left blank. */ } /** @brief Iterate Defaults Test cases. * * @return Iteration result. */ tcu::TestNode::IterateResult DefaultsTest::iterate() { /* Get context setup. */ bool is_at_least_gl_45 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5))); bool is_arb_direct_state_access = m_context.getContextInfo().isExtensionSupported("GL_ARB_direct_state_access"); if ((!is_at_least_gl_45) && (!is_arb_direct_state_access)) { m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported"); return STOP; } /* Running tests. */ bool is_ok = true; bool is_error = false; try { prepare(); is_ok &= testBuffersBindingPoints(); is_ok &= testBuffersDimensions(); is_ok &= testActive(); is_ok &= testPaused(); } catch (...) { is_ok = false; is_error = true; } /* Clean up. */ clean(); /* Result's setup. */ if (is_ok) { m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); } else { if (is_error) { m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error"); } else { m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); } } return STOP; } /** @brief Create XFB and Buffer Objects. Prepare function pointers. * * @note The function may throw if unexpected error has occured. * * @return True if test succeeded, false otherwise. */ void DefaultsTest::prepare() { /* Shortcut for GL functionality */ const glw::Functions& gl = m_context.getRenderContext().getFunctions(); /* Fetching function pointers. */ m_gl_getTransformFeedbackiv = (GetTransformFeedbackiv_ProcAddress)gl.getTransformFeedbackiv; m_gl_getTransformFeedbacki_v = (GetTransformFeedbacki_v_ProcAddress)gl.getTransformFeedbacki_v; m_gl_getTransformFeedbacki64_v = (GetTransformFeedbacki64_v_ProcAddress)gl.getTransformFeedbacki64_v; if ((DE_NULL == m_gl_getTransformFeedbackiv) || (DE_NULL == m_gl_getTransformFeedbacki_v) || (DE_NULL == m_gl_getTransformFeedbacki64_v)) { m_context.getTestContext().getLog() << tcu::TestLog::Message << "Function pointers are set to NULL values." << tcu::TestLog::EndMessage; throw 0; } /* XFB object creation */ gl.createTransformFeedbacks(1, &m_xfb_dsa); GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateTransformFeedbacks have failed"); /* Query limits. */ gl.getIntegerv(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, &m_xfb_indexed_binding_points_count); GLU_EXPECT_NO_ERROR(gl.getError(), "glIntegerv have failed"); } /** @brief Test default value of GL_TRANSFORM_FEEDBACK_BUFFER_BINDING. * * @note The function may throw if unexpected error has occured. * * @return True if test succeeded, false otherwise. */ bool DefaultsTest::testBuffersBindingPoints() { /* Shortcut for GL functionality */ const glw::Functions& gl = m_context.getRenderContext().getFunctions(); /* Check default binding points value. */ for (glw::GLint i = 0; i < m_xfb_indexed_binding_points_count; ++i) { glw::GLint buffer_binding = -1; m_gl_getTransformFeedbacki_v(m_xfb_dsa, GL_TRANSFORM_FEEDBACK_BUFFER_BINDING, i, &buffer_binding); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetTransformFeedbacki_v have failed"); if (-1 == buffer_binding) { m_context.getTestContext().getLog() << tcu::TestLog::Message << "glGetTransformFeedbacki_v with parameter GL_TRANSFORM_FEEDBACK_BUFFER_BINDING has not returned " "anything and error has not been generated." << tcu::TestLog::EndMessage; return false; } else { if (0 != buffer_binding) { m_context.getTestContext().getLog() << tcu::TestLog::Message << "glGetTransformFeedbacki_v with parameter GL_TRANSFORM_FEEDBACK_BUFFER_BINDING has returned " << buffer_binding << ", however 0 is expected." << tcu::TestLog::EndMessage; return false; } } } return true; } /** @brief Test default values of GL_TRANSFORM_FEEDBACK_START and GL_TRANSFORM_FEEDBACK_SIZE. * * @note The function may throw if unexpected error has occured. * * @return True if test succeeded, false otherwise. */ bool DefaultsTest::testBuffersDimensions() { /* Shortcut for GL functionality */ const glw::Functions& gl = m_context.getRenderContext().getFunctions(); /* Check default buffers' start value. */ for (glw::GLint i = 0; i < m_xfb_indexed_binding_points_count; ++i) { glw::GLint64 buffer_start = -1; m_gl_getTransformFeedbacki64_v(m_xfb_dsa, GL_TRANSFORM_FEEDBACK_BUFFER_START, i, &buffer_start); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetTransformFeedbacki_v have failed"); if (-1 == buffer_start) { m_context.getTestContext().getLog() << tcu::TestLog::Message << "glGetTransformFeedbacki_v with parameter GL_TRANSFORM_FEEDBACK_BUFFER_START has not returned " "anything and error has not been generated." << tcu::TestLog::EndMessage; return false; } else { if (0 != buffer_start) { m_context.getTestContext().getLog() << tcu::TestLog::Message << "glGetTransformFeedbacki_v with parameter GL_TRANSFORM_FEEDBACK_BUFFER_START has returned " << buffer_start << ", however 0 is expected." << tcu::TestLog::EndMessage; return false; } } } /** @brief Check default buffers' size value. * * @note The function may throw if unexpected error has occured. */ for (glw::GLint i = 0; i < m_xfb_indexed_binding_points_count; ++i) { glw::GLint64 buffer_size = -1; m_gl_getTransformFeedbacki64_v(m_xfb_dsa, GL_TRANSFORM_FEEDBACK_BUFFER_SIZE, i, &buffer_size); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetTransformFeedbacki_v have failed"); if (-1 == buffer_size) { m_context.getTestContext().getLog() << tcu::TestLog::Message << "glGetTransformFeedbacki_v with parameter GL_TRANSFORM_FEEDBACK_BUFFER_SIZE has not returned " "anything and error has not been generated." << tcu::TestLog::EndMessage; return false; } else { if (0 != buffer_size) { m_context.getTestContext().getLog() << tcu::TestLog::Message << "glGetTransformFeedbacki_v with parameter GL_TRANSFORM_FEEDBACK_BUFFER_SIZE has returned " << buffer_size << ", however 0 is expected." << tcu::TestLog::EndMessage; return false; } } } return true; } /** @brief Test default value of GL_TRANSFORM_FEEDBACK_ACTIVE. * * @return True if test succeeded, false otherwise. */ bool DefaultsTest::testActive() { /* Check that it is not active. */ glw::GLint is_active = -1; m_gl_getTransformFeedbackiv(m_xfb_dsa, GL_TRANSFORM_FEEDBACK_ACTIVE, &is_active); if (-1 == is_active) { m_context.getTestContext().getLog() << tcu::TestLog::Message << "glGetTransformFeedbackiv with parameter GL_TRANSFORM_FEEDBACK_ACTIVE " "has not returned anything and error has not been generated." << tcu::TestLog::EndMessage; return false; } else { if (0 != is_active) { m_context.getTestContext().getLog() << tcu::TestLog::Message << "glGetTransformFeedbackiv with parameter GL_TRANSFORM_FEEDBACK_ACTIVE has returned " << is_active << ", however FALSE is expected." << tcu::TestLog::EndMessage; return false; } } return true; } /** @brief Test default value of GL_TRANSFORM_FEEDBACK_PAUSED. * * @return True if test succeeded, false otherwise. */ bool DefaultsTest::testPaused() { /* Check that it is not paused. */ glw::GLint is_paused = -1; m_gl_getTransformFeedbackiv(m_xfb_dsa, GL_TRANSFORM_FEEDBACK_PAUSED, &is_paused); if (-1 == is_paused) { m_context.getTestContext().getLog() << tcu::TestLog::Message << "glGetTransformFeedbacki_v with parameter GL_TRANSFORM_FEEDBACK_PAUSED " "has not returned anything and error has not been generated." << tcu::TestLog::EndMessage; return false; } else { if (0 != is_paused) { m_context.getTestContext().getLog() << tcu::TestLog::Message << "glGetTransformFeedbackiv with parameter GL_TRANSFORM_FEEDBACK_PAUSED has returned " << is_paused << ", however FALSE is expected." << tcu::TestLog::EndMessage; return false; } } return true; } /** @brief Release GL objects. */ void DefaultsTest::clean() { /* Shortcut for GL functionality */ const glw::Functions& gl = m_context.getRenderContext().getFunctions(); if (m_xfb_dsa) { gl.deleteTransformFeedbacks(1, &m_xfb_dsa); m_xfb_dsa = 0; } } /******************************** Buffers Test Implementation ********************************/ /** @brief Buffers Test constructor. * * @param [in] context OpenGL context. */ BuffersTest::BuffersTest(deqp::Context& context) : deqp::TestCase(context, "xfb_buffers", "Transform Feedback Buffers Test") , m_gl_getTransformFeedbacki_v(DE_NULL) , m_gl_getTransformFeedbacki64_v(DE_NULL) , m_gl_TransformFeedbackBufferBase(DE_NULL) , m_gl_TransformFeedbackBufferRange(DE_NULL) , m_xfb_dsa(0) , m_bo_a(0) , m_bo_b(0) { /* Intentionally left blank. */ } /** @brief Iterate Buffers Test cases. * * @return Iteration result. */ tcu::TestNode::IterateResult BuffersTest::iterate() { /* Get context setup. */ bool is_at_least_gl_45 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5))); bool is_arb_direct_state_access = m_context.getContextInfo().isExtensionSupported("GL_ARB_direct_state_access"); if ((!is_at_least_gl_45) && (!is_arb_direct_state_access)) { m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported"); return STOP; } /* Running tests. */ bool is_ok = true; bool is_error = false; try { /* Prepare function pointers, transform feedback and buffer objects. */ prepareObjects(); /* Setup transform feedback object binding points with buffer objects. */ is_ok = prepareTestSetup(); /* Continue only if test setup succeeded */ if (is_ok) { is_ok &= testBindingPoint(0, m_bo_a, "glTransformFeedbackBufferBase"); is_ok &= testBindingPoint(1, m_bo_b, "glTransformFeedbackBufferRange"); is_ok &= testBindingPoint(2, m_bo_b, "glTransformFeedbackBufferRange"); is_ok &= testStart(0, 0, "glTransformFeedbackBufferBase"); is_ok &= testStart(1, 0, "glTransformFeedbackBufferRange"); is_ok &= testStart(2, s_bo_size / 2, "glTransformFeedbackBufferRange"); is_ok &= testSize(0, 0, "glTransformFeedbackBufferBase"); is_ok &= testSize(1, s_bo_size / 2, "glTransformFeedbackBufferRange"); is_ok &= testSize(2, s_bo_size / 2, "glTransformFeedbackBufferRange"); } } catch (...) { is_ok = false; is_error = true; } /* Clean up. */ clean(); /* Result's setup. */ if (is_ok) { m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); } else { if (is_error) { m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error"); } else { m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); } } return STOP; } /** @brief Create XFB amd BO objects. Setup function pointers. * * @note The function may throw if unexpected error has occured. */ void BuffersTest::prepareObjects() { /* Shortcut for GL functionality */ const glw::Functions& gl = m_context.getRenderContext().getFunctions(); /* Fetching function pointers. */ m_gl_getTransformFeedbacki_v = (GetTransformFeedbacki_v_ProcAddress)gl.getTransformFeedbacki_v; m_gl_getTransformFeedbacki64_v = (GetTransformFeedbacki64_v_ProcAddress)gl.getTransformFeedbacki64_v; m_gl_TransformFeedbackBufferBase = (TransformFeedbackBufferBase_ProcAddress)gl.transformFeedbackBufferBase; m_gl_TransformFeedbackBufferRange = (TransformFeedbackBufferRange_ProcAddress)gl.transformFeedbackBufferRange; if ((DE_NULL == m_gl_getTransformFeedbacki_v) || (DE_NULL == m_gl_getTransformFeedbacki64_v) || (DE_NULL == m_gl_TransformFeedbackBufferBase) || (DE_NULL == m_gl_TransformFeedbackBufferRange)) { m_context.getTestContext().getLog() << tcu::TestLog::Message << "Function pointers are set to NULL values." << tcu::TestLog::EndMessage; throw 0; } /** @brief XFB object creation */ gl.createTransformFeedbacks(1, &m_xfb_dsa); GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateTransformFeedbacks have failed"); /* Buffer Objects creation. */ gl.genBuffers(1, &m_bo_a); gl.genBuffers(1, &m_bo_b); GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers have failed"); if ((0 == m_bo_a) || (0 == m_bo_b)) { m_context.getTestContext().getLog() << tcu::TestLog::Message << "Buffer object has not been generated and no error has been triggered." << tcu::TestLog::EndMessage; throw 0; } /* First buffer memory allocation. */ gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_a); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffers have failed"); gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, s_bo_size, NULL, GL_DYNAMIC_COPY); GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData have failed"); /* Sainty check of buffer size */ glw::GLint allocated_size = -1; gl.getBufferParameteriv(GL_TRANSFORM_FEEDBACK_BUFFER, GL_BUFFER_SIZE, &allocated_size); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetBufferParameteriv have failed"); if (allocated_size != (glw::GLint)s_bo_size) { m_context.getTestContext().getLog() << tcu::TestLog::Message << "Buffer allocation failed." << tcu::TestLog::EndMessage; throw 0; } /* Second buffer memory allocation. */ gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_b); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffers have failed"); gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, s_bo_size, NULL, GL_DYNAMIC_COPY); GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData have failed"); /* Sainty check of buffer size */ allocated_size = -1; gl.getBufferParameteriv(GL_TRANSFORM_FEEDBACK_BUFFER, GL_BUFFER_SIZE, &allocated_size); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetBufferParameteriv have failed"); if (allocated_size != (glw::GLint)s_bo_size) { m_context.getTestContext().getLog() << tcu::TestLog::Message << "Buffer allocation failed." << tcu::TestLog::EndMessage; throw 0; } gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffers have failed"); } /** @brief Setup indexed buffer binding points in the xfb object using * glTransformFeedbackBufferBase and glTransformFeedbackBufferRange * functions. * * @return True if setup succeeded, false otherwise (functions triggered errors). */ bool BuffersTest::prepareTestSetup() { /* Shortcut for GL functionality */ const glw::Functions& gl = m_context.getRenderContext().getFunctions(); /* Bind Buffer Object to first indexed binding point. */ m_gl_TransformFeedbackBufferBase(m_xfb_dsa, 0, m_bo_a); /* Check errors. */ glw::GLenum error_value = gl.getError(); if (GL_NONE != error_value) { m_context.getTestContext().getLog() << tcu::TestLog::Message << "glTransformFeedbackBufferBase has generated unexpected error (" << glu::getErrorStr(error_value) << "). Test Failed." << tcu::TestLog::EndMessage; return false; } /* Bind Buffer Object to second and third indexed binding point. */ m_gl_TransformFeedbackBufferRange(m_xfb_dsa, 1, m_bo_b, 0, s_bo_size / 2); m_gl_TransformFeedbackBufferRange(m_xfb_dsa, 2, m_bo_b, s_bo_size / 2, s_bo_size / 2); /* Check errors. */ error_value = gl.getError(); if (GL_NONE != error_value) { m_context.getTestContext().getLog() << tcu::TestLog::Message << "glTransformFeedbackBufferRange has generated unexpected error (" << glu::getErrorStr(error_value) << "). Test Failed." << tcu::TestLog::EndMessage; return false; } return true; } /** @brief Test that xfb object's binding point # has . * * @param [in] index Tested index point. * @param [in] expected_value Value to be expected (buffer name). * @param [in] tested_function_name Name of function which this function is going to test * (glTransformFeedbackBufferBase or glTransformFeedbackBufferRange) * for logging purposes. * * @note The function may throw if unexpected error has occured. * * @return True if test succeeded, false otherwise. */ bool BuffersTest::testBindingPoint(glw::GLuint const index, glw::GLint const expected_value, glw::GLchar const* const tested_function_name) { /* Shortcut for GL functionality */ const glw::Functions& gl = m_context.getRenderContext().getFunctions(); /* Check default binding points value. */ glw::GLint buffer_binding = -1; m_gl_getTransformFeedbacki_v(m_xfb_dsa, GL_TRANSFORM_FEEDBACK_BUFFER_BINDING, index, &buffer_binding); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetTransformFeedbacki_v have failed"); if (-1 == buffer_binding) { m_context.getTestContext().getLog() << tcu::TestLog::Message << "glGetTransformFeedbacki_v with parameter GL_TRANSFORM_FEEDBACK_BUFFER_BINDING " "has not returned anything and error has not been generated." << tcu::TestLog::EndMessage; return false; } else { if (expected_value != buffer_binding) { m_context.getTestContext().getLog() << tcu::TestLog::Message << "glGetTransformFeedbacki_v with parameter GL_TRANSFORM_FEEDBACK_BUFFER_BINDING has returned " << buffer_binding << ", however " << expected_value << " is expected. As a consequence function " << tested_function_name << " have failed to setup proper value." << tcu::TestLog::EndMessage; return false; } } return true; } /** @brief Test that buffer object at xfb object's binding point # has starting offset set to the . * * @param [in] index Tested index point. * @param [in] expected_value Value to be expected (starting offset). * @param [in] tested_function_name Name of function which this function is going to test * (glTransformFeedbackBufferBase or glTransformFeedbackBufferRange) * for logging purposes. * * @note The function may throw if unexpected error has occured. * * @return True if test succeeded, false otherwise. */ bool BuffersTest::testStart(glw::GLuint const index, glw::GLint const expected_value, glw::GLchar const* const tested_function_name) { /* Shortcut for GL functionality */ const glw::Functions& gl = m_context.getRenderContext().getFunctions(); /* Check default buffers' start value. */ glw::GLint64 buffer_start = -1; m_gl_getTransformFeedbacki64_v(m_xfb_dsa, GL_TRANSFORM_FEEDBACK_BUFFER_START, index, &buffer_start); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetTransformFeedbacki_v have failed"); /* Checking results and errors. */ if (-1 == buffer_start) { m_context.getTestContext().getLog() << tcu::TestLog::Message << "glGetTransformFeedbacki_v with parameter GL_TRANSFORM_FEEDBACK_BUFFER_START " "has not returned anything and error has not been generated." << tcu::TestLog::EndMessage; return false; } else { if (expected_value != buffer_start) { m_context.getTestContext().getLog() << tcu::TestLog::Message << "glGetTransformFeedbacki_v with parameter GL_TRANSFORM_FEEDBACK_BUFFER_START has returned " << buffer_start << ", however " << expected_value << " is expected. As a consequence function " << tested_function_name << " have failed to setup proper value." << tcu::TestLog::EndMessage; return false; } } return true; } /** @brief Test that buffer object at xfb object's binding point # has size set to the . * * @param [in] index Tested index point. * @param [in] expected_value Value to be expected (buffer's size). * @param [in] tested_function_name Name of function which this function is going to test * (glTransformFeedbackBufferBase or glTransformFeedbackBufferRange) * for logging purposes. * * @note The function may throw if unexpected error has occured. * * @return True if test succeeded, false otherwise. */ bool BuffersTest::testSize(glw::GLuint const index, glw::GLint const expected_value, glw::GLchar const* const tested_function_name) { /* Shortcut for GL functionality */ const glw::Functions& gl = m_context.getRenderContext().getFunctions(); /* Check default buffer's size value. */ glw::GLint64 buffer_size = -1; m_gl_getTransformFeedbacki64_v(m_xfb_dsa, GL_TRANSFORM_FEEDBACK_BUFFER_SIZE, index, &buffer_size); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetTransformFeedbacki_v have failed"); /* Checking results and errors. */ if (-1 == buffer_size) { m_context.getTestContext().getLog() << tcu::TestLog::Message << "glGetTransformFeedbacki_v with parameter GL_TRANSFORM_FEEDBACK_BUFFER_SIZE " "has not returned anything and error has not been generated." << tcu::TestLog::EndMessage; return false; } else { if (expected_value != buffer_size) { m_context.getTestContext().getLog() << tcu::TestLog::Message << "glGetTransformFeedbacki_v with parameter GL_TRANSFORM_FEEDBACK_BUFFER_SIZE has returned " << buffer_size << ", however " << expected_value << " is expected. As a consequence function " << tested_function_name << " have failed to setup proper value." << tcu::TestLog::EndMessage; return false; } } return true; } /** @brief Clean al GL objects */ void BuffersTest::clean() { /* Shortcut for GL functionality */ const glw::Functions& gl = m_context.getRenderContext().getFunctions(); /* Release transform feedback object. */ if (m_xfb_dsa) { gl.deleteTransformFeedbacks(1, &m_xfb_dsa); m_xfb_dsa = 0; } /* Release buffer objects. */ if (m_bo_a) { gl.deleteBuffers(1, &m_bo_a); m_bo_a = 0; } if (m_bo_b) { gl.deleteBuffers(1, &m_bo_b); m_bo_b = 0; } } /** @brief Buffer Object Size */ const glw::GLuint BuffersTest::s_bo_size = 512; /******************************** Errors Test Implementation ********************************/ /** @brief Errors Test constructor. * * @param [in] context OpenGL context. */ ErrorsTest::ErrorsTest(deqp::Context& context) : deqp::TestCase(context, "xfb_errors", "Transform Feedback Errors Test") , m_gl_getTransformFeedbackiv(DE_NULL) , m_gl_getTransformFeedbacki_v(DE_NULL) , m_gl_getTransformFeedbacki64_v(DE_NULL) { /* Intentionally left blank. */ } /** @brief Iterate Errors Test cases. * * @return Iteration result. */ tcu::TestNode::IterateResult ErrorsTest::iterate() { /* Get context setup. */ bool is_at_least_gl_45 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5))); bool is_arb_direct_state_access = m_context.getContextInfo().isExtensionSupported("GL_ARB_direct_state_access"); if ((!is_at_least_gl_45) && (!is_arb_direct_state_access)) { m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported"); return STOP; } /* Running tests. */ bool is_ok = true; bool is_error = false; try { prepareFunctionPointers(); is_ok &= testCreateTransformFeedbacksForInvalidNumberOfObjects(); cleanErrors(); is_ok &= testQueriesForInvalidNameOfObject(); cleanErrors(); is_ok &= testGetTransformFeedbackivQueryForInvalidParameterName(); cleanErrors(); is_ok &= testGetTransformFeedbacki_vQueryForInvalidParameterName(); cleanErrors(); is_ok &= testGetTransformFeedbacki64_vQueryForInvalidParameterName(); cleanErrors(); is_ok &= testIndexedQueriesForInvalidBindingPoint(); cleanErrors(); } catch (...) { is_ok = false; is_error = true; } /* Result's setup. */ if (is_ok) { m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); } else { if (is_error) { m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error"); } else { m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); } } return STOP; } /** @brief Fetch GL function pointers. * * @note The function may throw if unexpected error has occured. */ void ErrorsTest::prepareFunctionPointers() { /* Shortcut for GL functionality */ const glw::Functions& gl = m_context.getRenderContext().getFunctions(); /* Fetching function pointers. */ m_gl_getTransformFeedbackiv = (GetTransformFeedbackiv_ProcAddress)gl.getTransformFeedbackiv; m_gl_getTransformFeedbacki_v = (GetTransformFeedbacki_v_ProcAddress)gl.getTransformFeedbacki_v; m_gl_getTransformFeedbacki64_v = (GetTransformFeedbacki64_v_ProcAddress)gl.getTransformFeedbacki64_v; if ((DE_NULL == m_gl_getTransformFeedbackiv) || (DE_NULL == m_gl_getTransformFeedbacki_v) || (DE_NULL == m_gl_getTransformFeedbacki64_v)) { m_context.getTestContext().getLog() << tcu::TestLog::Message << "Function pointers are set to NULL values." << tcu::TestLog::EndMessage; throw 0; } } /** @brief Sanity clean-up of GL errors. * * @note This function is to only make sure that failing test will not affect other tests. */ void ErrorsTest::cleanErrors() { /* Shortcut for GL functionality */ const glw::Functions& gl = m_context.getRenderContext().getFunctions(); /* Cleaning errors. */ while (GL_NO_ERROR != gl.getError()) ; } /** @brief Test Creation of Transform Feedbacks using Invalid Number Of Objects * * @note Test checks that CreateTransformFeedbacks generates INVALID_VALUE error if * number of transform feedback objects to create is negative. * * @return true if test succeded, false otherwise. */ bool ErrorsTest::testCreateTransformFeedbacksForInvalidNumberOfObjects() { /* Shortcut for GL functionality */ const glw::Functions& gl = m_context.getRenderContext().getFunctions(); glw::GLuint xfbs = 314159; gl.createTransformFeedbacks(-1 /* invalid count */, &xfbs); glw::GLenum error = gl.getError(); if (GL_INVALID_VALUE != error) { m_context.getTestContext().getLog() << tcu::TestLog::Message << "glCreateTransformFeedbacks called with negative number of objects had " "been expected to generate GL_INVALID_VALUE. However, " << glu::getErrorStr(error) << " was captured." << tcu::TestLog::EndMessage; return false; } if (314159 != xfbs) { m_context.getTestContext().getLog() << tcu::TestLog::Message << "glCreateTransformFeedbacks called with negative number of objects had " "been expected not to change the given buffer." << tcu::TestLog::EndMessage; return false; } return true; } /** @brief Test Direct State Access queries with invalid object name * * @note Test checks that GetTransformFeedbackiv, GetTransformFeedbacki_v and * GetTransformFeedbacki64_v generate INVALID_OPERATION error if xfb is not * zero or the name of an existing transform feedback object. * * @return true if test succeded, false otherwise. */ bool ErrorsTest::testQueriesForInvalidNameOfObject() { /* Shortcut for GL functionality */ const glw::Functions& gl = m_context.getRenderContext().getFunctions(); /* Generating not a-TransformFeedback name. */ glw::GLuint invalid_name = 0; while (GL_TRUE == gl.isTransformFeedback(++invalid_name)) ; /* Dummy storage. */ glw::GLint buffer = 314159; glw::GLint64 buffer64 = 314159; /* Error variable. */ glw::GLenum error = 0; /* Test of GetTransformFeedbackiv. */ m_gl_getTransformFeedbackiv(invalid_name, GL_TRANSFORM_FEEDBACK_PAUSED, &buffer); if (GL_INVALID_OPERATION != (error = gl.getError())) { m_context.getTestContext().getLog() << tcu::TestLog::Message << "glGetTransformFeedbackiv called with invalid object name had been " "expected to generate GL_INVALID_OPERATION. However, " << glu::getErrorStr(error) << " was captured." << tcu::TestLog::EndMessage; return false; } if (314159 != buffer) { m_context.getTestContext().getLog() << tcu::TestLog::Message << "glGetTransformFeedbackiv called with invalid object name had been " "expected not to change the given buffer." << tcu::TestLog::EndMessage; return false; } while (GL_NO_ERROR != (error = gl.getError())) { m_context.getTestContext().getLog() << tcu::TestLog::Message << "Warning! glGetTransformFeedbackiv called with invalid object name has " "generated more than one error, The next error was " << glu::getErrorStr(error) << "." << tcu::TestLog::EndMessage; } /* Test of GetTransformFeedbacki_v. */ m_gl_getTransformFeedbacki_v(invalid_name, GL_TRANSFORM_FEEDBACK_BUFFER_BINDING, 0, &buffer); if (GL_INVALID_OPERATION != (error = gl.getError())) { m_context.getTestContext().getLog() << tcu::TestLog::Message << "glGetTransformFeedbacki_v called with invalid object name had been " "expected to generate GL_INVALID_OPERATION. However, " << glu::getErrorStr(error) << " was captured." << tcu::TestLog::EndMessage; return false; } if (314159 != buffer) { m_context.getTestContext().getLog() << tcu::TestLog::Message << "glGetTransformFeedbacki_v called with invalid object name had been " "expected not to change the given buffer." << tcu::TestLog::EndMessage; return false; } while (GL_NO_ERROR != (error = gl.getError())) { m_context.getTestContext().getLog() << tcu::TestLog::Message << "Warning! glGetTransformFeedbacki_v called with invalid object name has " "unexpectedly generated more than one error, The next error was " << glu::getErrorStr(error) << "." << tcu::TestLog::EndMessage; } /* Test of GetTransformFeedbacki64_v. */ m_gl_getTransformFeedbacki64_v(invalid_name, GL_TRANSFORM_FEEDBACK_BUFFER_START, 0, &buffer64); if (GL_INVALID_OPERATION != (error = gl.getError())) { m_context.getTestContext().getLog() << tcu::TestLog::Message << "glGetTransformFeedbacki64_v called with invalid object name had been " "expected to generate GL_INVALID_OPERATION. However, " << glu::getErrorStr(error) << " was captured." << tcu::TestLog::EndMessage; return false; } if (314159 != buffer64) { m_context.getTestContext().getLog() << tcu::TestLog::Message << "glGetTransformFeedbacki64_v called with invalid object name had been " "expected not to change the given buffer." << tcu::TestLog::EndMessage; return false; } while (GL_NO_ERROR != (error = gl.getError())) { m_context.getTestContext().getLog() << tcu::TestLog::Message << "Warning! glGetTransformFeedbacki64_v called with invalid object name " "has unexpectedly generated more than one error, The next error was " << glu::getErrorStr(error) << "." << tcu::TestLog::EndMessage; } return true; } /** @brief Test Direct State Access queries with invalid parameter name * * @note Test checks that GetTransformFeedbackiv generates INVALID_ENUM error if pname * is not TRANSFORM_FEEDBACK_PAUSED or TRANSFORM_FEEDBACK_ACTIVE. * * @note The function may throw if unexpected error has occured. * * @return true if test succeded, false otherwise. */ bool ErrorsTest::testGetTransformFeedbackivQueryForInvalidParameterName() { /* Shortcut for GL functionality */ const glw::Functions& gl = m_context.getRenderContext().getFunctions(); /* Creating XFB object. */ glw::GLuint xfb = 0; gl.createTransformFeedbacks(1, &xfb); GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateTransformFeedbacks have failed"); /* Generating invalid parameter name. */ glw::GLuint invalid_parameter_name = 0; /* Dummy storage. */ glw::GLint buffer = 314159; /* Error variable. */ glw::GLenum error = 0; /* Default result. */ bool is_ok = true; /* Test of GetTransformFeedbackiv. */ m_gl_getTransformFeedbackiv(xfb, invalid_parameter_name, &buffer); if (GL_INVALID_ENUM != (error = gl.getError())) { m_context.getTestContext().getLog() << tcu::TestLog::Message << "glGetTransformFeedbackiv called with invalid parameter name had been " "expected to generate GL_INVALID_ENUM. However, " << glu::getErrorStr(error) << " was captured." << tcu::TestLog::EndMessage; is_ok = false; } if (314159 != buffer) { m_context.getTestContext().getLog() << tcu::TestLog::Message << "glGetTransformFeedbackiv called with invalid parameter name had been " "expected not to change the given buffer." << tcu::TestLog::EndMessage; is_ok = false; } while (GL_NO_ERROR != (error = gl.getError())) { m_context.getTestContext().getLog() << tcu::TestLog::Message << "Warning! glGetTransformFeedbackiv called with invalid parameter name " "has generated more than one error, The next error was " << glu::getErrorStr(error) << "." << tcu::TestLog::EndMessage; } /* Clean-up. */ gl.deleteTransformFeedbacks(1, &xfb); GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteTransformFeedbacks have failed"); return is_ok; } /** @brief Test Direct State Access indexed integer query with invalid parameter name * * @note Test checks that GetTransformFeedbacki_v generates INVALID_ENUM error if pname * is not TRANSFORM_FEEDBACK_BUFFER_BINDING. * * @note The function may throw if unexpected error has occured. * * @return true if test succeded, false otherwise. */ bool ErrorsTest::testGetTransformFeedbacki_vQueryForInvalidParameterName() { /* Shortcut for GL functionality */ const glw::Functions& gl = m_context.getRenderContext().getFunctions(); /* Creating XFB object. */ glw::GLuint xfb = 0; gl.createTransformFeedbacks(1, &xfb); GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateTransformFeedbacks have failed"); /* Generating invalid parameter name. */ glw::GLuint invalid_parameter_name = 0; /* Dummy storage. */ glw::GLint buffer = 314159; /* Error variable. */ glw::GLenum error = 0; /* Default result. */ bool is_ok = true; /* Test of GetTransformFeedbackiv. */ m_gl_getTransformFeedbacki_v(xfb, invalid_parameter_name, 0, &buffer); if (GL_INVALID_ENUM != (error = gl.getError())) { m_context.getTestContext().getLog() << tcu::TestLog::Message << "glGetTransformFeedbacki_v called with invalid parameter name had been " "expected to generate GL_INVALID_ENUM. However, " << glu::getErrorStr(error) << " was captured." << tcu::TestLog::EndMessage; is_ok = false; } if (314159 != buffer) { m_context.getTestContext().getLog() << tcu::TestLog::Message << "glGetTransformFeedbacki_v called with invalid parameter name had been " "expected not to change the given buffer." << tcu::TestLog::EndMessage; is_ok = false; } while (GL_NO_ERROR != (error = gl.getError())) { m_context.getTestContext().getLog() << tcu::TestLog::Message << "Warning! glGetTransformFeedbacki_v called with invalid parameter name " "has generated more than one error, The next error was " << glu::getErrorStr(error) << "." << tcu::TestLog::EndMessage; } /* Clean-up. */ gl.deleteTransformFeedbacks(1, &xfb); GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteTransformFeedbacks have failed"); return is_ok; } /** @brief Test Direct State Access indexed 64 bit integer query with invalid parameter name * * @note Test checks that GetTransformFeedbacki64_v generates INVALID_ENUM error if * pname is not TRANSFORM_FEEDBACK_BUFFER_START or * TRANSFORM_FEEDBACK_BUFFER_SIZE. * * @note The function may throw if unexpected error has occured. * * @return true if test succeded, false otherwise. */ bool ErrorsTest::testGetTransformFeedbacki64_vQueryForInvalidParameterName() { /* Shortcut for GL functionality */ const glw::Functions& gl = m_context.getRenderContext().getFunctions(); /* Creating XFB object. */ glw::GLuint xfb = 0; gl.createTransformFeedbacks(1, &xfb); GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateTransformFeedbacks have failed"); /* Generating invalid parameter name. */ glw::GLuint invalid_parameter_name = 0; /* Dummy storage. */ glw::GLint64 buffer = 314159; /* Error variable. */ glw::GLenum error = 0; /* Default result. */ bool is_ok = true; /* Test of GetTransformFeedbackiv. */ m_gl_getTransformFeedbacki64_v(xfb, invalid_parameter_name, 0, &buffer); if (GL_INVALID_ENUM != (error = gl.getError())) { m_context.getTestContext().getLog() << tcu::TestLog::Message << "glGetTransformFeedbacki64_v called with invalid parameter name had " "been expected to generate GL_INVALID_ENUM. However, " << glu::getErrorStr(error) << " was captured." << tcu::TestLog::EndMessage; is_ok = false; } if (314159 != buffer) { m_context.getTestContext().getLog() << tcu::TestLog::Message << "glGetTransformFeedbacki64_v called with invalid parameter name had " "been expected not to change the given buffer." << tcu::TestLog::EndMessage; is_ok = false; } while (GL_NO_ERROR != (error = gl.getError())) { m_context.getTestContext().getLog() << tcu::TestLog::Message << "Warning! glGetTransformFeedbacki64_v called with invalid parameter " "name has generated more than one error, The next error was " << glu::getErrorStr(error) << "." << tcu::TestLog::EndMessage; } /* Clean-up. */ gl.deleteTransformFeedbacks(1, &xfb); GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteTransformFeedbacks have failed"); return is_ok; } /** @brief Test Direct State Access indexed queries with invalid index * * @note Test checks that GetTransformFeedbacki_v and GetTransformFeedbacki64_v * generate INVALID_VALUE error by GetTransformFeedbacki_v and * GetTransformFeedbacki64_v if index is greater than or equal to the * number of binding points for transform feedback (the value of * MAX_TRANSFORM_FEEDBACK_BUFFERS). * * @note The function may throw if unexpected error has occured. * * @return true if test succeded, false otherwise. */ bool ErrorsTest::testIndexedQueriesForInvalidBindingPoint() { /* Shortcut for GL functionality */ const glw::Functions& gl = m_context.getRenderContext().getFunctions(); /* Generating invalid index. */ glw::GLint max_transform_feedback_buffers = 4; /* Default limit is 4 - OpenGL 4.5 Core Specification, Table 23.72: Implementation Dependent Transform Feedback Limits. */ gl.getIntegerv(GL_MAX_TRANSFORM_FEEDBACK_BUFFERS, &max_transform_feedback_buffers); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv have failed"); /* Creating XFB object. */ glw::GLuint xfb = 0; gl.createTransformFeedbacks(1, &xfb); GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateTransformFeedbacks have failed"); /* Dummy storage. */ glw::GLint buffer = 314159; glw::GLint64 buffer64 = 314159; /* Error variable. */ glw::GLenum error = 0; /* Default result. */ bool is_ok = true; /* Test of GetTransformFeedbacki_v. */ m_gl_getTransformFeedbacki_v(xfb, GL_TRANSFORM_FEEDBACK_BUFFER_BINDING, max_transform_feedback_buffers, &buffer); if (GL_INVALID_VALUE != (error = gl.getError())) { m_context.getTestContext().getLog() << tcu::TestLog::Message << "glGetTransformFeedbacki_v called with invalid index had been expected " "to generate GL_INVALID_VALUE. However, " << glu::getErrorStr(error) << " was captured." << tcu::TestLog::EndMessage; is_ok = false; } if (314159 != buffer) { m_context.getTestContext().getLog() << tcu::TestLog::Message << "glGetTransformFeedbacki_v called with invalid index had been expected not to change the given buffer." << tcu::TestLog::EndMessage; is_ok = false; } while (GL_NO_ERROR != (error = gl.getError())) { m_context.getTestContext().getLog() << tcu::TestLog::Message << "Warning! glGetTransformFeedbacki_v called with invalid index has " "unexpectedly generated more than one error, The next error was " << glu::getErrorStr(error) << "." << tcu::TestLog::EndMessage; } /* Test of GetTransformFeedbacki64_v. */ m_gl_getTransformFeedbacki64_v(xfb, GL_TRANSFORM_FEEDBACK_BUFFER_START, max_transform_feedback_buffers, &buffer64); if (GL_INVALID_VALUE != (error = gl.getError())) { m_context.getTestContext().getLog() << tcu::TestLog::Message << "glGetTransformFeedbacki64_v called with invalid index had been " "expected to generate GL_INVALID_VALUE. However, " << glu::getErrorStr(error) << " was captured." << tcu::TestLog::EndMessage; is_ok = false; } if (314159 != buffer64) { m_context.getTestContext().getLog() << tcu::TestLog::Message << "glGetTransformFeedbacki64_v called with invalid index had been expected not to change the given buffer." << tcu::TestLog::EndMessage; is_ok = false; } while (GL_NO_ERROR != (error = gl.getError())) { m_context.getTestContext().getLog() << tcu::TestLog::Message << "Warning! glGetTransformFeedbacki64_v called with invalid index has " "unexpectedly generated more than one error, The next error was " << glu::getErrorStr(error) << "." << tcu::TestLog::EndMessage; } /* Clean-up. */ gl.deleteTransformFeedbacks(1, &xfb); GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteTransformFeedbacks have failed"); return is_ok; } /******************************** Functional Test Implementation ********************************/ /** @brief Functional Test constructor. * * @param [in] context OpenGL context. */ FunctionalTest::FunctionalTest(deqp::Context& context) : deqp::TestCase(context, "xfb_functional", "Transform Feedback Functional Test") , m_gl_getTransformFeedbackiv(DE_NULL) , m_gl_TransformFeedbackBufferBase(DE_NULL) , m_xfb_dsa(0) , m_bo(0) , m_po(0) , m_vao(0) { /* Intentionally left blank. */ } /** @brief Iterate Functional Test cases. * * @return Iteration result. */ tcu::TestNode::IterateResult FunctionalTest::iterate() { /* Get context setup. */ bool is_at_least_gl_45 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5))); bool is_arb_direct_state_access = m_context.getContextInfo().isExtensionSupported("GL_ARB_direct_state_access"); if ((!is_at_least_gl_45) && (!is_arb_direct_state_access)) { m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported"); return STOP; } /* Running tests. */ bool is_ok = true; bool is_error = false; try { prepareFunctionPointers(); prepareTransformFeedback(); prepareBuffer(); prepareProgram(); prepareVertexArrayObject(); is_ok &= draw(); is_ok &= verifyBufferContent(); } catch (...) { is_ok = false; is_error = true; } /* Releasing GL objects. */ clean(); /* Result's setup. */ if (is_ok) { m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); } else { if (is_error) { m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error"); } else { m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); } } return STOP; } /** @brief Get access pointers to GL functions. * * @note The function may throw if unexpected error has occured. */ void FunctionalTest::prepareFunctionPointers() { /* Shortcut for GL functionality */ const glw::Functions& gl = m_context.getRenderContext().getFunctions(); /* Fetching function pointers. */ m_gl_getTransformFeedbackiv = (GetTransformFeedbackiv_ProcAddress)gl.getTransformFeedbackiv; m_gl_TransformFeedbackBufferBase = (TransformFeedbackBufferBase_ProcAddress)gl.transformFeedbackBufferBase; if ((DE_NULL == m_gl_getTransformFeedbackiv) || (DE_NULL == m_gl_TransformFeedbackBufferBase)) { m_context.getTestContext().getLog() << tcu::TestLog::Message << "Function pointers are set to NULL values." << tcu::TestLog::EndMessage; throw 0; } } /** @brief Create transform feedback object using direct access function. * * @note The function may throw if unexpected error has occured. */ void FunctionalTest::prepareTransformFeedback() { /* Shortcut for GL functionality */ const glw::Functions& gl = m_context.getRenderContext().getFunctions(); /* XFB object creation. */ gl.createTransformFeedbacks(1, &m_xfb_dsa); GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateTransformFeedbacks have failed"); } /** @brief Create buffer object and bind it to transform feedback object using direct access function. * * @note The function may throw if unexpected error has occured. */ void FunctionalTest::prepareBuffer() { /* Shortcut for GL functionality */ const glw::Functions& gl = m_context.getRenderContext().getFunctions(); /* Buffer creation and memory allocation. */ gl.genBuffers(1, &m_bo); GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers have failed"); gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer have failed"); gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, s_bo_size, DE_NULL, GL_DYNAMIC_COPY); GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData have failed"); gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer have failed"); /* Bind buffer to xfb object (using direct state access function). */ m_gl_TransformFeedbackBufferBase(m_xfb_dsa, 0, m_bo); GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackBufferBase have failed"); } /** @brief Build test's GLSL program. * * @note The function may throw if unexpected error has occured. */ void FunctionalTest::prepareProgram() { /* Shortcut for GL functionality */ const glw::Functions& gl = m_context.getRenderContext().getFunctions(); struct Shader { glw::GLchar const* const source; glw::GLenum const type; glw::GLuint id; } shader[] = { { s_vertex_shader, GL_VERTEX_SHADER, 0 }, { s_fragment_shader, GL_FRAGMENT_SHADER, 0 } }; glw::GLuint const shader_count = sizeof(shader) / sizeof(shader[0]); try { /* Create program. */ m_po = gl.createProgram(); GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram call failed."); /* Shader compilation. */ for (glw::GLuint i = 0; i < shader_count; ++i) { if (DE_NULL != shader[i].source) { shader[i].id = gl.createShader(shader[i].type); GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader call failed."); gl.attachShader(m_po, shader[i].id); GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader call failed."); gl.shaderSource(shader[i].id, 1, &(shader[i].source), NULL); GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource call failed."); gl.compileShader(shader[i].id); GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader call failed."); glw::GLint status = GL_FALSE; gl.getShaderiv(shader[i].id, GL_COMPILE_STATUS, &status); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv call failed."); if (GL_FALSE == status) { glw::GLint log_size = 0; gl.getShaderiv(shader[i].id, GL_INFO_LOG_LENGTH, &log_size); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv call failed."); glw::GLchar* log_text = new glw::GLchar[log_size]; gl.getShaderInfoLog(shader[i].id, log_size, NULL, &log_text[0]); m_context.getTestContext().getLog() << tcu::TestLog::Message << "Shader compilation has failed.\n" << "Shader type: " << glu::getShaderTypeStr(shader[i].type) << "\n" << "Shader compilation error log:\n" << log_text << "\n" << "Shader source code:\n" << shader[i].source << "\n" << tcu::TestLog::EndMessage; delete[] log_text; GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderInfoLog call failed."); throw 0; } } } /* Transform Feedback setup. */ gl.transformFeedbackVaryings(m_po, 1, &s_xfb_varying, GL_INTERLEAVED_ATTRIBS); GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings call failed."); /* Link. */ gl.linkProgram(m_po); GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings call failed."); glw::GLint status = GL_FALSE; gl.getProgramiv(m_po, GL_LINK_STATUS, &status); if (GL_TRUE == status) { for (glw::GLuint i = 0; i < shader_count; ++i) { if (shader[i].id) { gl.detachShader(m_po, shader[i].id); GLU_EXPECT_NO_ERROR(gl.getError(), "glDetachShader call failed."); } } } else { glw::GLint log_size = 0; gl.getProgramiv(m_po, GL_INFO_LOG_LENGTH, &log_size); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv call failed."); glw::GLchar* log_text = new glw::GLchar[log_size]; gl.getProgramInfoLog(m_po, log_size, NULL, &log_text[0]); m_context.getTestContext().getLog() << tcu::TestLog::Message << "Program linkage has failed due to:\n" << log_text << "\n" << tcu::TestLog::EndMessage; delete[] log_text; GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramInfoLog call failed."); throw 0; } } catch (...) { if (m_po) { gl.deleteProgram(m_po); m_po = 0; } } for (glw::GLuint i = 0; i < shader_count; ++i) { if (0 != shader[i].id) { gl.deleteShader(shader[i].id); shader[i].id = 0; } } if (m_po) { gl.useProgram(m_po); GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram call failed."); } if (0 == m_po) { throw 0; } } /** @brief Create and bind empty vertex array object. * * @note The function may throw if unexpected error has occured. */ void FunctionalTest::prepareVertexArrayObject() { /* Shortcut for GL functionality */ const glw::Functions& gl = m_context.getRenderContext().getFunctions(); /* Creating and binding empty vertex array object. */ gl.genVertexArrays(1, &m_vao); GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays call failed."); gl.bindVertexArray(m_vao); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray call failed."); } /** @brief Draw with XFB. * * @note Function follows steps: * Begin transform feedback environment. * * Using the program with discarded rasterizer, draw array of 4 indices * using POINTS. * * Pause transform feedback environment. * * Query parameter TRANSFORM_FEEDBACK_PAUSED using GetTransformFeedbackiv. * Expect value equal to TRUE. * * Query parameter TRANSFORM_FEEDBACK_ACTIVE using GetTransformFeedbackiv. * Expect value equal to TRUE. * * Resume transform feedback environment. * * Query parameter TRANSFORM_FEEDBACK_PAUSED using GetTransformFeedbackiv. * Expect value equal to FALSE. * * Query parameter TRANSFORM_FEEDBACK_ACTIVE using GetTransformFeedbackiv. * Expect value equal to TRUE. * * End Transform feedback environment. * * Query parameter TRANSFORM_FEEDBACK_ACTIVE using GetTransformFeedbackiv. * Expect value equal to FALSE. * * @note The function may throw if unexpected error has occured. * * @return True if included tests succeded, false otherwise. */ bool FunctionalTest::draw() { /* Shortcut for GL functionality */ const glw::Functions& gl = m_context.getRenderContext().getFunctions(); /* Default result. */ bool is_ok = true; /* Start transform feedback environment. */ gl.bindTransformFeedback(GL_TRANSFORM_FEEDBACK, m_xfb_dsa); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTransformFeedback call failed."); gl.beginTransformFeedback(GL_POINTS); GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback call failed."); /* Use only xfb. No rendering. */ gl.enable(GL_RASTERIZER_DISCARD); GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable(GL_RASTERIZER_DISCARD) call failed."); /* Draw. */ gl.drawArrays(GL_POINTS, 0, 4); GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays call failed."); /* Pause Transform Feedback and tests direct state queries related to paused state. */ gl.pauseTransformFeedback(); GLU_EXPECT_NO_ERROR(gl.getError(), "glPauseTransformFeedback call failed."); is_ok &= testTransformFeedbackStatus(GL_TRANSFORM_FEEDBACK_PAUSED, GL_TRUE); is_ok &= testTransformFeedbackStatus(GL_TRANSFORM_FEEDBACK_ACTIVE, GL_TRUE); /* Activate Transform Feedback and tests direct state queries related to paused state. */ gl.resumeTransformFeedback(); GLU_EXPECT_NO_ERROR(gl.getError(), "glPauseTransformFeedback call failed."); is_ok &= testTransformFeedbackStatus(GL_TRANSFORM_FEEDBACK_PAUSED, GL_FALSE); is_ok &= testTransformFeedbackStatus(GL_TRANSFORM_FEEDBACK_ACTIVE, GL_TRUE); /* Finish transform feedback. */ gl.endTransformFeedback(); GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback call failed."); is_ok &= testTransformFeedbackStatus(GL_TRANSFORM_FEEDBACK_ACTIVE, GL_FALSE); return is_ok; } /** @brief Check that selected Transform Feedback state has an expected value. * * @param [in] parameter_name Name of the parameter to be queried. * It must be GL_TRANSFORM_FEEDBACK_PAUSED or * GL_TRANSFORM_FEEDBACK_ACTIVE * @param [in] expected_value The expected value of the query. * * @note The function may throw if unexpected error has occured. * * @return True if the queried value is equal to expected value, false otherwise. */ bool FunctionalTest::testTransformFeedbackStatus(glw::GLenum parameter_name, glw::GLint expected_value) { /* Shortcut for GL functionality */ const glw::Functions& gl = m_context.getRenderContext().getFunctions(); /* Dummy storage. */ glw::GLint value = 314159; /* Test of GetTransformFeedbackiv. */ m_gl_getTransformFeedbackiv(m_xfb_dsa, parameter_name, &value); GLU_EXPECT_NO_ERROR(gl.getError(), "glGetTransformFeedbackiv call failed."); if (expected_value != value) { m_context.getTestContext().getLog() << tcu::TestLog::Message << "It was expected that glGetTransformFeedbackiv query of parameter " << ((parameter_name == GL_TRANSFORM_FEEDBACK_PAUSED) ? "GL_TRANSFORM_FEEDBACK_PAUSED" : "GL_TRANSFORM_FEEDBACK_ACTIVE") << " shall return " << ((expected_value == GL_TRUE) ? "GL_TRUE" : "GL_FALSE") << "however, " << ((value == GL_TRUE) ? "GL_TRUE" : "GL_FALSE") << " was returned." << tcu::TestLog::EndMessage; return false; } return true; } /** @brief Check that transform feedback buffer contains * consecutive integer numbers from 0 to 3 (included). * * @note The function may throw if unexpected error has occured. * * @return True if buffer conatins consecutive integer * numbers from 0 to 3 (included), false otherwise. */ bool FunctionalTest::verifyBufferContent() { /* Shortcut for GL functionality */ const glw::Functions& gl = m_context.getRenderContext().getFunctions(); /* Default result. */ bool is_ok = true; /* Mapping buffer object to the user-space. */ gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer call failed."); glw::GLint* buffer = (glw::GLint*)gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY); GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBuffer call failed."); for (glw::GLint i = 0; i < 4 /* Number of emitted vertices. */; ++i) { if (buffer[i] != i) { is_ok = false; break; } } gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER); GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer call failed."); gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0); GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer call failed."); return is_ok; } /** Release GL objects, return to the default state */ void FunctionalTest::clean() { /* Shortcut for GL functionality */ const glw::Functions& gl = m_context.getRenderContext().getFunctions(); /* Release transform feedback object. */ if (m_xfb_dsa) { gl.deleteTransformFeedbacks(1, &m_xfb_dsa); m_xfb_dsa = 0; } /* Release buffer object. */ if (m_bo) { gl.deleteBuffers(1, &m_bo); m_bo = 0; } /* Release GLSL program. */ if (m_po) { gl.useProgram(0); gl.deleteProgram(m_po); m_po = 0; } /* Release vertex array object. */ if (m_vao) { gl.bindVertexArray(0); gl.deleteVertexArrays(1, &m_vao); m_vao = 0; } /* Returning to default rasterizer state. */ gl.disable(GL_RASTERIZER_DISCARD); } const glw::GLuint FunctionalTest::s_bo_size = 4 * sizeof(glw::GLint); const glw::GLchar FunctionalTest::s_vertex_shader[] = "#version 130\n" "\n" "out int result;\n" "\n" "void main()\n" "{\n" "\n" " result = gl_VertexID;\n" " gl_Position = vec4(1.0);\n" "}\n"; const glw::GLchar FunctionalTest::s_fragment_shader[] = "#version 130\n" "\n" "out vec4 color;\n" "\n" "void main()\n" "{\n" " color = vec4(0.0, 0.0, 0.0, 1.0);\n" "}\n"; const glw::GLchar* const FunctionalTest::s_xfb_varying = "result"; } /* TransformFeedback namespace */ } /* DirectStateAccess namespace */ } /* gl4cts namespace */