/*------------------------------------------------------------------------- * drawElements Quality Program EGL Module * --------------------------------------- * * Copyright 2014 The Android Open Source Project * * 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 Extension function pointer query tests. *//*--------------------------------------------------------------------*/ #include "teglGetProcAddressTests.hpp" #include "teglTestCase.hpp" #include "egluCallLogWrapper.hpp" #include "egluStrUtil.hpp" #include "egluUtil.hpp" #include "eglwLibrary.hpp" #include "eglwEnums.hpp" #include "tcuTestLog.hpp" #include "deSTLUtil.hpp" #include "deStringUtil.hpp" namespace deqp { namespace egl { namespace { #define EGL_MAKE_VERSION(major, minor) (((major) << 12) | (minor)) using tcu::TestLog; using namespace eglw; // Function name strings generated from API headers #include "teglGetProcAddressTests.inl" struct FunctionNames { int numFunctions; const char* const* functions; FunctionNames (int numFunctions_, const char* const* functions_) : numFunctions (numFunctions_) , functions (functions_) { } }; FunctionNames getExtFunctionNames (const std::string& extName) { for (int ndx = 0; ndx <= DE_LENGTH_OF_ARRAY(s_extensions); ndx++) { if (extName == s_extensions[ndx].name) return FunctionNames(s_extensions[ndx].numFunctions, s_extensions[ndx].functions); } DE_ASSERT(false); return FunctionNames(0, DE_NULL); } } // anonymous // Base class for eglGetProcAddress() test cases class GetProcAddressCase : public TestCase, protected eglu::CallLogWrapper { public: GetProcAddressCase (EglTestContext& eglTestCtx, const char* name, const char* description); virtual ~GetProcAddressCase (void); void init (void); void deinit (void); IterateResult iterate (void); bool isSupported (const std::string& extName); virtual void executeTest (void) = 0; protected: EGLDisplay m_display; int m_eglVersion; private: std::vector m_supported; }; GetProcAddressCase::GetProcAddressCase (EglTestContext& eglTestCtx, const char* name, const char* description) : TestCase (eglTestCtx, name, description) , CallLogWrapper (eglTestCtx.getLibrary(), eglTestCtx.getTestContext().getLog()) , m_display (EGL_NO_DISPLAY) { } GetProcAddressCase::~GetProcAddressCase (void) { } void GetProcAddressCase::init (void) { try { m_supported = eglu::getClientExtensions(m_eglTestCtx.getLibrary()); } catch (const tcu::NotSupportedError& error) { // Ignore case where EGL client extensions are not supported // that's okay for these tests. } DE_ASSERT(m_display == EGL_NO_DISPLAY); m_display = eglu::getAndInitDisplay(m_eglTestCtx.getNativeDisplay()); // The EGL_VERSION string is laid out as follows: // major_version.minor_version space vendor_specific_info // Split version from vendor_specific_info std::vector tokens = de::splitString(eglQueryString(m_display, EGL_VERSION), ' '); // split version into major & minor std::vector values = de::splitString(tokens[0], '.'); m_eglVersion = EGL_MAKE_VERSION(atoi(values[0].c_str()), atoi(values[1].c_str())); { const std::vector displayExtensios = eglu::getDisplayExtensions(m_eglTestCtx.getLibrary(), m_display); m_supported.insert(m_supported.end(), displayExtensios.begin(), displayExtensios.end()); } m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); } void GetProcAddressCase::deinit (void) { m_eglTestCtx.getLibrary().terminate(m_display); m_display = EGL_NO_DISPLAY; } tcu::TestNode::IterateResult GetProcAddressCase::iterate (void) { enableLogging(true); executeTest(); enableLogging(false); return STOP; } bool GetProcAddressCase::isSupported (const std::string& extName) { return de::contains(m_supported.begin(), m_supported.end(), extName); } // Test by extension class GetProcAddressExtensionCase : public GetProcAddressCase { public: GetProcAddressExtensionCase (EglTestContext& eglTestCtx, const char* name, const char* description, const std::string& extName) : GetProcAddressCase (eglTestCtx, name, description) , m_extName (extName) { } virtual ~GetProcAddressExtensionCase (void) { } void executeTest (void) { TestLog& log = m_testCtx.getLog(); bool supported = isSupported(m_extName); const FunctionNames funcNames = getExtFunctionNames(m_extName); DE_ASSERT(funcNames.numFunctions > 0); log << TestLog::Message << m_extName << ": " << (supported ? "supported" : "not supported") << TestLog::EndMessage; log << TestLog::Message << TestLog::EndMessage; for (int funcNdx = 0; funcNdx < funcNames.numFunctions; funcNdx++) { const char* funcName = funcNames.functions[funcNdx]; void (*funcPtr)(void); funcPtr = eglGetProcAddress(funcName); eglu::checkError(eglGetError(), "eglGetProcAddress()", __FILE__, __LINE__); if (supported && funcPtr == 0) { log << TestLog::Message << "Fail, received null pointer for supported extension function: " << funcName << TestLog::EndMessage; m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Unexpected null pointer"); } } } private: std::string m_extName; }; // Test core functions class GetProcAddressCoreFunctionsCase : public GetProcAddressCase { public: enum ApiType { EGL14, EGL15, GLES, GLES2, GLES3 }; GetProcAddressCoreFunctionsCase (EglTestContext& eglTestCtx, const char* name, const char* description, const ApiType apiType) : GetProcAddressCase (eglTestCtx, name, description) , m_apiType (apiType) { } virtual ~GetProcAddressCoreFunctionsCase (void) { } EGLint RenderableType (ApiType type) { EGLint renderableType = EGL_OPENGL_ES_BIT; switch (type) { case EGL14: case EGL15: case GLES: renderableType = EGL_OPENGL_ES_BIT; break; case GLES2: renderableType = EGL_OPENGL_ES2_BIT; break; case GLES3: renderableType = EGL_OPENGL_ES3_BIT_KHR; break; } return renderableType; } bool isApiSupported (void) { EGLint renderableType = EGL_OPENGL_ES_BIT; switch (m_apiType) { case EGL14: if (m_eglVersion >= EGL_MAKE_VERSION(1, 4)) return true; return false; break; case EGL15: // With Android Q, EGL 1.5 entry points must have valid // GetProcAddress. if (m_eglVersion >= EGL_MAKE_VERSION(1, 5)) return true; return false; break; case GLES: case GLES2: case GLES3: renderableType = RenderableType(m_apiType); break; } return (eglu::getRenderableAPIsMask(m_eglTestCtx.getLibrary(), m_display) & renderableType) == renderableType; } FunctionNames getCoreFunctionNames (EGLint apiType) { switch (apiType) { case EGL14: return FunctionNames(DE_LENGTH_OF_ARRAY(s_EGL14), s_EGL14); case EGL15: return FunctionNames(DE_LENGTH_OF_ARRAY(s_EGL15), s_EGL15); case GLES : return FunctionNames(DE_LENGTH_OF_ARRAY(s_GLES10), s_GLES10); case GLES2: return FunctionNames(DE_LENGTH_OF_ARRAY(s_GLES20), s_GLES20); case GLES3: return FunctionNames(DE_LENGTH_OF_ARRAY(s_GLES30), s_GLES30); default: DE_ASSERT(false); } return FunctionNames(0, DE_NULL); } void executeTest (void) { TestLog& log = m_testCtx.getLog(); const bool funcPtrSupported = isSupported("EGL_KHR_get_all_proc_addresses"); const bool apiSupported = isApiSupported(); const FunctionNames funcNames = getCoreFunctionNames(m_apiType); log << TestLog::Message << "EGL_KHR_get_all_proc_addresses: " << (funcPtrSupported ? "supported" : "not supported") << TestLog::EndMessage; log << TestLog::Message << TestLog::EndMessage; if (!apiSupported) { switch (m_apiType) { case EGL14: log << TestLog::Message << " EGL not supported by any available configuration." << TestLog::EndMessage; break; case EGL15: log << TestLog::Message << " EGL 1.5 not supported by any available configuration." << TestLog::EndMessage; break; case GLES: case GLES2: case GLES3: log << TestLog::Message << eglu::getConfigAttribValueStr(EGL_RENDERABLE_TYPE, RenderableType(m_apiType)) << " not supported by any available configuration." << TestLog::EndMessage; break; } log << TestLog::Message << TestLog::EndMessage; } for (int funcNdx = 0; funcNdx < funcNames.numFunctions; funcNdx++) { const char* funcName = funcNames.functions[funcNdx]; void (*funcPtr)(void); funcPtr = eglGetProcAddress(funcName); eglu::checkError(eglGetError(), "eglGetProcAddress()", __FILE__, __LINE__); if (apiSupported && funcPtrSupported && (funcPtr == 0)) { log << TestLog::Message << "Fail, received null pointer for supported function: " << funcName << TestLog::EndMessage; m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Unexpected null pointer"); } else if (!apiSupported && (funcPtr != 0)) { log << TestLog::Message << "Warning, received non-null value for unsupported function: " << funcName << TestLog::EndMessage; m_testCtx.setTestResult(QP_TEST_RESULT_QUALITY_WARNING, "Non-null value for unsupported function"); } } } private: const ApiType m_apiType; }; GetProcAddressTests::GetProcAddressTests (EglTestContext& eglTestCtx) : TestCaseGroup(eglTestCtx, "get_proc_address", "eglGetProcAddress() tests") { } GetProcAddressTests::~GetProcAddressTests (void) { } void GetProcAddressTests::init (void) { // extensions { tcu::TestCaseGroup* extensionsGroup = new tcu::TestCaseGroup(m_testCtx, "extension", "Test EGL extensions"); addChild(extensionsGroup); for (int extNdx = 0; extNdx < DE_LENGTH_OF_ARRAY(s_extensions); extNdx++) { const std::string& extName = s_extensions[extNdx].name; std::string testName (extName); for (size_t ndx = 0; ndx < extName.length(); ndx++) testName[ndx] = de::toLower(extName[ndx]); extensionsGroup->addChild(new GetProcAddressExtensionCase(m_eglTestCtx, testName.c_str(), ("Test " + extName).c_str(), extName)); } } // core functions { tcu::TestCaseGroup* coreFuncGroup = new tcu::TestCaseGroup(m_testCtx, "core", "Test core functions"); addChild(coreFuncGroup); coreFuncGroup->addChild(new GetProcAddressCoreFunctionsCase (m_eglTestCtx, "egl", "Test EGL core functions", GetProcAddressCoreFunctionsCase::EGL14)); coreFuncGroup->addChild(new GetProcAddressCoreFunctionsCase (m_eglTestCtx, "egl15", "Test EGL 1.5 functions", GetProcAddressCoreFunctionsCase::EGL15)); coreFuncGroup->addChild(new GetProcAddressCoreFunctionsCase (m_eglTestCtx, "gles", "Test OpenGL ES core functions", GetProcAddressCoreFunctionsCase::GLES)); coreFuncGroup->addChild(new GetProcAddressCoreFunctionsCase (m_eglTestCtx, "gles2", "Test OpenGL ES 2 core functions", GetProcAddressCoreFunctionsCase::GLES2)); coreFuncGroup->addChild(new GetProcAddressCoreFunctionsCase (m_eglTestCtx, "gles3", "Test OpenGL ES 3 core functions", GetProcAddressCoreFunctionsCase::GLES3)); } } } // egl } // deqp