blob: a3fa9a807afb20571919d11dcafd02e3335c4c3c [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 gl4cDirectStateAccessQueriesTests.cpp
* \brief Conformance tests for the Direct State Access feature functionality (Queries 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"
/* Define OpenGL enumerations not available in framework. */
#ifndef GL_QUERY_TARGET
#define GL_QUERY_TARGET 0x82EA
#endif
namespace gl4cts
{
namespace DirectStateAccess
{
namespace Queries
{
/******************************** Creation Test Implementation ********************************/
/** @brief Creation Test constructor.
*
* @param [in] context OpenGL context.
*/
CreationTest::CreationTest(deqp::Context& context)
: deqp::TestCase(context, "queries_creation", "Query Objects 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;
/* Query targets */
static const glw::GLenum targets[] = {
GL_SAMPLES_PASSED, GL_ANY_SAMPLES_PASSED, GL_ANY_SAMPLES_PASSED_CONSERVATIVE, GL_TIME_ELAPSED,
GL_TIMESTAMP, GL_PRIMITIVES_GENERATED, GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN
};
static const glw::GLuint targets_count = sizeof(targets) / sizeof(targets[0]);
/* Queries objects */
static const glw::GLuint queries_count = 2;
glw::GLuint queries_legacy[queries_count] = {};
glw::GLuint queries_dsa[targets_count][queries_count] = {};
try
{
/* Check legacy state creation. */
gl.genQueries(queries_count, queries_legacy);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenQueries have failed");
for (glw::GLuint i = 0; i < queries_count; ++i)
{
if (gl.isQuery(queries_legacy[i]))
{
is_ok = false;
/* Log. */
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "GenQueries has created default objects, but it should create only a names."
<< tcu::TestLog::EndMessage;
}
}
/* Check direct state creation. */
for (glw::GLuint i = 0; i < targets_count; ++i)
{
gl.createQueries(targets[i], queries_count, queries_dsa[i]);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateQueries have failed");
for (glw::GLuint j = 0; j < queries_count; ++j)
{
if (!gl.isQuery(queries_dsa[i][j]))
{
is_ok = false;
/* Log. */
m_context.getTestContext().getLog() << tcu::TestLog::Message
<< "CreateQueries has not created default objects."
<< tcu::TestLog::EndMessage;
}
}
}
}
catch (...)
{
is_ok = false;
is_error = true;
}
/* Cleanup. */
for (glw::GLuint j = 0; j < queries_count; ++j)
{
if (queries_legacy[j])
{
gl.deleteQueries(1, &queries_legacy[j]);
queries_legacy[j] = 0;
}
for (glw::GLuint i = 0; i < targets_count; ++i)
{
if (queries_dsa[i][j])
{
gl.deleteQueries(1, &queries_dsa[i][j]);
queries_dsa[i][j] = 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, "queries_defaults", "Queries Defaults Test"), m_query_dsa(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;
/* Query targets. */
static const glw::GLenum targets[] = {
GL_SAMPLES_PASSED, GL_ANY_SAMPLES_PASSED, GL_ANY_SAMPLES_PASSED_CONSERVATIVE, GL_TIME_ELAPSED,
GL_TIMESTAMP, GL_PRIMITIVES_GENERATED, GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN
};
static const glw::GLchar* target_names[] = {
"GL_SAMPLES_PASSED", "GL_ANY_SAMPLES_PASSED", "GL_ANY_SAMPLES_PASSED_CONSERVATIVE", "GL_TIME_ELAPSED",
"GL_TIMESTAMP", "GL_PRIMITIVES_GENERATED", "GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN"
};
static const glw::GLuint targets_count = sizeof(targets) / sizeof(targets[0]);
try
{
/* Check direct state creation. */
for (glw::GLuint i = 0; i < targets_count; ++i)
{
prepare(targets[i]);
is_ok &= testQueryParameter(GL_QUERY_RESULT, GL_FALSE, target_names[i]);
is_ok &= testQueryParameter(GL_QUERY_RESULT_AVAILABLE, GL_TRUE, target_names[i]);
clean();
}
}
catch (...)
{
is_ok = false;
is_error = true;
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 Query Objects.
*
* @note The function may throw if unexpected error has occured.
*
* @return True if test succeeded, false otherwise.
*/
void DefaultsTest::prepare(const glw::GLenum target)
{
/* Shortcut for GL functionality. */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Query object creation */
gl.createQueries(target, 1, &m_query_dsa);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateTransformFeedbacks have failed");
}
/** @brief Test Query Integer Parameter.
*
* @note The function may throw if unexpected error has occured.
*
* @param [in] pname Parameter name to be tested.
* @param [in] expected_value Expected value for comparison.
* @param [in] target_name Target name of the tested query object - for logging purposes.
*
* @return True if test succeeded, false otherwise.
*/
bool DefaultsTest::testQueryParameter(const glw::GLenum pname, const glw::GLuint expected_value,
const glw::GLchar* target_name)
{
/* Shortcut for GL functionality. */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Get data. */
glw::GLuint value = 0;
gl.getQueryObjectuiv(m_query_dsa, pname, &value);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetQueryObjectuiv have failed");
if (expected_value != value)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "glGetQueryObjectuiv of query object with target " << target_name
<< " with parameter " << pname << " has returned " << value << ", however " << expected_value
<< " was 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_query_dsa)
{
gl.deleteQueries(1, &m_query_dsa);
m_query_dsa = 0;
}
}
/******************************** Errors Test Implementation ********************************/
/** @brief Errors Test constructor.
*
* @param [in] context OpenGL context.
*/
ErrorsTest::ErrorsTest(deqp::Context& context)
: deqp::TestCase(context, "queries_errors", "Queries Errors Test")
, m_pGetQueryBufferObjectiv(DE_NULL)
, m_pGetQueryBufferObjectuiv(DE_NULL)
, m_pGetQueryBufferObjecti64v(DE_NULL)
, m_pGetQueryBufferObjectui64v(DE_NULL)
{
/* Intentionally left blank. */
}
/** @brief Iterate Errors Test cases.
*
* @return Iteration result.
*/
tcu::TestNode::IterateResult ErrorsTest::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;
}
/* Getting function pointers. */
m_pGetQueryBufferObjectiv = (PFNGLGETQUERYBUFFEROBJECT)gl.getQueryBufferObjectiv;
m_pGetQueryBufferObjectuiv = (PFNGLGETQUERYBUFFEROBJECT)gl.getQueryBufferObjectuiv;
m_pGetQueryBufferObjecti64v = (PFNGLGETQUERYBUFFEROBJECT)gl.getQueryBufferObjecti64v;
m_pGetQueryBufferObjectui64v = (PFNGLGETQUERYBUFFEROBJECT)gl.getQueryBufferObjectui64v;
/* Running tests. */
bool is_ok = true;
bool is_error = false;
try
{
if ((DE_NULL == m_pGetQueryBufferObjectiv) || (DE_NULL == m_pGetQueryBufferObjectuiv) ||
(DE_NULL == m_pGetQueryBufferObjecti64v) || (DE_NULL == m_pGetQueryBufferObjectui64v))
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "Test could not get the pointers for glGetQueryBufferObject* functions."
<< tcu::TestLog::EndMessage;
throw 0;
}
is_ok &= testNegativeNumberOfObjects();
is_ok &= testInvalidTarget();
is_ok &= testInvalidQueryName();
is_ok &= testInvalidBufferName();
is_ok &= testInvalidParameterName();
is_ok &= testBufferOverflow();
is_ok &= testBufferNegativeOffset();
}
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 Check that CreateQueries generates INVALID_VALUE
* error if number of query objects to create is
* negative.
*
* @return True if test succeded, false otherwise.
*/
bool ErrorsTest::testNegativeNumberOfObjects()
{
/* Shortcut for GL functionality. */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Test for each target. */
for (glw::GLuint i = 0; i < s_targets_count; ++i)
{
glw::GLuint query = 0;
gl.createQueries(s_targets[i], -1, &query); /* Create negative number of queries. */
glw::GLenum error = gl.getError();
if (GL_INVALID_VALUE != error)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "glCreateQueries called with target " << s_target_names[i]
<< " with negative number of objects to be created (-1) has generated error " << glu::getErrorStr(error)
<< ", however GL_INVALID_VALUE was expected." << tcu::TestLog::EndMessage;
if (query)
{
gl.deleteQueries(1, &query);
while (error == gl.getError())
;
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "glCreateQueries called with target " << s_target_names[i]
<< " with negative number of objects to be created (-1) has created at least one object."
<< tcu::TestLog::EndMessage;
}
return false;
}
}
return true;
}
/** @brief Check that CreateQueries generates INVALID_ENUM error if target is not
* one of accepted values:
* - SAMPLES_PASSED,
* - ANY_SAMPLES_PASSED,
* - ANY_SAMPLES_PASSED_CONSERVATIVE,
* - TIME_ELAPSED,
* - TIMESTAMP,
* - PRIMITIVES_GENERATED or
* - TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN.
*
* @return True if test succeded, false otherwise.
*/
bool ErrorsTest::testInvalidTarget()
{
/* Shortcut for GL functionality. */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Creating invalid target. */
glw::GLenum invalid_target = 0;
while (isTarget(++invalid_target))
;
/* Test. */
glw::GLuint query = 0;
gl.createQueries(invalid_target, 1, &query); /* Create negative number of queries. */
glw::GLenum error = gl.getError();
if (GL_INVALID_ENUM != error)
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << "glCreateQueries called with invalid target ("
<< invalid_target << ") has generated error " << glu::getErrorStr(error)
<< ", however GL_INVALID_ENUM was expected." << tcu::TestLog::EndMessage;
if (query)
{
gl.deleteQueries(1, &query);
while (error == gl.getError())
;
m_context.getTestContext().getLog() << tcu::TestLog::Message
<< "glCreateQueries called with invalid target (" << invalid_target
<< ") has created an object." << tcu::TestLog::EndMessage;
}
return false;
}
return true;
}
/** @brief Check that GetQueryBufferObjectiv, GetQueryBufferObjectuiv,
* GetQueryBufferObjecti64v and GetQueryBufferObjectui64v generate
* INVALID_OPERATION error if <id> is not the name of a query object, or
* if the query object named by <id> is currently active.
*
* @return True if test succeded, false otherwise.
*/
bool ErrorsTest::testInvalidQueryName()
{
/* Shortcut for GL functionality. */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Creating invalid query name. */
glw::GLuint invalid_query = 0;
/* Default result. */
bool is_ok = true;
bool is_error = false;
while (gl.isQuery(++invalid_query))
;
/* Test's objects. */
glw::GLuint buffer = 0;
glw::GLuint query = 0;
try
{
/* Creating buffer for the test. */
gl.genBuffers(1, &buffer);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers have failed");
gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, buffer);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffers have failed");
gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(glw::GLint64), DE_NULL, GL_DYNAMIC_COPY);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffers have failed");
/* Test invalid query object name (integer version). */
m_pGetQueryBufferObjectiv(invalid_query, buffer, GL_QUERY_RESULT, 0);
glw::GLenum error = gl.getError();
if (GL_INVALID_OPERATION != error)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "glGetQueryBufferObjectiv called with invalid query name has generated error "
<< glu::getErrorStr(error) << ", however GL_INVALID_OPERATION was expected."
<< tcu::TestLog::EndMessage;
is_ok = false;
}
/* Test invalid query object name (unsigned integer version). */
m_pGetQueryBufferObjectuiv(invalid_query, buffer, GL_QUERY_RESULT, 0);
error = gl.getError();
if (GL_INVALID_OPERATION != error)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "glGetQueryBufferObjectuiv called with invalid query name has generated error "
<< glu::getErrorStr(error) << ", however GL_INVALID_OPERATION was expected."
<< tcu::TestLog::EndMessage;
is_ok = false;
}
/* Test invalid query object name (64-bit integer version). */
m_pGetQueryBufferObjecti64v(invalid_query, buffer, GL_QUERY_RESULT, 0);
error = gl.getError();
if (GL_INVALID_OPERATION != error)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "glGetQueryBufferObjecti64v called with invalid query name has generated error "
<< glu::getErrorStr(error) << ", however GL_INVALID_OPERATION was expected."
<< tcu::TestLog::EndMessage;
is_ok = false;
}
/* Test invalid query object name (64-bit unsigned integer version). */
m_pGetQueryBufferObjectui64v(invalid_query, buffer, GL_QUERY_RESULT, 0);
error = gl.getError();
if (GL_INVALID_OPERATION != error)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "glGetQueryBufferObjectui64v called with invalid query name has generated error "
<< glu::getErrorStr(error) << ", however GL_INVALID_OPERATION was expected."
<< tcu::TestLog::EndMessage;
is_ok = false;
}
/* Create query object for the test. */
gl.createQueries(s_targets[0], 1, &query);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateQueries have failed");
gl.beginQuery(s_targets[0], query);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateQueries have failed");
/* Test query of active query object name (integer version). */
m_pGetQueryBufferObjectiv(query, buffer, GL_QUERY_RESULT, 0);
error = gl.getError();
if (GL_INVALID_OPERATION != error)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "glGetQueryBufferObjectiv called with active query object has generated error "
<< glu::getErrorStr(error) << ", however GL_INVALID_OPERATION was expected."
<< tcu::TestLog::EndMessage;
is_ok = false;
}
/* Test query of active query object name (unsigned integer version). */
m_pGetQueryBufferObjectuiv(query, buffer, GL_QUERY_RESULT, 0);
error = gl.getError();
if (GL_INVALID_OPERATION != error)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "glGetQueryBufferObjectuiv called with active query object has generated error "
<< glu::getErrorStr(error) << ", however GL_INVALID_OPERATION was expected."
<< tcu::TestLog::EndMessage;
is_ok = false;
}
/* Test query of active query object name (64-bit integer version). */
m_pGetQueryBufferObjecti64v(query, buffer, GL_QUERY_RESULT, 0);
error = gl.getError();
if (GL_INVALID_OPERATION != error)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "glGetQueryBufferObjecti64v called with active query object has generated error "
<< glu::getErrorStr(error) << ", however GL_INVALID_OPERATION was expected."
<< tcu::TestLog::EndMessage;
is_ok = false;
}
/* Test query of active query object name (64-bit unsigned integer version). */
m_pGetQueryBufferObjectui64v(query, buffer, GL_QUERY_RESULT, 0);
error = gl.getError();
if (GL_INVALID_OPERATION != error)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "glGetQueryBufferObjectui64v called with active query object has generated error "
<< glu::getErrorStr(error) << ", however GL_INVALID_OPERATION was expected."
<< tcu::TestLog::EndMessage;
is_ok = false;
}
}
catch (...)
{
is_error = true;
}
/* Releasing objects. */
if (query)
{
gl.endQuery(s_targets[0]);
gl.deleteQueries(1, &query);
}
if (buffer)
{
gl.deleteBuffers(1, &buffer);
}
/* Error cleanup. */
while (gl.getError())
;
if (is_error)
{
throw 0;
}
return is_ok;
}
/** @brief Check that GetQueryBufferObjectiv, GetQueryBufferObjectuiv,
* GetQueryBufferObjecti64v and GetQueryBufferObjectui64v generate
* INVALID_OPERATION error if <buffer> is not the name of an existing
* buffer object.
*
* @return True if test succeded, false otherwise.
*/
bool ErrorsTest::testInvalidBufferName()
{
/* Shortcut for GL functionality. */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Default result. */
bool is_ok = true;
bool is_error = false;
/* Creating invalid buffer name. */
glw::GLuint invalid_buffer = 0;
while (gl.isBuffer(++invalid_buffer))
;
/* Test's objects. */
glw::GLuint query = 0;
try
{
/* Create query object for the test. */
gl.createQueries(s_targets[0], 1, &query);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateQueries have failed");
/* Test query of invalid buffer name (integer version). */
m_pGetQueryBufferObjectiv(query, invalid_buffer, GL_QUERY_RESULT_AVAILABLE, 0);
glw::GLenum error = gl.getError();
if (GL_INVALID_OPERATION != error)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "glGetQueryBufferObjectiv which could generate buffers overflow generated error "
<< glu::getErrorStr(error) << ", however GL_INVALID_OPERATION was expected."
<< tcu::TestLog::EndMessage;
is_ok = false;
}
/* Test query of invalid buffer name (unsigned integer version). */
m_pGetQueryBufferObjectuiv(query, invalid_buffer, GL_QUERY_RESULT_AVAILABLE, 0);
error = gl.getError();
if (GL_INVALID_OPERATION != error)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "glGetQueryBufferObjectuiv which could generate buffers overflow generated error "
<< glu::getErrorStr(error) << ", however GL_INVALID_OPERATION was expected."
<< tcu::TestLog::EndMessage;
is_ok = false;
}
/* Test query of invalid buffer name (64-bit integer version). */
m_pGetQueryBufferObjecti64v(query, invalid_buffer, GL_QUERY_RESULT_AVAILABLE, 0);
error = gl.getError();
if (GL_INVALID_OPERATION != error)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "glGetQueryBufferObjecti64v which could generate buffers overflow generated error "
<< glu::getErrorStr(error) << ", however GL_INVALID_OPERATION was expected."
<< tcu::TestLog::EndMessage;
is_ok = false;
}
/* Test query of invalid buffer name (64-bit unsigned integer version). */
m_pGetQueryBufferObjectui64v(query, invalid_buffer, GL_QUERY_RESULT_AVAILABLE, 0);
error = gl.getError();
if (GL_INVALID_OPERATION != error)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "glGetQueryBufferObjectui64v which could generate buffers overflow generated error "
<< glu::getErrorStr(error) << ", however GL_INVALID_OPERATION was expected."
<< tcu::TestLog::EndMessage;
is_ok = false;
}
}
catch (...)
{
is_error = true;
}
/* Releasing objects. */
if (query)
{
gl.deleteQueries(1, &query);
}
/* Error cleanup. */
while (gl.getError())
;
if (is_error)
{
throw 0;
}
return is_ok;
}
/** @brief Check that GetQueryBufferObjectiv, GetQueryBufferObjectuiv,
* GetQueryBufferObjecti64v and GetQueryBufferObjectui64v generate
* INVALID_ENUM error if <pname> is not QUERY_RESULT,
* QUERY_RESULT_AVAILABLE, QUERY_RESULT_NO_WAIT or QUERY_TARGET.
*
* @return True if test succeded, false otherwise.
*/
bool ErrorsTest::testInvalidParameterName()
{
/* Shortcut for GL functionality. */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Creating invalid parameter name. */
glw::GLuint invalid_pname = 0;
while (isParameterName(++invalid_pname))
;
/* Default result. */
bool is_ok = true;
bool is_error = false;
/* Test's objects. */
glw::GLuint buffer = 0;
glw::GLuint query = 0;
try
{
/* Creating buffer for the test. */
gl.genBuffers(1, &buffer);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers have failed");
gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, buffer);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffers have failed");
gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(glw::GLint64), DE_NULL, GL_DYNAMIC_COPY);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffers have failed");
/* Create query object for the test. */
gl.createQueries(s_targets[0], 1, &query);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateQueries have failed");
/* Test query of invalid parameter name (integer version). */
m_pGetQueryBufferObjectiv(query, buffer, invalid_pname, 0);
glw::GLenum error = gl.getError();
if (GL_INVALID_ENUM != error)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "glGetQueryBufferObjectiv called with invalid parameter name has generated error "
<< glu::getErrorStr(error) << ", however GL_INVALID_ENUM was expected." << tcu::TestLog::EndMessage;
is_ok = false;
}
/* Test query of invalid parameter name (unsigned integer version). */
m_pGetQueryBufferObjectuiv(query, buffer, invalid_pname, 0);
error = gl.getError();
if (GL_INVALID_ENUM != error)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "glGetQueryBufferObjectuiv called with invalid parameter name has generated error "
<< glu::getErrorStr(error) << ", however GL_INVALID_ENUM was expected." << tcu::TestLog::EndMessage;
is_ok = false;
}
/* Test query of invalid parameter name (64-bit integer version). */
m_pGetQueryBufferObjecti64v(query, buffer, invalid_pname, 0);
error = gl.getError();
if (GL_INVALID_ENUM != error)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "glGetQueryBufferObjecti64v called with invalid parameter name has generated error "
<< glu::getErrorStr(error) << ", however GL_INVALID_ENUM was expected." << tcu::TestLog::EndMessage;
is_ok = false;
}
/* Test query of invalid parameter name (64-bit unsigned integer version). */
m_pGetQueryBufferObjectui64v(query, buffer, invalid_pname, 0);
error = gl.getError();
if (GL_INVALID_ENUM != error)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "glGetQueryBufferObjectui64v called with invalid parameter name has generated error "
<< glu::getErrorStr(error) << ", however GL_INVALID_ENUM was expected." << tcu::TestLog::EndMessage;
is_ok = false;
}
}
catch (...)
{
is_error = true;
}
/* Releasing objects. */
if (query)
{
gl.deleteQueries(1, &query);
}
if (buffer)
{
gl.deleteBuffers(1, &buffer);
}
/* Error cleanup. */
while (gl.getError())
;
if (is_error)
{
throw 0;
}
return is_ok;
}
/** @brief Check that GetQueryBufferObjectiv, GetQueryBufferObjectuiv,
* GetQueryBufferObjecti64v and GetQueryBufferObjectui64v generate
* INVALID_OPERATION error if the query writes to a buffer object, and the
* specified buffer offset would cause data to be written beyond the bounds
* of that buffer object.
*
* @return True if test succeded, false otherwise.
*/
bool ErrorsTest::testBufferOverflow()
{
/* Shortcut for GL functionality. */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Default result. */
bool is_ok = true;
bool is_error = false;
/* Test's objects. */
glw::GLuint buffer = 0;
glw::GLuint query = 0;
try
{
/* Creating buffer for the test. */
gl.genBuffers(1, &buffer);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers have failed");
gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, buffer);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffers have failed");
gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(glw::GLint64), DE_NULL, GL_DYNAMIC_COPY);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffers have failed");
/* Create query object for the test. */
gl.createQueries(s_targets[0], 1, &query);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateQueries have failed");
/* Test query of buffer overflow (integer version). */
m_pGetQueryBufferObjectiv(query, buffer, GL_QUERY_RESULT_AVAILABLE, sizeof(glw::GLint64));
glw::GLenum error = gl.getError();
if (GL_INVALID_OPERATION != error)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "glGetQueryBufferObjectiv which could generate buffers overflow generated error "
<< glu::getErrorStr(error) << ", however GL_INVALID_OPERATION was expected."
<< tcu::TestLog::EndMessage;
is_ok = false;
}
/* Test query of buffer overflow (unsigned integer version). */
m_pGetQueryBufferObjectuiv(query, buffer, GL_QUERY_RESULT_AVAILABLE, sizeof(glw::GLint64));
error = gl.getError();
if (GL_INVALID_OPERATION != error)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "glGetQueryBufferObjectuiv which could generate buffers overflow generated error "
<< glu::getErrorStr(error) << ", however GL_INVALID_OPERATION was expected."
<< tcu::TestLog::EndMessage;
is_ok = false;
}
/* Test query of buffer overflow (64-bit integer version). */
m_pGetQueryBufferObjecti64v(query, buffer, GL_QUERY_RESULT_AVAILABLE, sizeof(glw::GLint64));
error = gl.getError();
if (GL_INVALID_OPERATION != error)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "glGetQueryBufferObjecti64v which could generate buffers overflow generated error "
<< glu::getErrorStr(error) << ", however GL_INVALID_OPERATION was expected."
<< tcu::TestLog::EndMessage;
is_ok = false;
}
/* Test query of buffer overflow (64-bit unsigned integer version). */
m_pGetQueryBufferObjectui64v(query, buffer, GL_QUERY_RESULT_AVAILABLE, sizeof(glw::GLint64));
error = gl.getError();
if (GL_INVALID_OPERATION != error)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "glGetQueryBufferObjectui64v which could generate buffers overflow generated error "
<< glu::getErrorStr(error) << ", however GL_INVALID_OPERATION was expected."
<< tcu::TestLog::EndMessage;
is_ok = false;
}
}
catch (...)
{
is_error = true;
}
/* Releasing objects. */
if (query)
{
gl.deleteQueries(1, &query);
}
if (buffer)
{
gl.deleteBuffers(1, &buffer);
}
/* Error cleanup. */
while (gl.getError())
;
if (is_error)
{
throw 0;
}
return is_ok;
}
/** @brief Check that GetQueryBufferObjectiv, GetQueryBufferObjectuiv,
* GetQueryBufferObjecti64v and GetQueryBufferObjectui64v generate
* INVALID_VALUE error if <offset> is negative.
*
* @return True if test succeded, false otherwise.
*/
bool ErrorsTest::testBufferNegativeOffset()
{
/* Shortcut for GL functionality. */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Default result. */
bool is_ok = true;
bool is_error = false;
/* Test's objects. */
glw::GLuint buffer = 0;
glw::GLuint query = 0;
try
{
/* Creating buffer for the test. */
gl.genBuffers(1, &buffer);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers have failed");
gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, buffer);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffers have failed");
gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(glw::GLint64), DE_NULL, GL_DYNAMIC_COPY);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffers have failed");
/* Create query object for the test. */
gl.createQueries(s_targets[0], 1, &query);
GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateQueries have failed");
/* Test query with negative offset (integer version). */
m_pGetQueryBufferObjectiv(query, buffer, GL_QUERY_RESULT_AVAILABLE, -1);
glw::GLenum error = gl.getError();
if (GL_INVALID_VALUE != error)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "glGetQueryBufferObjectiv called with negative offset generated error "
<< glu::getErrorStr(error) << ", however GL_INVALID_VALUE was expected." << tcu::TestLog::EndMessage;
is_ok = false;
}
/* Test query with negative offset (unsigned integer version). */
m_pGetQueryBufferObjectuiv(query, buffer, GL_QUERY_RESULT_AVAILABLE, -1);
error = gl.getError();
if (GL_INVALID_VALUE != error)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "glGetQueryBufferObjectuiv called with negative offset generated error "
<< glu::getErrorStr(error) << ", however GL_INVALID_VALUE was expected." << tcu::TestLog::EndMessage;
is_ok = false;
}
/* Test query with negative offset (64-bit integer version). */
m_pGetQueryBufferObjecti64v(query, buffer, GL_QUERY_RESULT_AVAILABLE, -1);
error = gl.getError();
if (GL_INVALID_VALUE != error)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "glGetQueryBufferObjecti64v called with negative offset generated error "
<< glu::getErrorStr(error) << ", however GL_INVALID_VALUE was expected." << tcu::TestLog::EndMessage;
is_ok = false;
}
/* Test query with negative offset (64-bit unsigned integer version). */
m_pGetQueryBufferObjectui64v(query, buffer, GL_QUERY_RESULT_AVAILABLE, -1);
error = gl.getError();
if (GL_INVALID_VALUE != error)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "glGetQueryBufferObjectui64v called with negative offset generated error "
<< glu::getErrorStr(error) << ", however GL_INVALID_VALUE was expected." << tcu::TestLog::EndMessage;
is_ok = false;
}
}
catch (...)
{
is_error = true;
}
/* Releasing objects. */
if (query)
{
gl.deleteQueries(1, &query);
}
if (buffer)
{
gl.deleteBuffers(1, &buffer);
}
/* Error cleanup. */
while (gl.getError())
;
if (is_error)
{
throw 0;
}
return is_ok;
}
/** @brief Check if argument is one of the target names:
* - SAMPLES_PASSED,
* - TIME_ELAPSED,
* - PRIMITIVES_GENERATED,
* - TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN.
*
* @param [in] maybe_target Target to be checked.
*
* @return True if argument is one of the listed targets, false otherwise.
*/
bool ErrorsTest::isTarget(glw::GLenum maybe_target)
{
for (glw::GLuint i = 0; i < s_targets_count; ++i)
{
if (maybe_target == s_targets[i])
{
return true;
}
}
return false;
}
/** @brief Check if argument is one of the parameter names:
* - QUERY_RESULT,
* - QUERY_RESULT_AVAILABLE,
* - QUERY_RESULT_NO_WAIT,
* - QUERY_TARGET.
*
* @param [in] maybe_pname Parameter name to be checked.
*
* @return True if argument is one of the listed parameters, false otherwise.
*/
bool ErrorsTest::isParameterName(glw::GLenum maybe_pname)
{
glw::GLenum pnames[] = { GL_QUERY_RESULT, GL_QUERY_RESULT_AVAILABLE, GL_QUERY_RESULT_NO_WAIT, GL_QUERY_TARGET };
glw::GLuint pnames_count = sizeof(pnames) / sizeof(pnames[0]);
for (glw::GLuint i = 0; i < pnames_count; ++i)
{
if (maybe_pname == pnames[i])
{
return true;
}
}
return false;
}
/** Targets to be tested. */
const glw::GLenum ErrorsTest::s_targets[] = {
GL_SAMPLES_PASSED, GL_ANY_SAMPLES_PASSED, GL_ANY_SAMPLES_PASSED_CONSERVATIVE, GL_TIME_ELAPSED,
GL_TIMESTAMP, GL_PRIMITIVES_GENERATED, GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN
};
/** Names of targets to be tested. */
const glw::GLchar* ErrorsTest::s_target_names[] = {
"GL_SAMPLES_PASSED", "GL_ANY_SAMPLES_PASSED", "GL_ANY_SAMPLES_PASSED_CONSERVATIVE", "GL_TIME_ELAPSED",
"GL_TIMESTAMP", "GL_PRIMITIVES_GENERATED", "GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN"
};
/** Number of targets. */
const glw::GLuint ErrorsTest::s_targets_count = sizeof(s_targets) / sizeof(s_targets[0]);
/******************************** Functional Test Implementation ********************************/
/** @brief Functional Test constructor.
*
* @param [in] context OpenGL context.
*/
FunctionalTest::FunctionalTest(deqp::Context& context)
: deqp::TestCase(context, "queries_functional", "Queries Functional Test")
, m_pGetQueryBufferObjectiv(DE_NULL)
, m_pGetQueryBufferObjectuiv(DE_NULL)
, m_pGetQueryBufferObjecti64v(DE_NULL)
, m_pGetQueryBufferObjectui64v(DE_NULL)
, m_fbo(0)
, m_rbo(0)
, m_vao(0)
, m_bo_query(0)
, m_bo_xfb(0)
, m_qo(DE_NULL)
, m_po(0)
{
/* Intentionally left blank. */
}
/** @brief Do comparison (a == b).
*
* @tparam Type of the values to be compared.
*
* @param [in] a First value to be compared.
* @param [in] b Second value to be compared.
*
* @return Result of the comparison.
*/
template <typename T>
bool FunctionalTest::equal(T a, T b)
{
return (a == b);
}
/** @brief Do comparison (a < b).
*
* @tparam Type of the values to be compared.
*
* @param [in] a First value to be compared.
* @param [in] b Second value to be compared.
*
* @return Result of the comparison.
*/
template <typename T>
bool FunctionalTest::less(T a, T b)
{
return (a < b);
}
/** @brief Template specialization of glGetQueryBufferObject* function for GLint.
* This is pass through function to glGetQueryBufferObjectiv
*
* @param [in] id Query object identifier.
* @param [in] buffer Buffer object identifier.
* @param [in] pname Parameter name to be queried.
* @param [in] offset Offset of the buffer to be saved at.
*/
template <>
void FunctionalTest::GetQueryBufferObject<glw::GLint>(glw::GLuint id, glw::GLuint buffer, glw::GLenum pname,
glw::GLintptr offset)
{
m_pGetQueryBufferObjectiv(id, buffer, pname, offset);
}
/** @brief Template specialization of glGetQueryBufferObject* function for GLuint.
* This is pass through function to glGetQueryBufferObjectuiv
*
* @param [in] id Query object identifier.
* @param [in] buffer Buffer object identifier.
* @param [in] pname Parameter name to be queried.
* @param [in] offset Offset of the buffer to be saved at.
*/
template <>
void FunctionalTest::GetQueryBufferObject<glw::GLuint>(glw::GLuint id, glw::GLuint buffer, glw::GLenum pname,
glw::GLintptr offset)
{
m_pGetQueryBufferObjectuiv(id, buffer, pname, offset);
}
/** @brief Template specialization of glGetQueryBufferObject* function for GLint64.
* This is pass through function to glGetQueryBufferObjecti64v
*
* @param [in] id Query object identifier.
* @param [in] buffer Buffer object identifier.
* @param [in] pname Parameter name to be queried.
* @param [in] offset Offset of the buffer to be saved at.
*/
template <>
void FunctionalTest::GetQueryBufferObject<glw::GLint64>(glw::GLuint id, glw::GLuint buffer, glw::GLenum pname,
glw::GLintptr offset)
{
m_pGetQueryBufferObjecti64v(id, buffer, pname, offset);
}
/** @brief Template specialization of glGetQueryBufferObject* function for GLuint64.
* This is pass through function to glGetQueryBufferObjectui64v
*
* @param [in] id Query object identifier.
* @param [in] buffer Buffer object identifier.
* @param [in] pname Parameter name to be queried.
* @param [in] offset Offset of the buffer to be saved at.
*/
template <>
void FunctionalTest::GetQueryBufferObject<glw::GLuint64>(glw::GLuint id, glw::GLuint buffer, glw::GLenum pname,
glw::GLintptr offset)
{
m_pGetQueryBufferObjectui64v(id, buffer, pname, offset);
}
/** @brief Function template fetches query result to buffer object using
* glGetQueryBufferObject* function (selected on the basis of template parameter).
* Then buffer is mapped and the result is compared with expected_value using comparison function.
*
* @tparam Templated type of fetched data.
* It shall be one of glw::GL[u]int[64].
*
* @param [in] query Query object to be queried.
* @param [in] pname Parameter name to be queried.
* @param [in] expected_value Reference value to be compared.
* @param [in] comparison Comparison function pointer.
* Comparsion function shall NOT throw.
*
* @note The function may throw if unexpected error has occured.
*
* @return True if comparison succeeded, false otherwise.
*/
template <typename T>
bool FunctionalTest::checkQueryBufferObject(glw::GLuint query, glw::GLenum pname, T expected_value,
bool (*comparison)(T, T))
{
/* Shortcut for GL functionality. */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Default result. */
bool is_ok = true;
/* Saving results to buffer. */
GetQueryBufferObject<T>(query, m_bo_query, pname, 0);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGetQueryBufferObject* have failed");
/* Mapping buffer to user space. */
T* value = (T*)gl.mapBuffer(GL_QUERY_BUFFER, GL_READ_ONLY);
GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBuffer have failed");
/* Doing test. */
if (!comparison(expected_value, *value))
{
is_ok = false;
}
/* Cleanup. */
gl.unmapBuffer(GL_QUERY_BUFFER);
GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer have failed");
/* Return test result. */
return is_ok;
}
/** @brief Iterate Functional Test cases.
*
* @return Iteration result.
*/
tcu::TestNode::IterateResult FunctionalTest::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;
}
/* Fetching access point to GL functions. */
m_pGetQueryBufferObjectiv = (PFNGLGETQUERYBUFFEROBJECT)gl.getQueryBufferObjectiv;
m_pGetQueryBufferObjectuiv = (PFNGLGETQUERYBUFFEROBJECT)gl.getQueryBufferObjectuiv;
m_pGetQueryBufferObjecti64v = (PFNGLGETQUERYBUFFEROBJECT)gl.getQueryBufferObjecti64v;
m_pGetQueryBufferObjectui64v = (PFNGLGETQUERYBUFFEROBJECT)gl.getQueryBufferObjectui64v;
/* Running tests. */
bool is_ok = true;
bool is_error = false;
try
{
if ((DE_NULL == m_pGetQueryBufferObjectiv) || (DE_NULL == m_pGetQueryBufferObjectuiv) ||
(DE_NULL == m_pGetQueryBufferObjecti64v) || (DE_NULL == m_pGetQueryBufferObjectui64v))
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "Test could not get the pointers for glGetQueryBufferObject* functions."
<< tcu::TestLog::EndMessage;
throw 0;
}
prepareView();
prepareVertexArray();
prepareBuffers();
prepareQueries();
prepareProgram();
draw();
/* Make sure that framebuffer and transform feedback buffer are filled with expectd data. */
is_ok &= checkView();
is_ok &= checkXFB();
/* Make comparisons for each query object. */
for (glw::GLuint i = 0; i < s_targets_count; ++i)
{
/* Checking targets. */
is_ok &= checkQueryBufferObject<glw::GLint>(m_qo[i], GL_QUERY_TARGET, s_targets[i],
&FunctionalTest::equal<glw::GLint>);
is_ok &= checkQueryBufferObject<glw::GLuint>(m_qo[i], GL_QUERY_TARGET, s_targets[i],
&FunctionalTest::equal<glw::GLuint>);
is_ok &= checkQueryBufferObject<glw::GLint64>(m_qo[i], GL_QUERY_TARGET, s_targets[i],
&FunctionalTest::equal<glw::GLint64>);
is_ok &= checkQueryBufferObject<glw::GLuint64>(m_qo[i], GL_QUERY_TARGET, s_targets[i],
&FunctionalTest::equal<glw::GLuint64>);
/* Checking result availability. */
is_ok &= checkQueryBufferObject<glw::GLint>(m_qo[i], GL_QUERY_RESULT_AVAILABLE, GL_TRUE,
&FunctionalTest::equal<glw::GLint>);
is_ok &= checkQueryBufferObject<glw::GLuint>(m_qo[i], GL_QUERY_RESULT_AVAILABLE, GL_TRUE,
&FunctionalTest::equal<glw::GLuint>);
is_ok &= checkQueryBufferObject<glw::GLint64>(m_qo[i], GL_QUERY_RESULT_AVAILABLE, GL_TRUE,
&FunctionalTest::equal<glw::GLint64>);
is_ok &= checkQueryBufferObject<glw::GLuint64>(m_qo[i], GL_QUERY_RESULT_AVAILABLE, GL_TRUE,
&FunctionalTest::equal<glw::GLuint64>);
if (GL_TIME_ELAPSED == s_targets[i])
{
/* Checking result. */
is_ok &= checkQueryBufferObject<glw::GLint>(m_qo[i], GL_QUERY_RESULT, (glw::GLint)s_results[i],
&FunctionalTest::less<glw::GLint>);
is_ok &= checkQueryBufferObject<glw::GLuint>(m_qo[i], GL_QUERY_RESULT, (glw::GLuint)s_results[i],
&FunctionalTest::less<glw::GLuint>);
is_ok &= checkQueryBufferObject<glw::GLint64>(m_qo[i], GL_QUERY_RESULT, (glw::GLint64)s_results[i],
&FunctionalTest::less<glw::GLint64>);
is_ok &= checkQueryBufferObject<glw::GLuint64>(m_qo[i], GL_QUERY_RESULT, (glw::GLuint64)s_results[i],
&FunctionalTest::less<glw::GLuint64>);
/* Checking result (no-wait). */
is_ok &= checkQueryBufferObject<glw::GLint>(m_qo[i], GL_QUERY_RESULT_NO_WAIT, (glw::GLint)s_results[i],
&FunctionalTest::less<glw::GLint>);
is_ok &= checkQueryBufferObject<glw::GLuint>(
m_qo[i], GL_QUERY_RESULT_NO_WAIT, (glw::GLuint)s_results[i], &FunctionalTest::less<glw::GLuint>);
is_ok &= checkQueryBufferObject<glw::GLint64>(
m_qo[i], GL_QUERY_RESULT_NO_WAIT, (glw::GLint64)s_results[i], &FunctionalTest::less<glw::GLint64>);
is_ok &=
checkQueryBufferObject<glw::GLuint64>(m_qo[i], GL_QUERY_RESULT_NO_WAIT, (glw::GLuint64)s_results[i],
&FunctionalTest::less<glw::GLuint64>);
}
else
{
/* Checking result. */
is_ok &= checkQueryBufferObject<glw::GLint>(m_qo[i], GL_QUERY_RESULT, (glw::GLint)s_results[i],
&FunctionalTest::equal<glw::GLint>);
is_ok &= checkQueryBufferObject<glw::GLuint>(m_qo[i], GL_QUERY_RESULT, (glw::GLuint)s_results[i],
&FunctionalTest::equal<glw::GLuint>);
is_ok &= checkQueryBufferObject<glw::GLint64>(m_qo[i], GL_QUERY_RESULT, (glw::GLint64)s_results[i],
&FunctionalTest::equal<glw::GLint64>);
is_ok &= checkQueryBufferObject<glw::GLuint64>(m_qo[i], GL_QUERY_RESULT, (glw::GLuint64)s_results[i],
&FunctionalTest::equal<glw::GLuint64>);
/* Checking result (no-wait). */
is_ok &= checkQueryBufferObject<glw::GLint>(m_qo[i], GL_QUERY_RESULT_NO_WAIT, (glw::GLint)s_results[i],
&FunctionalTest::equal<glw::GLint>);
is_ok &= checkQueryBufferObject<glw::GLuint>(
m_qo[i], GL_QUERY_RESULT_NO_WAIT, (glw::GLuint)s_results[i], &FunctionalTest::equal<glw::GLuint>);
is_ok &= checkQueryBufferObject<glw::GLint64>(
m_qo[i], GL_QUERY_RESULT_NO_WAIT, (glw::GLint64)s_results[i], &FunctionalTest::equal<glw::GLint64>);
is_ok &=
checkQueryBufferObject<glw::GLuint64>(m_qo[i], GL_QUERY_RESULT_NO_WAIT, (glw::GLuint64)s_results[i],
&FunctionalTest::equal<glw::GLuint64>);
}
}
}
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 Function prepares framebuffer with RGBA8 color attachment.
* Viewport is set up. Content of the framebuffer is cleared.
*
* @note The function may throw if unexpected error has occured.
*/
void FunctionalTest::prepareView()
{
/* Shortcut for GL functionality. */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Prepare framebuffer. */
gl.genFramebuffers(1, &m_fbo);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers call failed.");
gl.genRenderbuffers(1, &m_rbo);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenRenderbuffers call failed.");
gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer call failed.");
gl.bindRenderbuffer(GL_RENDERBUFFER, m_rbo);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindRenderbuffer call failed.");
gl.renderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 1 /* x size */, 1 /* y size */);
GLU_EXPECT_NO_ERROR(gl.getError(), "glRenderbufferStorage call failed.");
gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_rbo);
GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferRenderbuffer call failed.");
if (gl.checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
{
throw 0;
}
gl.viewport(0, 0, 1, 1);
GLU_EXPECT_NO_ERROR(gl.getError(), "glViewport call failed.");
/* Clear framebuffer's content. */
gl.clearColor(0.0f, 0.0f, 0.0f, 0.0f);
GLU_EXPECT_NO_ERROR(gl.getError(), "glClearColor call failed.");
gl.clear(GL_COLOR_BUFFER_BIT);
GLU_EXPECT_NO_ERROR(gl.getError(), "glClear call failed.");
}
/** @brief Function creates and binds empty vertex array.
*
* @note The function may throw if unexpected error has occured.
*/
void FunctionalTest::prepareVertexArray()
{
/* Shortcut for GL functionality. */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Creating and binding VAO. */
gl.genVertexArrays(1, &m_vao);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays have failed");
gl.bindVertexArray(m_vao);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray have failed");
}
/** @brief Function creates buffers for query and transform feedback data storage.
* The storage is allocated and buffers are bound to QUERY_BUFFER and
* TRANSFORM_FEEDBACK_BUFFER binding points respectively.
*
* @note The function may throw if unexpected error has occured.
*/
void FunctionalTest::prepareBuffers()
{
/* Shortcut for GL functionality. */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Buffer for storing query's result. */
gl.genBuffers(1, &m_bo_query);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers have failed");
gl.bindBuffer(GL_QUERY_BUFFER, m_bo_query);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer have failed");
gl.bufferData(GL_QUERY_BUFFER, sizeof(glw::GLint64), DE_NULL, GL_DYNAMIC_COPY);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData have failed");
/* Buffer for storing transform feedback results. */
gl.genBuffers(1, &m_bo_xfb);
GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers have failed");
gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_xfb);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer have failed");
gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER,
3 /* number of vertices per triangle */ * 2 /* number of triangles */ * sizeof(glw::GLint), DE_NULL,
GL_DYNAMIC_COPY);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData have failed");
gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_bo_xfb);
GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase have failed");
}
/** @brief Function creates array of query objects using DSA-style method.
*
* @note The function may throw if unexpected error has occured.
*/
void FunctionalTest::prepareQueries()
{
/* Shortcut for GL functionality. */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Allocating memory for queries array. */
m_qo = new glw::GLuint[s_targets_count];
if (DE_NULL == m_qo)
{
throw 0;
}
/* Creating query object for each target. */
for (glw::GLuint i = 0; i < s_targets_count; ++i)
{
gl.createQueries(s_targets[i], 1, &m_qo[i]);
/* Error checking. */
if (GL_NO_ERROR != gl.getError())
{
/* Remove previous. */
if (i > 0)
{
gl.deleteQueries(i, m_qo);
}
/* Deallocate storage. */
delete[] m_qo;
m_qo = DE_NULL;
/* Signalise test failure. */
throw 0;
}
}
}
/** @brief Function builds test's GLSL program.
* If succeded, the program will be set to be used.
*
* @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_name, 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 Function draws full screen quad. Queries are measured during the process.
* Also, transform feedback data is captured.
*
* @note The function may throw if unexpected error has occured.
*/
void FunctionalTest::draw()
{
/* Shortcut for GL functionality. */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Start queries. */
for (glw::GLuint i = 0; i < s_targets_count; ++i)
{
gl.beginQuery(s_targets[i], m_qo[i]);
}
/* Start XFB. */
gl.beginTransformFeedback(GL_TRIANGLES);
/* Draw full screen quad. */
gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
/* Finish XFB. */
gl.endTransformFeedback();
/* Finish queries. */
for (glw::GLuint i = 0; i < s_targets_count; ++i)
{
gl.endQuery(s_targets[i]);
}
/* Make sure OpenGL finished drawing. */
gl.finish();
/* Error checking. */
GLU_EXPECT_NO_ERROR(gl.getError(), "Drawing function have failed.");
}
/** @brief Check that framebuffer is filled with red color.
*/
bool FunctionalTest::checkView()
{
/* Shortcut for GL functionality. */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Fetch framebuffer data. */
glw::GLubyte pixel[4] = { 0 };
gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels have failed");
/* Comparison with expected values. */
if ((255 != pixel[0]) || (0 != pixel[1]) || (0 != pixel[2]) || (255 != pixel[3]))
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "Frameuffer content (" << (unsigned int)pixel[0] << ", "
<< (unsigned int)pixel[1] << ", " << (unsigned int)pixel[2] << ", " << (unsigned int)pixel[3]
<< ") is different than expected (255, 0, 0, 255)." << tcu::TestLog::EndMessage;
return false;
}
return true;
}
/** @brief Check that transform feedback buffer
* contains values representing quad.
*/
bool FunctionalTest::checkXFB()
{
/* 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. */
glw::GLint* buffer = (glw::GLint*)gl.mapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBuffer call failed.");
if ((0 != buffer[0]) || (1 != buffer[1]) || (2 != buffer[2]) ||
(2 != buffer[3]) || (1 != buffer[4]) || (3 != buffer[5]))
{
is_ok = false;
}
gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer call failed.");
return is_ok;
}
/** @brief Release all created objects.
*/
void FunctionalTest::clean()
{
/* Shortcut for GL functionality. */
const glw::Functions& gl = m_context.getRenderContext().getFunctions();
/* Releasing queries. */
if (DE_NULL != m_qo)
{
gl.deleteQueries(s_targets_count, m_qo);
delete[] m_qo;
m_qo = DE_NULL;
}
/* Release framebuffer. */
if (m_fbo)
{
gl.deleteFramebuffers(1, &m_fbo);
m_fbo = 0;
}
/* Release renderbuffer. */
if (m_rbo)
{
gl.deleteRenderbuffers(1, &m_rbo);
m_rbo = 0;
}
/* Release vertex array object. */
if (m_vao)
{
gl.deleteVertexArrays(1, &m_vao);
m_vao = 0;
}
/* Release buffer object for storing queries' results. */
if (m_bo_query)
{
gl.deleteBuffers(1, &m_bo_query);
m_bo_query = 0;
}
/* Release transform feedback buffer. */
if (m_bo_xfb)
{
gl.deleteBuffers(1, &m_bo_xfb);
m_bo_xfb = 0;
}
/* Release GLSL program. */
if (m_po)
{
gl.useProgram(0);
gl.deleteProgram(m_po);
m_po = 0;
}
}
/** Targets to be tested. */
const glw::GLenum FunctionalTest::s_targets[] = { GL_SAMPLES_PASSED, GL_TIME_ELAPSED, GL_PRIMITIVES_GENERATED,
GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN };
/** Expected result for each target. */
const glw::GLint FunctionalTest::s_results[] = { 1, 0, 2, 2 };
/** Number of targets. */
const glw::GLuint FunctionalTest::s_targets_count = sizeof(s_targets) / sizeof(s_targets[0]);
/** Vertex shader source code. */
const glw::GLchar FunctionalTest::s_vertex_shader[] = "#version 450\n"
"\n"
"out int xfb_result;\n"
"\n"
"void main()\n"
"{\n"
" switch(gl_VertexID)\n"
" {\n"
" case 0:\n"
" gl_Position = vec4(-1.0, 1.0, 0.0, 1.0);\n"
" break;\n"
" case 1:\n"
" gl_Position = vec4( 1.0, 1.0, 0.0, 1.0);\n"
" break;\n"
" case 2:\n"
" gl_Position = vec4(-1.0,-1.0, 0.0, 1.0);\n"
" break;\n"
" case 3:\n"
" gl_Position = vec4( 1.0,-1.0, 0.0, 1.0);\n"
" break;\n"
" }\n"
"\n"
" xfb_result = gl_VertexID;\n"
"}\n";
/** Fragment shader source program. */
const glw::GLchar FunctionalTest::s_fragment_shader[] = "#version 450\n"
"\n"
"out vec4 color;\n"
"\n"
"void main()\n"
"{\n"
" color = vec4(1.0, 0.0, 0.0, 1.0);\n"
"}\n";
/** Name of transform feedback varying in vertex shader. */
const glw::GLchar* FunctionalTest::s_xfb_varying_name = "xfb_result";
} /* Queries namespace. */
} /* DirectStateAccess namespace. */
} /* gl4cts namespace. */