blob: 026fda09af3dd0f5077271637a17a760d5b0d2c2 [file] [log] [blame]
/*-------------------------------------------------------------------------
* 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 #<index> has <expected_value>.
*
* @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 #<index> has starting offset set to the <expected_value>.
*
* @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 #<index> has size set to the <expected_value>.
*
* @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 */