/*------------------------------------------------------------------------- * 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 #define DEBUG_ENBALE_MESSAGE_CALLBACK 0 #if DEBUG_ENBALE_MESSAGE_CALLBACK //#include #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 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 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 is invalid; * - INVALID_ENUM when is invalid; * - INVALID_ENUM when is invalid; * - INVALID_VALUE when is negative; * - INVALID_OPERATION when is not zero and is DONT_CARE; * - INVALID_OPERATION when is not zero and is DONT_CARE; * - INVALID_OPERATION when is not zero and 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 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 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 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 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 set to GL_DONT_CARE and non zero "); 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 set to GL_DONT_CARE and non zero "); 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 set to GL_DEBUG_SEVERITY_LOW and non zero "); } /* * GetDebugMessageLog function should generate: * - INVALID_VALUE when 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 set to -1"); } /* * DebugMessageInsert function should generate: * - INVALID_ENUM when is not DEBUG_SOURCE_APPLICATION or * DEBUG_SOURCE_THIRD_PARTY; * - INVALID_ENUM when is invalid; * - INVALID_ENUM when is invalid; * - INVALID_VALUE when length of string 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 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 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 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 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 is not DEBUG_SOURCE_APPLICATION or * DEBUG_SOURCE_THIRD_PARTY; * - INVALID_VALUE when length of string 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 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 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 is invalid; * - INVALID_VALUE when if is not valid object name of type specified by * ; * - INVALID_VALUE when length of string