blob: efad8c4da8798417be657903d1ff3dca57b8d8d1 [file] [log] [blame]
/*-------------------------------------------------------------------------
* OpenGL Conformance Test Suite
* -----------------------------
*
* Copyright (c) 2015-2018 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 glcKHRDebugTests.cpp
* \brief Implements conformance tests for "KHR Debug" functionality.
*/ /*-------------------------------------------------------------------*/
#include "glcKHRDebugTests.hpp"
#include "gluPlatform.hpp"
#include "gluRenderConfig.hpp"
#include "gluRenderContext.hpp"
#include "gluStrUtil.hpp"
#include "glwEnums.hpp"
#include "glwFunctions.hpp"
#include "tcuCommandLine.hpp"
#include "tcuTestLog.hpp"
//
//#include <string>
#define DEBUG_ENBALE_MESSAGE_CALLBACK 0
#if DEBUG_ENBALE_MESSAGE_CALLBACK
//#include <iomanip>
#endif /* DEBUG_ENBALE_MESSAGE_CALLBACK */
using namespace glw;
namespace glcts
{
namespace KHRDebug
{
/** Macro, verifies generated error, logs error message and throws failure
*
* @param expected_error Expected error value
* @param error_message Message logged if generated error is not the expected one
**/
#define CHECK_ERROR(expected_error, error_message) \
do { \
GLenum generated_error = m_gl->getError(); \
\
if (expected_error != generated_error) \
{ \
m_testCtx.getLog() \
<< tcu::TestLog::Message << "File: " << __FILE__ << ", line: " << __LINE__ \
<< ". Got wrong error: " << glu::getErrorStr(generated_error) \
<< ", expected: " << glu::getErrorStr(expected_error) << ", message: " << error_message \
<< tcu::TestLog::EndMessage; \
TestBase::done(); \
TCU_FAIL("Invalid error generated"); \
} \
} while (0)
/** Pop all groups from stack
*
* @param gl GL functions
**/
void cleanGroupStack(const Functions* gl)
{
while (1)
{
gl->popDebugGroup();
const GLenum err = gl->getError();
if (GL_STACK_UNDERFLOW == err)
{
break;
}
GLU_EXPECT_NO_ERROR(err, "PopDebugGroup");
}
}
/** Extracts all messages from log
*
* @param gl GL functions
**/
void cleanMessageLog(const Functions* gl)
{
static const GLuint count = 16;
while (1)
{
GLuint ret = gl->getDebugMessageLog(count /* count */, 0 /* bufSize */, 0 /* sources */, 0 /* types */,
0 /* ids */, 0 /* severities */, 0 /* lengths */, 0 /* messageLog */);
GLU_EXPECT_NO_ERROR(gl->getError(), "GetDebugMessageLog");
if (0 == ret)
{
break;
}
}
}
/** Fill stack of groups
*
* @param gl GL functions
**/
void fillGroupStack(const Functions* gl)
{
static const GLchar message[] = "Foo";
static const GLsizei length = (GLsizei)(sizeof(message) / sizeof(message[0]));
while (1)
{
gl->pushDebugGroup(GL_DEBUG_SOURCE_APPLICATION /* source */, 1 /* id */, length /* length */,
message /* message */);
const GLenum err = gl->getError();
if (GL_STACK_OVERFLOW == err)
{
break;
}
GLU_EXPECT_NO_ERROR(err, "PopDebugGroup");
}
}
/** Constructor
* Creates and set as current new context that should be used by test.
*
* @param testCtx Test context
* @param is_debug Selects if debug or non-debug context should be created
**/
TestBase::TestBase(tcu::TestContext& testContext, glu::ApiType apiType, bool is_debug)
: m_gl(0), m_is_debug(is_debug), m_rc(0), m_testContext(testContext), m_apiType(apiType)
{
/* Nothing to be done here */
}
/** Destructor
* Destroys context used by test and set original context as current
**/
TestBase::~TestBase()
{
if (0 != m_rc)
{
done();
}
}
/** Initialize rendering context
**/
void TestBase::init()
{
if (true == m_is_debug)
{
initDebug();
}
else
{
initNonDebug();
}
/* Get functions */
m_gl = &m_rc->getFunctions();
}
/** Prepares debug context
**/
void TestBase::initDebug()
{
tcu::Platform& platform = m_testContext.getPlatform();
glu::RenderConfig renderCfg(glu::ContextType(m_apiType, glu::CONTEXT_DEBUG));
const tcu::CommandLine& commandLine = m_testContext.getCommandLine();
parseRenderConfig(&renderCfg, commandLine);
if (commandLine.getSurfaceType() != tcu::SURFACETYPE_WINDOW)
throw tcu::NotSupportedError("Test not supported in non-windowed context");
m_rc = createRenderContext(platform, commandLine, renderCfg);
m_rc->makeCurrent();
}
/** Prepares non-debug context
**/
void TestBase::initNonDebug()
{
tcu::Platform& platform = m_testContext.getPlatform();
glu::RenderConfig renderCfg(glu::ContextType(m_apiType, glu::ContextFlags(0)));
const tcu::CommandLine& commandLine = m_testContext.getCommandLine();
parseRenderConfig(&renderCfg, commandLine);
if (commandLine.getSurfaceType() != tcu::SURFACETYPE_WINDOW)
throw tcu::NotSupportedError("Test not supported in non-windowed context");
m_rc = createRenderContext(platform, commandLine, renderCfg);
m_rc->makeCurrent();
}
/** Finalize rendering context
**/
void TestBase::done()
{
/* Delete context used by test and make no context current */
delete m_rc;
m_rc = 0;
m_gl = 0;
}
/** Constructor
*
* @param testCtx Test context
* @param is_debug Selects if debug or non-debug context should be used
* @param name Name of test
**/
APIErrorsTest::APIErrorsTest(tcu::TestContext& testCtx, glu::ApiType apiType, bool is_debug, const GLchar* name)
: TestBase(testCtx, apiType, is_debug), TestCase(testCtx, name, "Verifies that errors are generated as expected")
{
/* Nothing to be done */
}
/** Execute test
*
* @return tcu::TestNode::STOP
**/
tcu::TestNode::IterateResult APIErrorsTest::iterate()
{
/* Initialize rendering context */
TestBase::init();
/* Get maximum label length */
GLint max_label = 0;
m_gl->getIntegerv(GL_MAX_LABEL_LENGTH, &max_label);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "GetIntegerv");
/* Prepare too long label */
std::vector<GLchar> too_long_label;
too_long_label.resize(max_label + 2);
for (GLint i = 0; i <= max_label; ++i)
{
too_long_label[i] = 'f';
}
too_long_label[max_label + 1] = 0;
/* Get maximum message length */
GLint max_length = 0;
m_gl->getIntegerv(GL_MAX_DEBUG_MESSAGE_LENGTH, &max_length);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "GetIntegerv");
/* Prepare too long message */
std::vector<GLchar> too_long_message;
too_long_message.resize(max_length + 2);
for (GLint i = 0; i <= max_length; ++i)
{
too_long_message[i] = 'f';
}
too_long_message[max_length + 1] = 0;
/* Get maximum number of groups on stack */
GLint max_groups = 0;
m_gl->getIntegerv(GL_MAX_DEBUG_GROUP_STACK_DEPTH, &max_groups);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "GetIntegerv");
/*
* DebugMessageControl function should generate:
* - INVALID_ENUM when <source> is invalid;
* - INVALID_ENUM when <type> is invalid;
* - INVALID_ENUM when <severity> is invalid;
* - INVALID_VALUE when <count> is negative;
* - INVALID_OPERATION when <count> is not zero and <source> is DONT_CARE;
* - INVALID_OPERATION when <count> is not zero and <type> is DONT_CARE;
* - INVALID_OPERATION when <count> is not zero and <severity> is not
* DONT_CARE.
*/
{
static const GLuint ids[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
static const GLsizei n_ids = (GLsizei)(sizeof(ids) / sizeof(ids[0]));
m_gl->debugMessageControl(GL_ARRAY_BUFFER /* source */, GL_DEBUG_TYPE_ERROR /* type */,
GL_DEBUG_SEVERITY_LOW /* severity */, 0 /* count */, 0 /* ids */,
GL_TRUE /* enabled */);
CHECK_ERROR(GL_INVALID_ENUM, "DebugMessageControl with <source> set to GL_ARRAY_BUFFER");
m_gl->debugMessageControl(GL_DEBUG_SOURCE_API /* source */, GL_ARRAY_BUFFER /* type */,
GL_DEBUG_SEVERITY_LOW /* severity */, 0 /* count */, 0 /* ids */,
GL_TRUE /* enabled */);
CHECK_ERROR(GL_INVALID_ENUM, "DebugMessageControl with <type> set to GL_ARRAY_BUFFER");
m_gl->debugMessageControl(GL_DEBUG_SOURCE_API /* source */, GL_DEBUG_TYPE_ERROR /* type */,
GL_ARRAY_BUFFER /* severity */, 0 /* count */, 0 /* ids */, GL_TRUE /* enabled */);
CHECK_ERROR(GL_INVALID_ENUM, "DebugMessageControl with <severity> set to GL_ARRAY_BUFFER");
m_gl->debugMessageControl(GL_DEBUG_SOURCE_API /* source */, GL_DEBUG_TYPE_ERROR /* type */,
GL_DEBUG_SEVERITY_LOW /* severity */, -1 /* count */, ids /* ids */,
GL_TRUE /* enabled */);
CHECK_ERROR(GL_INVALID_VALUE, "DebugMessageControl with <count> set to -1");
m_gl->debugMessageControl(GL_DONT_CARE /* source */, GL_DEBUG_TYPE_ERROR /* type */,
GL_DONT_CARE /* severity */, n_ids /* count */, ids /* ids */, GL_TRUE /* enabled */);
CHECK_ERROR(GL_INVALID_OPERATION, "DebugMessageControl with <source> set to GL_DONT_CARE and non zero <count>");
m_gl->debugMessageControl(GL_DEBUG_SOURCE_API /* source */, GL_DONT_CARE /* type */,
GL_DONT_CARE /* severity */, n_ids /* count */, ids /* ids */, GL_TRUE /* enabled */);
CHECK_ERROR(GL_INVALID_OPERATION, "DebugMessageControl with <type> set to GL_DONT_CARE and non zero <count>");
m_gl->debugMessageControl(GL_DEBUG_SOURCE_API /* source */, GL_DEBUG_TYPE_ERROR /* type */,
GL_DEBUG_SEVERITY_LOW /* severity */, n_ids /* count */, ids /* ids */,
GL_TRUE /* enabled */);
CHECK_ERROR(GL_INVALID_OPERATION,
"DebugMessageControl with <severity> set to GL_DEBUG_SEVERITY_LOW and non zero <count>");
}
/*
* GetDebugMessageLog function should generate:
* - INVALID_VALUE when <bufSize> is negative and messageLog is not NULL.
*/
{
static const GLsizei bufSize = 32;
static const GLuint count = 4;
GLenum ids[count];
GLsizei lengths[count];
GLchar messageLog[bufSize];
GLenum types[count];
GLenum severities[count];
GLenum sources[count];
m_gl->getDebugMessageLog(count /* count */, -1 /* bufSize */, sources, types, ids, severities, lengths,
messageLog);
CHECK_ERROR(GL_INVALID_VALUE, "GetDebugMessageLog with <bufSize> set to -1");
}
/*
* DebugMessageInsert function should generate:
* - INVALID_ENUM when <source> is not DEBUG_SOURCE_APPLICATION or
* DEBUG_SOURCE_THIRD_PARTY;
* - INVALID_ENUM when <type> is invalid;
* - INVALID_ENUM when <severity> is invalid;
* - INVALID_VALUE when length of string <buf> is not less than
* MAX_DEBUG_MESSAGE_LENGTH.
*/
{
static const GLchar message[] = "Foo";
static const GLsizei length = (GLsizei)(sizeof(message) / sizeof(message[0]));
m_gl->debugMessageInsert(GL_DEBUG_SOURCE_API /* source */, GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR /* type */,
0 /* id */, GL_DEBUG_SEVERITY_LOW /* severity */, length /* length */,
message /* message */);
CHECK_ERROR(GL_INVALID_ENUM, "DebugMessageInsert with <source> set to GL_DEBUG_SOURCE_API");
m_gl->debugMessageInsert(GL_DEBUG_SOURCE_APPLICATION /* source */, GL_ARRAY_BUFFER /* type */, 0 /* id */,
GL_DEBUG_SEVERITY_LOW /* severity */, length /* length */, message /* message */);
CHECK_ERROR(GL_INVALID_ENUM, "DebugMessageInsert with <type> set to GL_ARRAY_BUFFER");
m_gl->debugMessageInsert(GL_DEBUG_SOURCE_APPLICATION /* source */, GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR /* type */,
0 /* id */, GL_ARRAY_BUFFER /* severity */, length /* length */,
message /* message */);
CHECK_ERROR(GL_INVALID_ENUM, "DebugMessageInsert with <severity> set to GL_ARRAY_BUFFER");
m_gl->debugMessageInsert(GL_DEBUG_SOURCE_APPLICATION /* source */, GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR /* type */,
0 /* id */, GL_DEBUG_SEVERITY_LOW /* severity */, max_length + 1 /* length */,
message /* message */);
CHECK_ERROR(GL_INVALID_VALUE, "DebugMessageInsert with <length> set to GL_MAX_DEBUG_MESSAGE_LENGTH + 1");
m_gl->debugMessageInsert(GL_DEBUG_SOURCE_APPLICATION /* source */, GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR /* type */,
0 /* id */, GL_DEBUG_SEVERITY_LOW /* severity */, -1 /* length */,
&too_long_message[0] /* message */);
CHECK_ERROR(GL_INVALID_VALUE, "DebugMessageInsert with too long message");
}
/*
* PushDebugGroup function should generate:
* - INVALID_ENUM when <source> is not DEBUG_SOURCE_APPLICATION or
* DEBUG_SOURCE_THIRD_PARTY;
* - INVALID_VALUE when length of string <message> is not less than
* MAX_DEBUG_MESSAGE_LENGTH;
* - STACK_OVERFLOW when stack contains MAX_DEBUG_GROUP_STACK_DEPTH entries.
*/
{
static const GLchar message[] = "Foo";
static const GLsizei length = (GLsizei)(sizeof(message) / sizeof(message[0]));
m_gl->pushDebugGroup(GL_DEBUG_SOURCE_API /* source */, 1 /* id */, length /* length */, message /* message */);
CHECK_ERROR(GL_INVALID_ENUM, "PushDebugGroup with <source> set to GL_DEBUG_SOURCE_API");
m_gl->pushDebugGroup(GL_DEBUG_SOURCE_APPLICATION /* source */, 1 /* id */, max_length + 1 /* length */,
message /* message */);
CHECK_ERROR(GL_INVALID_VALUE, "PushDebugGroup with <length> set to GL_MAX_DEBUG_MESSAGE_LENGTH + 1");
m_gl->pushDebugGroup(GL_DEBUG_SOURCE_APPLICATION /* source */, 1 /* id */, -1 /* length */,
&too_long_message[0] /* message */);
CHECK_ERROR(GL_INVALID_VALUE, "PushDebugGroup with too long message");
/* Clean stack */
cleanGroupStack(m_gl);
/* Fill stack */
for (GLint i = 0; i < max_groups - 1; ++i)
{
m_gl->pushDebugGroup(GL_DEBUG_SOURCE_APPLICATION /* source */, 1 /* id */, length /* length */,
message /* message */);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "PushDebugGroup");
}
/* Overflow stack */
m_gl->pushDebugGroup(GL_DEBUG_SOURCE_APPLICATION /* source */, 1 /* id */, length /* length */,
message /* message */);
CHECK_ERROR(GL_STACK_OVERFLOW, "PushDebugGroup called GL_MAX_DEBUG_GROUP_STACK_DEPTH times");
/* Clean stack */
cleanGroupStack(m_gl);
}
/*
* PopDebugGroup function should generate:
* - STACK_UNDERFLOW when stack contains no entries.
*/
{
fillGroupStack(m_gl);
for (GLint i = 0; i < max_groups - 1; ++i)
{
m_gl->popDebugGroup();
GLU_EXPECT_NO_ERROR(m_gl->getError(), "PopDebugGroup");
}
m_gl->popDebugGroup();
CHECK_ERROR(GL_STACK_UNDERFLOW, "PopDebugGroup called GL_MAX_DEBUG_GROUP_STACK_DEPTH times");
}
/*
* ObjectLabel function should generate:
* - INVALID_ENUM when <identifier> is invalid;
* - INVALID_VALUE when if <name> is not valid object name of type specified by
* <identifier>;
* - INVALID_VALUE when length of string <label> is not less than
* MAX_LABEL_LENGTH.
*/
{
static const GLchar label[] = "Foo";
static const GLsizei length = (GLsizei)(sizeof(label) / sizeof(label[0]));
GLuint texture_id = 0;
GLuint invalid_id = 1;
m_gl->genTextures(1, &texture_id);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "GenTextures");
m_gl->bindTexture(GL_TEXTURE_BUFFER, texture_id);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "BindTexture");
try
{
m_gl->objectLabel(GL_TEXTURE_BUFFER /* identifier */, texture_id /* name */, length /* length */,
label /* label */);
CHECK_ERROR(GL_INVALID_ENUM, "ObjectLabel with <identifier> set to GL_TEXTURE_BUFFER");
while (GL_TRUE == m_gl->isTexture(invalid_id))
{
invalid_id += 1;
}
m_gl->objectLabel(GL_TEXTURE /* identifier */, invalid_id /* name */, length /* length */,
label /* label */);
CHECK_ERROR(GL_INVALID_VALUE, "ObjectLabel with <name> set to not generated value");
m_gl->objectLabel(GL_TEXTURE /* identifier */, texture_id /* name */, max_label + 1 /* length */,
label /* label */);
CHECK_ERROR(GL_INVALID_VALUE, "ObjectLabel with <label> set to MAX_LABEL_LENGTH + 1");
m_gl->objectLabel(GL_TEXTURE /* identifier */, texture_id /* name */, -1 /* length */,
&too_long_label[0] /* label */);
CHECK_ERROR(GL_INVALID_VALUE, "ObjectLabel with too long label");
}
catch (const std::exception& exc)
{
m_gl->deleteTextures(1, &texture_id);
TCU_FAIL(exc.what());
}
m_gl->deleteTextures(1, &texture_id);
}
/*
* GetObjectLabel function should generate:
* - INVALID_ENUM when <identifier> is invalid;
* - INVALID_VALUE when if <name> is not valid object name of type specified by
* <identifier>;
* - INVALID_VALUE when <bufSize> is negative.
*/
{
static const GLsizei bufSize = 32;
GLchar label[bufSize];
GLsizei length = 0;
GLuint texture_id = 0;
GLuint invalid_id = 1;
m_gl->genTextures(1, &texture_id);
m_gl->bindTexture(GL_TEXTURE_2D, texture_id);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "GenTextures");
try
{
m_gl->getObjectLabel(GL_TEXTURE_BUFFER /* identifier */, texture_id /* name */, bufSize /* bufSize */,
&length /* length */, label /* label */);
CHECK_ERROR(GL_INVALID_ENUM, "GetObjectLabel with <identifier> set to GL_TEXTURE_BUFFER");
while (GL_TRUE == m_gl->isTexture(invalid_id))
{
invalid_id += 1;
}
m_gl->getObjectLabel(GL_TEXTURE /* identifier */, invalid_id /* name */, bufSize /* bufSize */,
&length /* length */, label /* label */);
CHECK_ERROR(GL_INVALID_VALUE, "GetObjectLabel with <name> set to not generated value");
m_gl->getObjectLabel(GL_TEXTURE /* identifier */, invalid_id /* name */, -1 /* bufSize */,
&length /* length */, label /* label */);
CHECK_ERROR(GL_INVALID_VALUE, "GetObjectLabel with <bufSize> set to -1");
}
catch (const std::exception& exc)
{
m_gl->deleteTextures(1, &texture_id);
TCU_FAIL(exc.what());
}
m_gl->deleteTextures(1, &texture_id);
}
/*
* ObjectPtrLabel function should generate:
* - INVALID_VALUE when <ptr> is not the name of sync object;
* - INVALID_VALUE when length of string <label> is not less than
* MAX_LABEL_LENGTH.
*/
{
static const GLchar label[] = "Foo";
static const GLsizei length = (GLsizei)(sizeof(label) / sizeof(label[0]));
GLsync sync_id = 0;
GLsync invalid_id = 0;
sync_id = m_gl->fenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "FenceSync");
try
{
while (GL_TRUE == m_gl->isSync(invalid_id))
{
invalid_id = (GLsync)(((unsigned long long)invalid_id) + 1);
}
m_gl->objectPtrLabel(invalid_id /* name */, length /* length */, label /* label */);
CHECK_ERROR(GL_INVALID_VALUE, "ObjectPtrLabel with <ptr> set to not generated value");
m_gl->objectPtrLabel(sync_id /* name */, max_label + 1 /* length */, label /* label */);
CHECK_ERROR(GL_INVALID_VALUE, "ObjectPtrLabel with <length> set to MAX_LABEL_LENGTH + 1");
m_gl->objectPtrLabel(sync_id /* name */, -1 /* length */, &too_long_label[0] /* label */);
CHECK_ERROR(GL_INVALID_VALUE, "ObjectPtrLabel with too long label");
}
catch (const std::exception& exc)
{
m_gl->deleteSync(sync_id);
TCU_FAIL(exc.what());
}
m_gl->deleteSync(sync_id);
}
/*
* GetObjectPtrLabel function should generate:
* - INVALID_VALUE when <ptr> is not the name of sync object;
* - INVALID_VALUE when <bufSize> is negative.
*/
{
static const GLsizei bufSize = 32;
GLchar label[bufSize];
GLsizei length = 0;
GLsync sync_id = 0;
GLsync invalid_id = 0;
sync_id = m_gl->fenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "FenceSync");
try
{
while (GL_TRUE == m_gl->isSync(invalid_id))
{
invalid_id = (GLsync)(((unsigned long long)invalid_id) + 1);
}
m_gl->getObjectPtrLabel(invalid_id /* name */, bufSize /* bufSize */, &length /* length */,
label /* label */);
CHECK_ERROR(GL_INVALID_VALUE, "GetObjectPtrLabel with <ptr> set to not generated value");
m_gl->getObjectPtrLabel(sync_id /* name */, -1 /* bufSize */, &length /* length */, label /* label */);
CHECK_ERROR(GL_INVALID_VALUE, "GetObjectPtrLabel with <bufSize> set to -1");
}
catch (const std::exception& exc)
{
m_gl->deleteSync(sync_id);
TCU_FAIL(exc.what());
}
m_gl->deleteSync(sync_id);
}
/*
* GetPointerv function should generate:
* - INVALID_ENUM when <pname> is invalid.
**/
{
GLuint uint;
GLuint* uint_ptr = &uint;
m_gl->getPointerv(GL_ARRAY_BUFFER, (GLvoid**)&uint_ptr);
CHECK_ERROR(GL_INVALID_ENUM, "GetPointerv with <pname> set to GL_ARRAY_BUFFER");
}
/* Set result */
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
/* Done */
TestBase::done();
return tcu::TestNode::STOP;
}
/** Constructor
*
* @param testCtx Test context
* @param is_debug Selects if debug or non-debug context should be used
* @param name Name of test
**/
LabelsTest::LabelsTest(tcu::TestContext& testCtx, glu::ApiType apiType, bool is_debug, const GLchar* name)
: TestCase(testCtx, name, "Verifies that labels can be assigned and queried"), TestBase(testCtx, apiType, is_debug)
{
/* Nothing to be done */
}
/** Represnets case for LabelsTest **/
struct labelsTestCase
{
GLenum m_identifier;
GLuint (*m_create)(const glw::Functions* gl, const glu::RenderContext*);
GLvoid (*m_destroy)(const glw::Functions* gl, GLuint id);
const GLchar* m_name;
};
/** Execute test
*
* @return tcu::TestNode::STOP
**/
tcu::TestNode::IterateResult LabelsTest::iterate()
{
static const labelsTestCase test_cases[] = {
{ GL_BUFFER, createBuffer, deleteBuffer, "Buffer" },
{ GL_FRAMEBUFFER, createFramebuffer, deleteFramebuffer, "Framebuffer" },
{ GL_PROGRAM, createProgram, deleteProgram, "Program" },
{ GL_PROGRAM_PIPELINE, createProgramPipeline, deleteProgramPipeline, "ProgramPipeline" },
{ GL_QUERY, createQuery, deleteQuery, "Query" },
{ GL_RENDERBUFFER, createRenderbuffer, deleteRenderbuffer, "Renderbuffer" },
{ GL_SAMPLER, createSampler, deleteSampler, "Sampler" },
{ GL_SHADER, createShader, deleteShader, "Shader" },
{ GL_TEXTURE, createTexture, deleteTexture, "Texture" },
{ GL_TRANSFORM_FEEDBACK, createTransformFeedback, deleteTransformFeedback, "TransformFeedback" },
{ GL_VERTEX_ARRAY, createVertexArray, deleteVertexArray, "VertexArray" },
};
static const size_t n_test_cases = sizeof(test_cases) / sizeof(test_cases[0]);
static const GLsizei bufSize = 32;
static const GLchar label[] = "foo";
static const GLsizei label_length = (GLsizei)(sizeof(label) / sizeof(label[0]) - 1);
/* Initialize render context */
TestBase::init();
/* For each test case */
for (size_t test_case_index = 0; test_case_index < n_test_cases; ++test_case_index)
{
const labelsTestCase& test_case = test_cases[test_case_index];
const GLenum identifier = test_case.m_identifier;
const GLuint id = test_case.m_create(m_gl, m_rc);
try
{
GLchar buffer[bufSize] = "HelloWorld";
GLsizei length;
/*
* - query label; It is expected that result will be an empty string and length
* will be zero;
*/
m_gl->getObjectLabel(identifier, id, bufSize, &length, buffer);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "GetObjectLabel");
if (0 != length)
{
TCU_FAIL("Just created object has label of length != 0");
}
if (0 != buffer[0])
{
TCU_FAIL("Just created object has not empty label");
}
/*
* - assign label to object;
* - query label; It is expected that result will be equal to the provided
* label and length will be correct;
*/
m_gl->objectLabel(identifier, id, -1 /* length */, label);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "ObjectLabel");
m_gl->getObjectLabel(identifier, id, bufSize, &length, buffer);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "GetObjectLabel");
if (label_length != length)
{
TCU_FAIL("Length is different than length of set label");
}
if (0 != strcmp(buffer, label))
{
TCU_FAIL("Different label returned");
}
/*
* - query length only; Correct value is expected;
*/
length = 0;
m_gl->getObjectLabel(identifier, id, 0 /* bufSize */, &length, 0 /* label */);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "GetObjectLabel");
if (label_length != length)
{
TCU_FAIL("Invalid length returned when label and bufSize are set to 0");
}
/*
* - query label with <bufSize> less than actual length of label; It is
* expected that only <bufSize> characters will be stored in buffer (including
* NULL);
*/
length = 0;
strcpy(buffer, "HelloWorld");
m_gl->getObjectLabel(identifier, id, 2 /* bufSize */, &length, buffer);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "GetObjectLabel");
if (buffer[0] != label[0])
{
TCU_FAIL("Different label returned");
}
if (buffer[1] != 0)
{
TCU_FAIL("GetObjectLabel did not stored NULL at the end of string");
}
if (buffer[2] != 'l')
{
TCU_FAIL("GetObjectLabel overflowed buffer");
}
/*
* - query label with <bufSize> equal zero; It is expected that buffer contents
* will not be modified;
*/
length = 0;
strcpy(buffer, "HelloWorld");
m_gl->getObjectLabel(identifier, id, 0 /* bufSize */, &length, buffer);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "GetObjectLabel");
if (0 != strcmp(buffer, "HelloWorld"))
{
TCU_FAIL("GetObjectLabel modified buffer, bufSize set to 0");
}
/*
* - assign empty string as label to object;
* - query label, it is expected that result will be an empty string and length
* will be zero;
*/
m_gl->objectLabel(identifier, id, -1 /* length */, "");
GLU_EXPECT_NO_ERROR(m_gl->getError(), "ObjectLabel");
m_gl->getObjectLabel(identifier, id, bufSize, &length, buffer);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "GetObjectLabel");
if (0 != length)
{
TCU_FAIL("Label length is != 0, empty string was set");
}
if (0 != buffer[0])
{
TCU_FAIL("Non empty label returned, empty string was set");
}
/*
* - assign NULL as label to object;
* - query label, it is expected that result will be an empty string and length
* will be zero;
*/
m_gl->objectLabel(identifier, id, 2, 0 /* label */);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "ObjectLabel");
m_gl->getObjectLabel(identifier, id, bufSize, &length, buffer);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "GetObjectLabel");
if (0 != length)
{
TCU_FAIL("Label length is != 0, label was removed");
}
if (0 != buffer[0])
{
TCU_FAIL("Different label returned, label was removed");
}
}
catch (const std::exception& exc)
{
test_case.m_destroy(m_gl, id);
m_testCtx.getLog()
<< tcu::TestLog::Message << "Error during test case: " << test_case.m_name << tcu::TestLog::EndMessage;
TCU_FAIL(exc.what());
}
test_case.m_destroy(m_gl, id);
}
/* Set result */
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
/* Done */
TestBase::done();
return tcu::TestNode::STOP;
}
/** Create buffer
*
* @param gl GL functions
*
* @return ID of created resource
**/
GLuint LabelsTest::createBuffer(const Functions* gl, const glu::RenderContext* rc)
{
GLuint id = 0;
if (glu::contextSupports(rc->getType(), glu::ApiType::core(4, 5)))
{
gl->createBuffers(1, &id);
GLU_EXPECT_NO_ERROR(gl->getError(), "CreateBuffers");
}
else
{
gl->genBuffers(1, &id);
gl->bindBuffer(GL_ARRAY_BUFFER, id);
GLU_EXPECT_NO_ERROR(gl->getError(), "GenBuffers");
}
return id;
}
/** Create FBO
*
* @param gl GL functions
*
* @return ID of created resource
**/
GLuint LabelsTest::createFramebuffer(const Functions* gl, const glu::RenderContext* rc)
{
GLuint id = 0;
if (glu::contextSupports(rc->getType(), glu::ApiType::core(4, 5)))
{
gl->createFramebuffers(1, &id);
GLU_EXPECT_NO_ERROR(gl->getError(), "CreateFramebuffers");
}
else
{
GLint currentFbo;
gl->getIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &currentFbo);
gl->genFramebuffers(1, &id);
gl->bindFramebuffer(GL_DRAW_FRAMEBUFFER, id);
gl->bindFramebuffer(GL_DRAW_FRAMEBUFFER, currentFbo);
GLU_EXPECT_NO_ERROR(gl->getError(), "GenFramebuffers / BindFramebuffer");
}
return id;
}
/** Create program
*
* @param gl GL functions
*
* @return ID of created resource
**/
GLuint LabelsTest::createProgram(const Functions* gl, const glu::RenderContext*)
{
GLuint id = gl->createProgram();
GLU_EXPECT_NO_ERROR(gl->getError(), "CreateProgram");
return id;
}
/** Create pipeline
*
* @param gl GL functions
*
* @return ID of created resource
**/
GLuint LabelsTest::createProgramPipeline(const Functions* gl, const glu::RenderContext* rc)
{
GLuint id = 0;
if (glu::contextSupports(rc->getType(), glu::ApiType::core(4, 5)))
{
gl->createProgramPipelines(1, &id);
GLU_EXPECT_NO_ERROR(gl->getError(), "CreateProgramPipelines");
}
else
{
gl->genProgramPipelines(1, &id);
gl->bindProgramPipeline(id);
GLU_EXPECT_NO_ERROR(gl->getError(), "GenProgramPipelines / BindProgramPipeline");
}
return id;
}
/** Create query
*
* @param gl GL functions
*
* @return ID of created resource
**/
GLuint LabelsTest::createQuery(const Functions* gl, const glu::RenderContext* rc)
{
GLuint id = 0;
if (glu::contextSupports(rc->getType(), glu::ApiType::core(4, 5)))
{
gl->createQueries(GL_TIMESTAMP, 1, &id);
GLU_EXPECT_NO_ERROR(gl->getError(), "CreateQueries");
}
else
{
gl->genQueries(1, &id);
gl->beginQuery(GL_SAMPLES_PASSED, id);
gl->endQuery(GL_SAMPLES_PASSED);
GLU_EXPECT_NO_ERROR(gl->getError(), "GenQueries / BeginQuery / EndQuery");
}
return id;
}
/** Create render buffer
*
* @param gl GL functions
*
* @return ID of created resource
**/
GLuint LabelsTest::createRenderbuffer(const Functions* gl, const glu::RenderContext* rc)
{
GLuint id = 0;
if (glu::contextSupports(rc->getType(), glu::ApiType::core(4, 5)))
{
gl->createRenderbuffers(1, &id);
GLU_EXPECT_NO_ERROR(gl->getError(), "CreateRenderbuffers");
}
else
{
gl->genRenderbuffers(1, &id);
gl->bindRenderbuffer(GL_RENDERBUFFER, id);
gl->bindRenderbuffer(GL_RENDERBUFFER, 0);
GLU_EXPECT_NO_ERROR(gl->getError(), "GenRenderbuffers / BindRenderbuffer");
}
return id;
}
/** Create sampler
*
* @param gl GL functions
*
* @return ID of created resource
**/
GLuint LabelsTest::createSampler(const Functions* gl, const glu::RenderContext* rc)
{
GLuint id = 0;
if (glu::contextSupports(rc->getType(), glu::ApiType::core(4, 5)))
{
gl->createSamplers(1, &id);
GLU_EXPECT_NO_ERROR(gl->getError(), "CreateSamplers");
}
else
{
gl->genSamplers(1, &id);
gl->bindSampler(0, id);
gl->bindSampler(0, 0);
GLU_EXPECT_NO_ERROR(gl->getError(), "GenSamplers / BindSampler");
}
return id;
}
/** Create shader
*
* @param gl GL functions
*
* @return ID of created resource
**/
GLuint LabelsTest::createShader(const Functions* gl, const glu::RenderContext*)
{
GLuint id = gl->createShader(GL_VERTEX_SHADER);
GLU_EXPECT_NO_ERROR(gl->getError(), "CreateShader");
return id;
}
/** Create texture
*
* @param gl GL functions
*
* @return ID of created resource
**/
GLuint LabelsTest::createTexture(const Functions* gl, const glu::RenderContext* rc)
{
GLuint id = 0;
if (glu::contextSupports(rc->getType(), glu::ApiType::core(4, 5)))
{
gl->createTextures(GL_TEXTURE_2D, 1, &id);
GLU_EXPECT_NO_ERROR(gl->getError(), "CreateTextures");
}
else
{
gl->genTextures(1, &id);
gl->bindTexture(GL_TEXTURE_2D, id);
gl->bindTexture(GL_TEXTURE_2D, 0);
GLU_EXPECT_NO_ERROR(gl->getError(), "GenTextures / BindTexture");
}
return id;
}
/** Create XFB
*
* @param gl GL functions
*
* @return ID of created resource
**/
GLuint LabelsTest::createTransformFeedback(const Functions* gl, const glu::RenderContext* rc)
{
GLuint id = 0;
if (glu::contextSupports(rc->getType(), glu::ApiType::core(4, 5)))
{
gl->createTransformFeedbacks(1, &id);
GLU_EXPECT_NO_ERROR(gl->getError(), "CreateTransformFeedbacks");
}
else
{
gl->genTransformFeedbacks(1, &id);
gl->bindTransformFeedback(GL_TRANSFORM_FEEDBACK, id);
gl->bindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
GLU_EXPECT_NO_ERROR(gl->getError(), "GenTransformFeedbacks / BindTransformFeedback");
}
return id;
}
/** Create VAO
*
* @param gl GL functions
*
* @return ID of created resource
**/
GLuint LabelsTest::createVertexArray(const Functions* gl, const glu::RenderContext* rc)
{
GLuint id = 0;
if (glu::contextSupports(rc->getType(), glu::ApiType::core(4, 5)))
{
gl->createVertexArrays(1, &id);
GLU_EXPECT_NO_ERROR(gl->getError(), "CreateVertexArrays");
}
else
{
gl->genVertexArrays(1, &id);
gl->bindVertexArray(id);
gl->bindVertexArray(0);
GLU_EXPECT_NO_ERROR(gl->getError(), "GenVertexArrays / BindVertexArrays");
}
return id;
}
/** Destroy buffer
*
* @param gl GL functions
* @param id ID of resource
**/
GLvoid LabelsTest::deleteBuffer(const Functions* gl, GLuint id)
{
gl->deleteBuffers(1, &id);
GLU_EXPECT_NO_ERROR(gl->getError(), "DeleteBuffers");
}
/** Destroy FBO
*
* @param gl GL functions
* @param id ID of resource
**/
GLvoid LabelsTest::deleteFramebuffer(const Functions* gl, GLuint id)
{
gl->deleteFramebuffers(1, &id);
GLU_EXPECT_NO_ERROR(gl->getError(), "DeleteFramebuffers");
}
/** Destroy program
*
* @param gl GL functions
* @param id ID of resource
**/
GLvoid LabelsTest::deleteProgram(const Functions* gl, GLuint id)
{
gl->deleteProgram(id);
GLU_EXPECT_NO_ERROR(gl->getError(), "DeleteProgram");
}
/** Destroy pipeline
*
* @param gl GL functions
* @param id ID of resource
**/
GLvoid LabelsTest::deleteProgramPipeline(const Functions* gl, GLuint id)
{
gl->deleteProgramPipelines(1, &id);
GLU_EXPECT_NO_ERROR(gl->getError(), "DeleteProgramPipelines");
}
/** Destroy query
*
* @param gl GL functions
* @param id ID of resource
**/
GLvoid LabelsTest::deleteQuery(const Functions* gl, GLuint id)
{
gl->deleteQueries(1, &id);
GLU_EXPECT_NO_ERROR(gl->getError(), "DeleteQueries");
}
/** Destroy render buffer
*
* @param gl GL functions
* @param id ID of resource
**/
GLvoid LabelsTest::deleteRenderbuffer(const Functions* gl, GLuint id)
{
gl->deleteRenderbuffers(1, &id);
GLU_EXPECT_NO_ERROR(gl->getError(), "DeleteRenderbuffers");
}
/** Destroy sampler
*
* @param gl GL functions
* @param id ID of resource
**/
GLvoid LabelsTest::deleteSampler(const Functions* gl, GLuint id)
{
gl->deleteSamplers(1, &id);
GLU_EXPECT_NO_ERROR(gl->getError(), "DeleteSamplers");
}
/** Destroy shader
*
* @param gl GL functions
* @param id ID of resource
**/
GLvoid LabelsTest::deleteShader(const Functions* gl, GLuint id)
{
gl->deleteShader(id);
GLU_EXPECT_NO_ERROR(gl->getError(), "DeleteShader");
}
/** Destroy texture
*
* @param gl GL functions
* @param id ID of resource
**/
GLvoid LabelsTest::deleteTexture(const Functions* gl, GLuint id)
{
gl->deleteTextures(1, &id);
GLU_EXPECT_NO_ERROR(gl->getError(), "DeleteTextures");
}
/** Destroy XFB
*
* @param gl GL functions
* @param id ID of resource
**/
GLvoid LabelsTest::deleteTransformFeedback(const Functions* gl, GLuint id)
{
gl->deleteTransformFeedbacks(1, &id);
GLU_EXPECT_NO_ERROR(gl->getError(), "DeleteTransformFeedbacks");
}
/** Destroy VAO
*
* @param gl GL functions
* @param id ID of resource
**/
GLvoid LabelsTest::deleteVertexArray(const Functions* gl, GLuint id)
{
gl->deleteVertexArrays(1, &id);
GLU_EXPECT_NO_ERROR(gl->getError(), "DeleteVertexArrays");
}
/** Constructor
*
* @param testCtx Test context
* @param is_debug Selects if debug or non-debug context should be used
* @param name Name of test
**/
ReceivingMessagesTest::ReceivingMessagesTest(tcu::TestContext& testCtx, glu::ApiType apiType)
: TestCase(testCtx, "receiving_messages", "Verifies that messages can be received")
, TestBase(testCtx, apiType, true /* is_debug */)
{
/* Nothing to be done */
}
/** Execute test
*
* @return tcu::TestNode::STOP
**/
tcu::TestNode::IterateResult ReceivingMessagesTest::iterate()
{
static const size_t bufSize = 32;
static const GLchar label[] = "foo";
static const size_t label_length = sizeof(label) / sizeof(label[0]) - 1;
static const size_t read_messages = 4;
GLuint callback_counter = 0;
GLint max_debug_messages = 0;
/* Initialize render context */
TestBase::init();
/* Get max number of debug messages */
m_gl->getIntegerv(GL_MAX_DEBUG_LOGGED_MESSAGES, &max_debug_messages);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "GetIntegerv");
/*
* - verify that the state of DEBUG_OUTPUT is enabled as it should be by
* default;
* - verify that state of DEBUG_CALLBACK_FUNCTION and
* DEBUG_CALLBACK_USER_PARAM are NULL;
*/
{
inspectDebugState(GL_TRUE, 0 /* cb */, 0 /* info */);
}
/*
* Ignore spurious performance messages
*/
m_gl->debugMessageControl(GL_DONT_CARE /* source */, GL_DEBUG_TYPE_PERFORMANCE /* type */,
GL_DONT_CARE /* severity */, 0 /* counts */, 0 /* ids */, GL_FALSE /* enabled */);
/*
* - insert a message with DebugMessageInsert;
* - inspect message log to check if the message is reported;
* - inspect message log again, there should be no messages;
*/
{
GLchar messageLog[bufSize];
GLenum sources[read_messages];
GLenum types[read_messages];
GLuint ids[read_messages];
GLenum severities[read_messages];
GLsizei lengths[read_messages];
cleanMessageLog(m_gl);
m_gl->debugMessageInsert(GL_DEBUG_SOURCE_APPLICATION /* source */, GL_DEBUG_TYPE_ERROR /* type */, 11 /* id */,
GL_DEBUG_SEVERITY_HIGH /* severity */, label_length /* length */, label);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "DebugMessageInsert");
GLuint ret = m_gl->getDebugMessageLog(read_messages /* count */, bufSize /* bufSize */, sources /* sources */,
types /* types */, ids /* ids */, severities /* severities */,
lengths /* lengths */, messageLog /* messageLog */);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "GetDebugMessageLog");
if (1 != ret)
{
m_testCtx.getLog() << tcu::TestLog::Message
<< "GetDebugMessageLog returned invalid number of messages: " << ret
<< ", expected 1" << tcu::TestLog::EndMessage;
TCU_FAIL("Invalid value returned by GetDebugMessageLog");
}
if (GL_DEBUG_SOURCE_APPLICATION != sources[0])
{
TCU_FAIL("Invalid source value returned by GetDebugMessageLog");
}
if (GL_DEBUG_TYPE_ERROR != types[0])
{
TCU_FAIL("Invalid type value returned by GetDebugMessageLog");
}
if (11 != ids[0])
{
TCU_FAIL("Invalid id value returned by GetDebugMessageLog");
}
if (GL_DEBUG_SEVERITY_HIGH != severities[0])
{
TCU_FAIL("Invalid severity value returned by GetDebugMessageLog");
}
// DebugMessageInsert's length does not include null-terminated character (if length is positive)
// But GetDebugMessageLog's length include null-terminated character
// OpenGL 4.5 Core Spec, Page 530 and Page 535
if (label_length + 1 != lengths[0])
{
TCU_FAIL("Invalid length value returned by GetDebugMessageLog");
}
if (0 != strcmp(label, messageLog))
{
TCU_FAIL("Invalid message returned by GetDebugMessageLog");
}
}
/*
* - disable DEBUG_OUTPUT;
* - insert a message with DebugMessageInsert;
* - inspect message log again, there should be no messages;
*/
{
m_gl->disable(GL_DEBUG_OUTPUT);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "Disable");
m_gl->debugMessageInsert(GL_DEBUG_SOURCE_APPLICATION /* source */, GL_DEBUG_TYPE_ERROR /* type */, 11 /* id */,
GL_DEBUG_SEVERITY_HIGH /* severity */, label_length /* length */, label);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "DebugMessageInsert");
inspectMessageLog(0);
}
/*
* - enable DEBUG_OUTPUT;
* - register debug message callback with DebugMessageCallback;
* - verify that the state of DEBUG_CALLBACK_FUNCTION and
* DEBUG_CALLBACK_USER_PARAM are correct;
* - insert a message with DebugMessageInsert;
* - it is expected that debug message callback will be executed for
* the message;
* - inspect message log to check there are no messages;
*/
{
m_gl->enable(GL_DEBUG_OUTPUT);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "Enable");
m_gl->debugMessageCallback(debug_proc, &callback_counter);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "DebugMessageCallback");
inspectDebugState(GL_TRUE, debug_proc, &callback_counter);
m_gl->debugMessageInsert(GL_DEBUG_SOURCE_APPLICATION /* source */, GL_DEBUG_TYPE_ERROR /* type */, 11 /* id */,
GL_DEBUG_SEVERITY_HIGH /* severity */, label_length /* length */, label);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "DebugMessageInsert");
inspectCallbackCounter(callback_counter, 1);
inspectMessageLog(0);
}
/*
* - disable DEBUG_OUTPUT;
* - insert a message with DebugMessageInsert;
* - debug message callback should not be called;
* - inspect message log to check there are no messages;
*/
{
m_gl->disable(GL_DEBUG_OUTPUT);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "Disable");
m_gl->debugMessageInsert(GL_DEBUG_SOURCE_APPLICATION /* source */, GL_DEBUG_TYPE_ERROR /* type */, 11 /* id */,
GL_DEBUG_SEVERITY_HIGH /* severity */, label_length /* length */, label);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "DebugMessageInsert");
inspectCallbackCounter(callback_counter, 1);
inspectMessageLog(0);
}
/*
* - enable DEBUG_OUTPUT;
* - execute DebugMessageControl with <type> DEBUG_TYPE_ERROR, <severity>
* DEBUG_SEVERITY_HIGH and <enabled> FALSE;
* - insert a message with DebugMessageInsert, set <type> to DEBUG_TYPE_ERROR
* and <severity> DEBUG_SEVERITY_MEDIUM;
* - insert a message with DebugMessageInsert, set <type> to DEBUG_TYPE_OTHER
* and <severity> DEBUG_SEVERITY_HIGH;
* - insert a message with DebugMessageInsert, set <type> to DEBUG_TYPE_OTHER
* and <severity> DEBUG_SEVERITY_LOW;
* - debug message callback should not be called;
* - inspect message log to check there are no messages;
*/
{
m_gl->enable(GL_DEBUG_OUTPUT);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "Enable");
m_gl->debugMessageControl(GL_DONT_CARE /* source */, GL_DEBUG_TYPE_ERROR /* type */,
GL_DONT_CARE /* severity */, 0 /* counts */, 0 /* ids */, GL_FALSE /* enabled */);
m_gl->debugMessageControl(GL_DONT_CARE /* source */, GL_DONT_CARE /* type */,
GL_DEBUG_SEVERITY_HIGH /* severity */, 0 /* counts */, 0 /* ids */,
GL_FALSE /* enabled */);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "DebugMessageControl");
m_gl->debugMessageInsert(GL_DEBUG_SOURCE_APPLICATION /* source */, GL_DEBUG_TYPE_ERROR /* type */, 11 /* id */,
GL_DEBUG_SEVERITY_MEDIUM /* severity */, label_length /* length */, label);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "DebugMessageInsert");
m_gl->debugMessageInsert(GL_DEBUG_SOURCE_APPLICATION /* source */, GL_DEBUG_TYPE_OTHER /* type */, 11 /* id */,
GL_DEBUG_SEVERITY_HIGH /* severity */, label_length /* length */, label);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "DebugMessageInsert");
m_gl->debugMessageInsert(GL_DEBUG_SOURCE_APPLICATION /* source */, GL_DEBUG_TYPE_OTHER /* type */, 11 /* id */,
GL_DEBUG_SEVERITY_LOW /* severity */, label_length /* length */, label);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "DebugMessageInsert");
inspectCallbackCounter(callback_counter, 1);
inspectMessageLog(0);
}
/*
* - set NULL as debug message callback;
* - verify that state of DEBUG_CALLBACK_FUNCTION and
* DEBUG_CALLBACK_USER_PARAM are NULL;
* - insert a message with DebugMessageInsert, set <type> to DEBUG_TYPE_ERROR
* and <severity> DEBUG_SEVERITY_MEDIUM;
* - insert a message with DebugMessageInsert, set <type> to DEBUG_TYPE_OTHER
* and <severity> DEBUG_SEVERITY_HIGH;
* - insert a message with DebugMessageInsert, set <type> to DEBUG_TYPE_OTHER
* and <severity> DEBUG_SEVERITY_LOW;
* - inspect message log to check there are no messages;
*/
{
m_gl->debugMessageCallback(0, 0);
inspectDebugState(GL_TRUE, 0, 0);
m_gl->debugMessageInsert(GL_DEBUG_SOURCE_APPLICATION /* source */, GL_DEBUG_TYPE_ERROR /* type */, 11 /* id */,
GL_DEBUG_SEVERITY_MEDIUM /* severity */, label_length /* length */, label);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "DebugMessageInsert");
m_gl->debugMessageInsert(GL_DEBUG_SOURCE_APPLICATION /* source */, GL_DEBUG_TYPE_OTHER /* type */, 11 /* id */,
GL_DEBUG_SEVERITY_HIGH /* severity */, label_length /* length */, label);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "DebugMessageInsert");
m_gl->debugMessageInsert(GL_DEBUG_SOURCE_APPLICATION /* source */, GL_DEBUG_TYPE_OTHER /* type */, 11 /* id */,
GL_DEBUG_SEVERITY_LOW /* severity */, label_length /* length */, label);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "DebugMessageInsert");
inspectMessageLog(0);
}
/*
* - execute DebugMessageControl to enable messages of <type> DEBUG_TYPE_ERROR
* and <severity> DEBUG_SEVERITY_HIGH.
*/
{
m_gl->debugMessageControl(GL_DONT_CARE /* source */, GL_DEBUG_TYPE_ERROR /* type */,
GL_DONT_CARE /* severity */, 0 /* counts */, 0 /* ids */, GL_TRUE /* enabled */);
m_gl->debugMessageControl(GL_DONT_CARE /* source */, GL_DONT_CARE /* type */,
GL_DEBUG_SEVERITY_HIGH /* severity */, 0 /* counts */, 0 /* ids */,
GL_TRUE /* enabled */);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "DebugMessageControl");
}
/*
* - insert MAX_DEBUG_LOGGED_MESSAGES + 1 unique messages with
* DebugMessageInsert;
* - check state of DEBUG_LOGGED_MESSAGES; It is expected that
* MAX_DEBUG_LOGGED_MESSAGES will be reported;
*/
{
for (GLint i = 0; i < max_debug_messages + 1; ++i)
{
m_gl->debugMessageInsert(GL_DEBUG_SOURCE_APPLICATION /* source */, GL_DEBUG_TYPE_ERROR /* type */,
i /* id */, GL_DEBUG_SEVERITY_MEDIUM /* severity */, label_length /* length */,
label);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "DebugMessageInsert");
}
GLint n_debug_messages = 0;
m_gl->getIntegerv(GL_DEBUG_LOGGED_MESSAGES, &n_debug_messages);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "GetIntegerv");
if (n_debug_messages != max_debug_messages)
{
m_testCtx.getLog()
<< tcu::TestLog::Message << "State of DEBUG_LOGGED_MESSAGES: " << n_debug_messages << ", expected "
<< max_debug_messages << tcu::TestLog::EndMessage;
TCU_FAIL("Invalid state of DEBUG_LOGGED_MESSAGES");
}
}
/*
* If MAX_DEBUG_LOGGED_MESSAGES is greater than 1:
* - inspect first half of the message log by specifying proper <count>; Verify
* that messages are reported in order from the oldest to the newest; Check
* that <count> messages were stored into provided buffers;
* - check state of DEBUG_LOGGED_MESSAGES; It is expected that <count> messages
* were removed from log;
* - inspect rest of the message log with <bufSize> too small to held last
* message; Verify that messages are reported in order from the oldest to the
* newest; Verify that maximum <bufSize> characters were written to
* <messageLog>;
* - check state of DEBUG_LOGGED_MESSAGES; It is expected that one message is
* available;
* - fetch the message and verify it is the newest one;
*/
if (1 != max_debug_messages)
{
GLint half_count = max_debug_messages / 2;
GLint n_debug_messages = 0;
GLint rest_count = max_debug_messages - half_count;
GLsizei buf_size = (GLsizei)((half_count + 1) * (label_length + 1));
std::vector<GLchar> messageLog;
std::vector<GLenum> sources;
std::vector<GLenum> types;
std::vector<GLuint> ids;
std::vector<GLenum> severities;
std::vector<GLsizei> lengths;
messageLog.resize(buf_size);
sources.resize(half_count + 1);
types.resize(half_count + 1);
ids.resize(half_count + 1);
severities.resize(half_count + 1);
lengths.resize(half_count + 1);
GLuint ret = m_gl->getDebugMessageLog(half_count /* count */, buf_size /* bufSize */, &sources[0] /* sources */,
&types[0] /* types */, &ids[0] /* ids */, &severities[0] /* severities */,
&lengths[0] /* lengths */, &messageLog[0] /* messageLog */);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "GetDebugMessageLog");
if (ret != (GLuint)half_count)
{
m_testCtx.getLog() << tcu::TestLog::Message
<< "GetDebugMessageLog returned unexpected number of messages: " << ret
<< ", expected " << half_count << tcu::TestLog::EndMessage;
TCU_FAIL("Invalid number of meessages");
}
m_gl->getIntegerv(GL_DEBUG_LOGGED_MESSAGES, &n_debug_messages);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "GetIntegerv");
if (n_debug_messages != rest_count)
{
m_testCtx.getLog()
<< tcu::TestLog::Message << "State of DEBUG_LOGGED_MESSAGES: " << n_debug_messages << ", expected "
<< rest_count << tcu::TestLog::EndMessage;
TCU_FAIL("Invalid state of DEBUG_LOGGED_MESSAGES");
}
for (GLint i = 0; i < half_count; ++i)
{
if (GL_DEBUG_SOURCE_APPLICATION != sources[i])
{
TCU_FAIL("Invalid source value returned by GetDebugMessageLog");
}
if (GL_DEBUG_TYPE_ERROR != types[i])
{
TCU_FAIL("Invalid type value returned by GetDebugMessageLog");
}
if ((GLuint)i != ids[i])
{
TCU_FAIL("Invalid id value returned by GetDebugMessageLog");
}
if (GL_DEBUG_SEVERITY_MEDIUM != severities[i])
{
TCU_FAIL("Invalid severity value returned by GetDebugMessageLog");
}
// DebugMessageInsert's length does not include null-terminated character (if length is positive)
// But GetDebugMessageLog's length include null-terminated character
// OpenGL 4.5 Core Spec, Page 530 and Page 535
if (label_length + 1 != lengths[i])
{
TCU_FAIL("Invalid length value returned by GetDebugMessageLog");
}
if (0 != strcmp(label, &messageLog[i * (label_length + 1)]))
{
TCU_FAIL("Invalid message returned by GetDebugMessageLog");
}
}
/* */
buf_size = (GLsizei)((rest_count - 1) * (label_length + 1) + label_length);
memset(&messageLog[0], 0, messageLog.size());
ret = m_gl->getDebugMessageLog(rest_count /* count */, buf_size /* bufSize */, &sources[0] /* sources */,
&types[0] /* types */, &ids[0] /* ids */, &severities[0] /* severities */,
&lengths[0] /* lengths */, &messageLog[0] /* messageLog */);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "GetDebugMessageLog");
if (ret != (GLuint)(rest_count - 1))
{
m_testCtx.getLog() << tcu::TestLog::Message
<< "GetDebugMessageLog returned unexpected number of messages: " << ret
<< ", expected " << (rest_count - 1) << tcu::TestLog::EndMessage;
TCU_FAIL("Invalid number of meessages");
}
m_gl->getIntegerv(GL_DEBUG_LOGGED_MESSAGES, &n_debug_messages);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "GetIntegerv");
if (n_debug_messages != 1)
{
m_testCtx.getLog()
<< tcu::TestLog::Message << "State of DEBUG_LOGGED_MESSAGES: " << n_debug_messages << ", expected "
<< (rest_count - 1) << tcu::TestLog::EndMessage;
TCU_FAIL("Invalid state of DEBUG_LOGGED_MESSAGES");
}
for (GLint i = 0; i < (rest_count - 1); ++i)
{
if (GL_DEBUG_SOURCE_APPLICATION != sources[i])
{
TCU_FAIL("Invalid source value returned by GetDebugMessageLog");
}
if (GL_DEBUG_TYPE_ERROR != types[i])
{
TCU_FAIL("Invalid type value returned by GetDebugMessageLog");
}
if ((GLuint)(i + half_count) != ids[i])
{
TCU_FAIL("Invalid id value returned by GetDebugMessageLog");
}
if (GL_DEBUG_SEVERITY_MEDIUM != severities[i])
{
TCU_FAIL("Invalid severity value returned by GetDebugMessageLog");
}
// DebugMessageInsert's length does not include null-terminated character (if length is positive)
// But GetDebugMessageLog's length include null-terminated character
// OpenGL 4.5 Core Spec, Page 530 and Page 535
if (label_length + 1 != lengths[i])
{
TCU_FAIL("Invalid length value returned by GetDebugMessageLog");
}
if (0 != strcmp(label, &messageLog[i * (label_length + 1)]))
{
TCU_FAIL("Invalid message returned by GetDebugMessageLog");
}
}
/* */
memset(&messageLog[0], 0, messageLog.size());
ret = m_gl->getDebugMessageLog(rest_count /* count */, buf_size /* bufSize */, &sources[0] /* sources */,
&types[0] /* types */, &ids[0] /* ids */, &severities[0] /* severities */,
&lengths[0] /* lengths */, &messageLog[0] /* messageLog */);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "GetDebugMessageLog");
if (ret != 1)
{
m_testCtx.getLog() << tcu::TestLog::Message
<< "GetDebugMessageLog returned unexpected number of messages: " << ret
<< ", expected 1" << tcu::TestLog::EndMessage;
TCU_FAIL("Invalid number of meessages");
}
m_gl->getIntegerv(GL_DEBUG_LOGGED_MESSAGES, &n_debug_messages);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "GetIntegerv");
if (n_debug_messages != 0)
{
m_testCtx.getLog()
<< tcu::TestLog::Message << "State of DEBUG_LOGGED_MESSAGES: " << n_debug_messages << ", expected 1"
<< tcu::TestLog::EndMessage;
TCU_FAIL("Invalid state of DEBUG_LOGGED_MESSAGES");
}
if (GL_DEBUG_SOURCE_APPLICATION != sources[0])
{
TCU_FAIL("Invalid source value returned by GetDebugMessageLog");
}
if (GL_DEBUG_TYPE_ERROR != types[0])
{
TCU_FAIL("Invalid type value returned by GetDebugMessageLog");
}
if ((GLuint)(max_debug_messages - 1) != ids[0])
{
TCU_FAIL("Invalid id value returned by GetDebugMessageLog");
}
if (GL_DEBUG_SEVERITY_MEDIUM != severities[0])
{
TCU_FAIL("Invalid severity value returned by GetDebugMessageLog");
}
// DebugMessageInsert's length does not include null-terminated character (if length is positive)
// But GetDebugMessageLog's length include null-terminated character
// OpenGL 4.5 Core Spec, Page 530 and Page 535
if (label_length + 1 != lengths[0])
{
TCU_FAIL("Invalid length value returned by GetDebugMessageLog");
}
if (0 != strcmp(label, &messageLog[0]))
{
TCU_FAIL("Invalid message returned by GetDebugMessageLog");
}
}
/* Set result */
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
/* Done */
TestBase::done();
return tcu::TestNode::STOP;
}
/** Debug callback used by the test, increase counter by one
*
* @param ignored
* @param ignored
* @param ignored
* @param ignored
* @param ignored
* @param ignored
* @param info Pointer to uint counter
**/
void ReceivingMessagesTest::debug_proc(glw::GLenum /* source */, glw::GLenum /* type */, glw::GLuint /* id */,
glw::GLenum /* severity */, glw::GLsizei /* length */,
const glw::GLchar* /* message */, const void* info)
{
GLuint* counter = (GLuint*)info;
*counter += 1;
}
/** Inspects state of DEBUG_OUTPUT and debug callback
*
* @param expected_state Expected state of DEBUG_OUTPUT
* @param expected_callback Expected state of DEBUG_CALLBACK_FUNCTION
* @param expected_user_info Expected state of DEBUG_CALLBACK_USER_PARAM
**/
void ReceivingMessagesTest::inspectDebugState(GLboolean expected_state, GLDEBUGPROC expected_callback,
GLvoid* expected_user_info) const
{
GLboolean debug_state = -1;
m_gl->getBooleanv(GL_DEBUG_OUTPUT, &debug_state);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "GetBooleanv");
if (expected_state != debug_state)
{
m_testCtx.getLog() << tcu::TestLog::Message << "State of DEBUG_OUTPUT: " << debug_state
<< ", expected " << expected_state << tcu::TestLog::EndMessage;
TCU_FAIL("Invalid state of DEBUG_OUTPUT");
}
GLvoid* callback_procedure = 0;
m_gl->getPointerv(GL_DEBUG_CALLBACK_FUNCTION, &callback_procedure);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "GetPointerv");
if (expected_callback != callback_procedure)
{
TCU_FAIL("Invalid state of DEBUG_CALLBACK_FUNCTION");
}
GLvoid* callback_user_info = 0;
m_gl->getPointerv(GL_DEBUG_CALLBACK_USER_PARAM, &callback_user_info);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "GetPointerv");
if (expected_user_info != callback_user_info)
{
TCU_FAIL("Invalid state of DEBUG_CALLBACK_USER_PARAM");
}
}
/** Inspects value of counter used by callback
*
* @param callback_counter Reference to counter
* @param expected_number_of_messages Expected value of counter
**/
void ReceivingMessagesTest::inspectCallbackCounter(GLuint& callback_counter, GLuint expected_number_of_messages) const
{
m_gl->finish();
GLU_EXPECT_NO_ERROR(m_gl->getError(), "Finish");
if (expected_number_of_messages != callback_counter)
{
m_testCtx.getLog()
<< tcu::TestLog::Message << "Debug callback was executed invalid number of times: " << callback_counter
<< ", expected " << expected_number_of_messages << tcu::TestLog::EndMessage;
TCU_FAIL("Invalid execution of debug callback");
}
}
/** Inspects amount of messages stored in log
*
* @param expected_number_of_messages Expected number of messages
**/
void ReceivingMessagesTest::inspectMessageLog(GLuint expected_number_of_messages) const
{
static const size_t bufSize = 32;
static const size_t read_messages = 4;
GLchar messageLog[bufSize];
GLenum sources[read_messages];
GLenum types[read_messages];
GLuint ids[read_messages];
GLenum severities[read_messages];
GLsizei lengths[read_messages];
GLuint ret = m_gl->getDebugMessageLog(read_messages /* count */, bufSize /* bufSize */, sources /* sources */,
types /* types */, ids /* ids */, severities /* severities */,
lengths /* lengths */, messageLog /* messageLog */);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "GetDebugMessageLog");
if (expected_number_of_messages != ret)
{
m_testCtx.getLog() << tcu::TestLog::Message
<< "GetDebugMessageLog returned invalid number of messages: " << ret
<< ", expected " << expected_number_of_messages << tcu::TestLog::EndMessage;
TCU_FAIL("Invalid value returned by GetDebugMessageLog");
}
}
/** Constructor
*
* @param testCtx Test context
* @param is_debug Selects if debug or non-debug context should be used
* @param name Name of test
**/
GroupsTest::GroupsTest(tcu::TestContext& testCtx, glu::ApiType apiType)
: TestCase(testCtx, "groups", "Verifies that groups can be used to control generated messages")
, TestBase(testCtx, apiType, true /* is_debug */)
{
/* Nothing to be done */
}
/** Execute test
*
* @return tcu::TestNode::STOP
**/
tcu::TestNode::IterateResult GroupsTest::iterate()
{
static const GLchar label[] = "foo";
static const size_t label_length = sizeof(label) / sizeof(label[0]) - 1;
/* Initialize render context */
TestBase::init();
cleanMessageLog(m_gl);
/*
* - check state of DEBUG_GROUP_STACK_DEPTH; It should be 1;
*/
inspectGroupStack(1);
/*
* - insert message with <type> DEBUG_TYPE_ERROR;
* - inspect message log to check if the message is reported;
* - insert message with <type> DEBUG_TYPE_OTHER;
* - inspect message log to check if the message is reported;
*/
{
m_gl->debugMessageInsert(GL_DEBUG_SOURCE_APPLICATION /* source */, GL_DEBUG_TYPE_ERROR /* type */, 11 /* id */,
GL_DEBUG_SEVERITY_HIGH /* severity */, label_length /* length */, label);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "DebugMessageInsert");
inspectMessageLog(GL_DEBUG_SOURCE_APPLICATION /* source */, GL_DEBUG_TYPE_ERROR /* type */, 11 /* id */,
GL_DEBUG_SEVERITY_HIGH /* severity */, label_length /* length */, label);
m_gl->debugMessageInsert(GL_DEBUG_SOURCE_APPLICATION /* source */, GL_DEBUG_TYPE_OTHER /* type */, 11 /* id */,
GL_DEBUG_SEVERITY_HIGH /* severity */, label_length /* length */, label);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "DebugMessageInsert");
inspectMessageLog(GL_DEBUG_SOURCE_APPLICATION /* source */, GL_DEBUG_TYPE_OTHER /* type */, 11 /* id */,
GL_DEBUG_SEVERITY_HIGH /* severity */, label_length /* length */, label);
}
/*
* - push debug group with unique <id> and <message>;
* - inspect message log to check if the message about push is reported;
* - disable messages with <type> DEBUG_TYPE_ERROR;
* - insert message with <type> DEBUG_TYPE_ERROR;
* - inspect message log to check there are no messages;
* - insert message with <type> DEBUG_TYPE_OTHER;
* - inspect message log to check if the message is reported;
*/
{
m_gl->pushDebugGroup(GL_DEBUG_SOURCE_APPLICATION /* source */, 0xabcd0123 /* id */, -1 /* length */, label);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "PushDebugGroup");
inspectMessageLog(GL_DEBUG_SOURCE_APPLICATION /* source */, GL_DEBUG_TYPE_PUSH_GROUP /* type */,
0xabcd0123 /* id */, GL_DEBUG_SEVERITY_NOTIFICATION /* severity */, label_length /* length */,
label);
m_gl->debugMessageControl(GL_DONT_CARE /* source */, GL_DEBUG_TYPE_ERROR /* type */,
GL_DONT_CARE /* severity */, 0 /* counts */, 0 /* ids */, GL_FALSE /* enabled */);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "DebugMessageControl");
m_gl->debugMessageInsert(GL_DEBUG_SOURCE_APPLICATION /* source */, GL_DEBUG_TYPE_ERROR /* type */, 11 /* id */,
GL_DEBUG_SEVERITY_HIGH /* severity */, label_length /* length */, label);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "DebugMessageInsert");
verifyEmptyLog();
m_gl->debugMessageInsert(GL_DEBUG_SOURCE_APPLICATION /* source */, GL_DEBUG_TYPE_OTHER /* type */, 11 /* id */,
GL_DEBUG_SEVERITY_HIGH /* severity */, label_length /* length */, label);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "DebugMessageInsert");
inspectMessageLog(GL_DEBUG_SOURCE_APPLICATION /* source */, GL_DEBUG_TYPE_OTHER /* type */, 11 /* id */,
GL_DEBUG_SEVERITY_HIGH /* severity */, label_length /* length */, label);
}
/*
* - check state of DEBUG_GROUP_STACK_DEPTH; It should be 2;
*/
inspectGroupStack(2);
/*
* - push debug group with unique <id> and <message>;
* - inspect message log to check if the message about push is reported;
* - disable messages with <type> DEBUG_TYPE_OTHER;
* - insert message with <type> DEBUG_TYPE_ERROR;
* - inspect message log to check there are no messages;
* - insert message with <type> DEBUG_TYPE_OTHER;
* - inspect message log to check there are no messages;
*/
{
m_gl->pushDebugGroup(GL_DEBUG_SOURCE_APPLICATION /* source */, 0x0123abcd /* id */, -1 /* length */, label);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "PushDebugGroup");
inspectMessageLog(GL_DEBUG_SOURCE_APPLICATION /* source */, GL_DEBUG_TYPE_PUSH_GROUP /* type */,
0x0123abcd /* id */, GL_DEBUG_SEVERITY_NOTIFICATION /* severity */, label_length /* length */,
label);
m_gl->debugMessageControl(GL_DONT_CARE /* source */, GL_DEBUG_TYPE_OTHER /* type */,
GL_DONT_CARE /* severity */, 0 /* counts */, 0 /* ids */, GL_FALSE /* enabled */);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "DebugMessageControl");
m_gl->debugMessageInsert(GL_DEBUG_SOURCE_APPLICATION /* source */, GL_DEBUG_TYPE_ERROR /* type */, 11 /* id */,
GL_DEBUG_SEVERITY_HIGH /* severity */, label_length /* length */, label);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "DebugMessageInsert");
verifyEmptyLog();
m_gl->debugMessageInsert(GL_DEBUG_SOURCE_APPLICATION /* source */, GL_DEBUG_TYPE_OTHER /* type */, 11 /* id */,
GL_DEBUG_SEVERITY_HIGH /* severity */, label_length /* length */, label);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "DebugMessageInsert");
verifyEmptyLog();
}
/*
* - check state of DEBUG_GROUP_STACK_DEPTH; It should be 3;
*/
inspectGroupStack(3);
/*
* - pop debug group;
* - inspect message log to check if the message about pop is reported and
* corresponds with the second push;
* - insert message with <type> DEBUG_TYPE_ERROR;
* - inspect message log to check there are no messages;
* - insert message with <type> DEBUG_TYPE_OTHER;
* - inspect message log to check if the message is reported;
*/
{
m_gl->popDebugGroup();
GLU_EXPECT_NO_ERROR(m_gl->getError(), "PopDebugGroup");
inspectMessageLog(GL_DEBUG_SOURCE_APPLICATION /* source */, GL_DEBUG_TYPE_POP_GROUP /* type */,
0x0123abcd /* id */, GL_DEBUG_SEVERITY_NOTIFICATION /* severity */, label_length /* length */,
label);
m_gl->debugMessageInsert(GL_DEBUG_SOURCE_APPLICATION /* source */, GL_DEBUG_TYPE_ERROR /* type */, 11 /* id */,
GL_DEBUG_SEVERITY_HIGH /* severity */, label_length /* length */, label);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "DebugMessageInsert");
verifyEmptyLog();
m_gl->debugMessageInsert(GL_DEBUG_SOURCE_APPLICATION /* source */, GL_DEBUG_TYPE_OTHER /* type */, 11 /* id */,
GL_DEBUG_SEVERITY_HIGH /* severity */, label_length /* length */, label);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "DebugMessageInsert");
inspectMessageLog(GL_DEBUG_SOURCE_APPLICATION /* source */, GL_DEBUG_TYPE_OTHER /* type */, 11 /* id */,
GL_DEBUG_SEVERITY_HIGH /* severity */, label_length /* length */, label);
}
/*
* - check state of DEBUG_GROUP_STACK_DEPTH; It should be 2;
*/
inspectGroupStack(2);
/*
* - pop debug group;
* - inspect message log to check if the message about pop is reported and
* corresponds with the first push;
* - insert message with <type> DEBUG_TYPE_ERROR;
* - inspect message log to check if the message is reported;
* - insert message with <type> DEBUG_TYPE_OTHER;
* - inspect message log to check if the message is reported;
*/
{
m_gl->popDebugGroup();
GLU_EXPECT_NO_ERROR(m_gl->getError(), "PopDebugGroup");
inspectMessageLog(GL_DEBUG_SOURCE_APPLICATION /* source */, GL_DEBUG_TYPE_POP_GROUP /* type */,
0xabcd0123 /* id */, GL_DEBUG_SEVERITY_NOTIFICATION /* severity */, label_length /* length */,
label);
m_gl->debugMessageInsert(GL_DEBUG_SOURCE_APPLICATION /* source */, GL_DEBUG_TYPE_ERROR /* type */, 11 /* id */,
GL_DEBUG_SEVERITY_HIGH /* severity */, label_length /* length */, label);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "DebugMessageInsert");
inspectMessageLog(GL_DEBUG_SOURCE_APPLICATION /* source */, GL_DEBUG_TYPE_ERROR /* type */, 11 /* id */,
GL_DEBUG_SEVERITY_HIGH /* severity */, label_length /* length */, label);
m_gl->debugMessageInsert(GL_DEBUG_SOURCE_APPLICATION /* source */, GL_DEBUG_TYPE_OTHER /* type */, 11 /* id */,
GL_DEBUG_SEVERITY_HIGH /* severity */, label_length /* length */, label);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "DebugMessageInsert");
inspectMessageLog(GL_DEBUG_SOURCE_APPLICATION /* source */, GL_DEBUG_TYPE_OTHER /* type */, 11 /* id */,
GL_DEBUG_SEVERITY_HIGH /* severity */, label_length /* length */, label);
}
/*
* - check state of DEBUG_GROUP_STACK_DEPTH; It should be 1;
*/
inspectGroupStack(1);
/* Set result */
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
/* Done */
TestBase::done();
return tcu::TestNode::STOP;
}
/** Inspects amount of groups on stack
*
* @param expected_depth Expected number of groups
**/
void GroupsTest::inspectGroupStack(GLuint expected_depth) const
{
GLint stack_depth = 0;
m_gl->getIntegerv(GL_DEBUG_GROUP_STACK_DEPTH, &stack_depth);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "GetIntegerv");
if (expected_depth != (GLuint)stack_depth)
{
m_testCtx.getLog() << tcu::TestLog::Message
<< "State of DEBUG_GROUP_STACK_DEPTH: " << stack_depth << ", expected "
<< expected_depth << tcu::TestLog::EndMessage;
TCU_FAIL("Invalid state of DEBUG_GROUP_STACK_DEPTH");
}
}
/** Inspects first message stored in log
*
* @param expected_source Expected source of messages
* @param expected_type Expected type of messages
* @param expected_id Expected id of messages
* @param expected_severity Expected severity of messages
* @param expected_length Expected length of messages
* @param expected_label Expected label of messages
**/
void GroupsTest::inspectMessageLog(glw::GLenum expected_source, glw::GLenum expected_type, glw::GLuint expected_id,
glw::GLenum expected_severity, glw::GLsizei expected_length,
const glw::GLchar* expected_label) const
{
static const size_t bufSize = 32;
static const size_t read_messages = 1;
GLchar messageLog[bufSize];
GLenum source;
GLenum type;
GLuint id;
GLenum severity;
GLsizei length;
GLuint ret = m_gl->getDebugMessageLog(read_messages /* count */, bufSize /* bufSize */, &source /* sources */,
&type /* types */, &id /* ids */, &severity /* severities */,
&length /* lengths */, messageLog /* messageLog */);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "GetDebugMessageLog");
if (0 == ret)
{
TCU_FAIL("GetDebugMessageLog returned 0 messages");
}
if (expected_source != source)
{
m_testCtx.getLog() << tcu::TestLog::Message << "Got message with invalid source: " << source
<< ", expected " << expected_source << tcu::TestLog::EndMessage;
TCU_FAIL("Invalid source of message");
}
if (expected_type != type)
{
m_testCtx.getLog() << tcu::TestLog::Message << "Got message with invalid type: " << type
<< ", expected " << expected_type << tcu::TestLog::EndMessage;
TCU_FAIL("Invalid type of message");
}
if (expected_id != id)
{
m_testCtx.getLog() << tcu::TestLog::Message << "Got message with invalid id: " << id
<< ", expected " << expected_id << tcu::TestLog::EndMessage;
TCU_FAIL("Invalid id of message");
}
if (expected_severity != severity)
{
m_testCtx.getLog() << tcu::TestLog::Message
<< "Got message with invalid severity: " << severity << ", expected "
<< expected_severity << tcu::TestLog::EndMessage;
TCU_FAIL("Invalid severity of message");
}
// DebugMessageInsert's length does not include null-terminated character (if length is positive)
// But GetDebugMessageLog's length include null-terminated character
// OpenGL 4.5 Core Spec, Page 530 and Page 535
if (expected_length + 1 != length)
{
m_testCtx.getLog() << tcu::TestLog::Message << "Got message with invalid length: " << length
<< ", expected " << expected_length << tcu::TestLog::EndMessage;
TCU_FAIL("Invalid length of message");
}
if (0 != strcmp(expected_label, messageLog))
{
m_testCtx.getLog() << tcu::TestLog::Message
<< "Got message with invalid message: " << messageLog << ", expected "
<< expected_label << tcu::TestLog::EndMessage;
TCU_FAIL("Invalid message");
}
}
/** Verifies that message log is empty
*
**/
void GroupsTest::verifyEmptyLog() const
{
static const size_t bufSize = 32;
static const size_t read_messages = 1;
GLchar messageLog[bufSize];
GLenum source;
GLenum type;
GLuint id;
GLenum severity;
GLsizei length;
GLuint ret = m_gl->getDebugMessageLog(read_messages /* count */, bufSize /* bufSize */, &source /* sources */,
&type /* types */, &id /* ids */, &severity /* severities */,
&length /* lengths */, messageLog /* messageLog */);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "GetDebugMessageLog");
if (0 != ret)
{
TCU_FAIL("GetDebugMessageLog returned unexpected messages");
}
}
/** Constructor
*
* @param testCtx Test context
* @param is_debug Selects if debug or non-debug context should be used
* @param name Name of test
**/
SynchronousCallsTest::SynchronousCallsTest(tcu::TestContext& testCtx, glu::ApiType apiType)
: TestCase(testCtx, "synchronous_calls", "Verifies that messages can be received")
, TestBase(testCtx, apiType, true /* is_debug */)
{
/* Create pthread_key_t visible to all threads
* The key has value NULL associated with it in all existing
* or about to be created threads
*/
m_uid = 0;
}
/** Execute test
*
* @return tcu::TestNode::STOP
**/
tcu::TestNode::IterateResult SynchronousCallsTest::iterate()
{
m_uid++;
/* associate some unique id with the current thread */
m_tls.set((void*)(deUintptr)m_uid);
static const GLchar label[] = "foo";
GLuint buffer_id = 0;
/* Initialize render context */
TestBase::init();
/* - set callback_executed to 0; */
int callback_executed = 0;
/*
*- enable DEBUG_OUTPUT_SYNCHRONOUS;
*/
m_gl->enable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "Enable");
/*
* - register debug message callback with DebugMessageCallback; Provide the
* instance of UserParam structure as <userParam>; Routine should do the
* following:
* * set callback_executed to 1;
*/
m_gl->debugMessageCallback(debug_proc, &callback_executed);
try
{
GLU_EXPECT_NO_ERROR(m_gl->getError(), "DebugMessageCallback");
/*
* - insert a message with DebugMessageInsert;
*/
m_gl->debugMessageInsert(GL_DEBUG_SOURCE_APPLICATION /* source */, GL_DEBUG_TYPE_ERROR /* type */, 11 /* id */,
GL_DEBUG_SEVERITY_HIGH /* severity */, -1 /* length */, label);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "DebugMessageInsert");
/* Make sure execution finished before we check results */
m_gl->finish();
GLU_EXPECT_NO_ERROR(m_gl->getError(), "Finish");
/*
* - check if:
* * callback_executed is set to 1;
*/
if (1 != callback_executed)
{
TCU_FAIL("callback_executed is not set to 1");
}
/* Check that the message was recorded by the current thread */
if ((deUintptr)(m_tls.get()) != m_uid)
{
TCU_FAIL("thread id stored by callback is not the same as \"test\" thread");
}
/*
* - reset callback_executed;
*/
callback_executed = 0;
/*
* - execute BindBufferBase with GL_ARRAY_BUFFER <target>, GL_INVALID_ENUM
* error should be generated;
*/
m_gl->genBuffers(1, &buffer_id);
GLU_EXPECT_NO_ERROR(m_gl->getError(), "GenBuffers");
m_gl->bindBufferBase(GL_ARRAY_BUFFER, 0 /* index */, buffer_id);
if (GL_INVALID_ENUM != m_gl->getError())
{
TCU_FAIL("Unexpected error generated");
}
/* Make sure execution finished before we check results */
m_gl->finish();
GLU_EXPECT_NO_ERROR(m_gl->getError(), "Finish");
/*
* - test pass if:
* * callback_executed is set to 0 - implementation does not send messages;
* * callback_executed is set to 1 and thread_id is the same
* as "test" thread - implementation sent message to proper thread;
*/
if (1 == callback_executed)
{
/* Check that the error was recorded by the current thread */
if ((deUintptr)(m_tls.get()) != m_uid)
{
TCU_FAIL("thread id stored by callback is not the same as \"test\" thread");
}
}
/* Clean */
m_gl->deleteBuffers(1, &buffer_id);
buffer_id = 0;
}
catch (const std::exception& exc)
{
if (0 != buffer_id)
{
m_gl->deleteBuffers(1, &buffer_id);
buffer_id = 0;
}
TCU_FAIL(exc.what());
}
/* Set result */
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
/* Done */
TestBase::done();
return tcu::TestNode::STOP;
}
/** Destructor */
SynchronousCallsTest::~SynchronousCallsTest(void)
{
}
/** Debug callback used by the test, sets callback_executed to 1 and stores 0 to tls
*
* @param ignored
* @param ignored
* @param ignored
* @param ignored
* @param ignored
* @param ignored
* @param info Pointer to uint counter
**/
void SynchronousCallsTest::debug_proc(glw::GLenum /* source */, glw::GLenum /* type */, glw::GLuint /* id */,
glw::GLenum /* severity */, glw::GLsizei /* length */,
const glw::GLchar* /* message */, const void* info)
{
int* callback_executed = (int*)info;
*callback_executed = 1;
}
} /* KHRDebug */
/** Constructor.
*
* @param context Rendering context.
**/
KHRDebugTests::KHRDebugTests(tcu::TestContext& testCtx, glu::ApiType apiType)
: TestCaseGroup(testCtx, "khr_debug", "Verifies \"khr debug\" functionality")
, m_apiType(apiType)
{
/* Left blank on purpose */
}
/** Initializes a khr_debug test group.
*
**/
void KHRDebugTests::init(void)
{
addChild(new KHRDebug::APIErrorsTest(m_testCtx, m_apiType, false, "api_errors_non_debug"));
addChild(new KHRDebug::LabelsTest(m_testCtx, m_apiType, false, "labels_non_debug"));
addChild(new KHRDebug::ReceivingMessagesTest(m_testCtx, m_apiType));
addChild(new KHRDebug::GroupsTest(m_testCtx, m_apiType));
addChild(new KHRDebug::APIErrorsTest(m_testCtx, m_apiType, true, "api_errors_debug"));
addChild(new KHRDebug::LabelsTest(m_testCtx, m_apiType, true, "labels_debug"));
addChild(new KHRDebug::SynchronousCallsTest(m_testCtx, m_apiType));
}
} /* glcts namespace */