/*------------------------------------------------------------------------- * drawElements Quality Program EGL Module * --------------------------------------- * * Copyright 2016 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 EGL thread clean up tests *//*--------------------------------------------------------------------*/ #include "teglThreadCleanUpTests.hpp" #include "egluUtil.hpp" #include "egluUnique.hpp" #include "egluConfigFilter.hpp" #include "eglwLibrary.hpp" #include "eglwEnums.hpp" #include "tcuMaybe.hpp" #include "tcuTestLog.hpp" #include "deThread.hpp" namespace deqp { namespace egl { namespace { using namespace eglw; using tcu::TestLog; bool isES2Renderable (const eglu::CandidateConfig& c) { return (c.get(EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES2_BIT) == EGL_OPENGL_ES2_BIT; } bool isPBuffer (const eglu::CandidateConfig& c) { return (c.surfaceType() & EGL_PBUFFER_BIT) == EGL_PBUFFER_BIT; } class Thread : public de::Thread { public: Thread (const Library& egl, EGLDisplay display, EGLSurface surface, EGLContext context, EGLConfig config, tcu::Maybe& error) : m_egl (egl) , m_display (display) , m_surface (surface) , m_context (context) , m_config (config) , m_error (error) { } void testContext (EGLContext context) { if (m_surface != EGL_NO_SURFACE) { EGLU_CHECK_MSG(m_egl, "eglCreateContext"); m_egl.makeCurrent(m_display, m_surface, m_surface, context); EGLU_CHECK_MSG(m_egl, "eglMakeCurrent"); } else { const EGLint attribs[] = { EGL_WIDTH, 32, EGL_HEIGHT, 32, EGL_NONE }; const eglu::UniqueSurface surface (m_egl, m_display, m_egl.createPbufferSurface(m_display, m_config, attribs)); EGLU_CHECK_MSG(m_egl, "eglCreateContext"); m_egl.makeCurrent(m_display, *surface, *surface, context); EGLU_CHECK_MSG(m_egl, "eglMakeCurrent"); } } void run (void) { try { const EGLint attribList[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; m_egl.bindAPI(EGL_OPENGL_ES_API); if (m_context == EGL_NO_CONTEXT) { const eglu::UniqueContext context (m_egl, m_display, m_egl.createContext(m_display, m_config, EGL_NO_CONTEXT, attribList)); testContext(*context); } else { testContext(m_context); } } catch (const eglu::Error& error) { m_error = error; } m_egl.releaseThread(); } private: const Library& m_egl; const EGLDisplay m_display; const EGLSurface m_surface; const EGLContext m_context; const EGLConfig m_config; tcu::Maybe& m_error; }; class ThreadCleanUpTest : public TestCase { public: enum ContextType { CONTEXTTYPE_SINGLE = 0, CONTEXTTYPE_MULTI }; enum SurfaceType { SURFACETYPE_SINGLE = 0, SURFACETYPE_MULTI }; static std::string testCaseName (ContextType contextType, SurfaceType surfaceType) { std::string name; if (contextType == CONTEXTTYPE_SINGLE) name += "single_context_"; else name += "multi_context_"; if (surfaceType ==SURFACETYPE_SINGLE) name += "single_surface"; else name += "multi_surface"; return name; } ThreadCleanUpTest (EglTestContext& eglTestCtx, ContextType contextType, SurfaceType surfaceType) : TestCase (eglTestCtx, testCaseName(contextType, surfaceType).c_str(), "Simple thread context clean up test") , m_contextType (contextType) , m_surfaceType (surfaceType) , m_iterCount (250) , m_iterNdx (0) , m_display (EGL_NO_DISPLAY) , m_config (0) , m_surface (EGL_NO_SURFACE) , m_context (EGL_NO_CONTEXT) { } ~ThreadCleanUpTest (void) { deinit(); } void init (void) { const Library& egl = m_eglTestCtx.getLibrary(); m_display = eglu::getAndInitDisplay(m_eglTestCtx.getNativeDisplay()); { eglu::FilterList filters; filters << isES2Renderable << isPBuffer; m_config = eglu::chooseSingleConfig(egl, m_display, filters); } if (m_contextType == CONTEXTTYPE_SINGLE) { const EGLint attribList[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; egl.bindAPI(EGL_OPENGL_ES_API); m_context = egl.createContext(m_display, m_config, EGL_NO_CONTEXT, attribList); EGLU_CHECK_MSG(egl, "Failed to create context"); } if (m_surfaceType == SURFACETYPE_SINGLE) { const EGLint attribs[] = { EGL_WIDTH, 32, EGL_HEIGHT, 32, EGL_NONE }; m_surface = egl.createPbufferSurface(m_display, m_config, attribs); EGLU_CHECK_MSG(egl, "Failed to create surface"); } } void deinit (void) { const Library& egl = m_eglTestCtx.getLibrary(); if (m_surface != EGL_NO_SURFACE) { egl.destroySurface(m_display, m_surface); m_surface = EGL_NO_SURFACE; } if (m_context != EGL_NO_CONTEXT) { egl.destroyContext(m_display, m_context); m_context = EGL_NO_CONTEXT; } if (m_display != EGL_NO_DISPLAY) { egl.terminate(m_display); m_display = EGL_NO_DISPLAY; } } IterateResult iterate (void) { if (m_iterNdx < m_iterCount) { tcu::Maybe error; Thread thread (m_eglTestCtx.getLibrary(), m_display, m_surface, m_context, m_config, error); thread.start(); thread.join(); if (error) { m_testCtx.getLog() << TestLog::Message << "Failed. Got error: " << error->getMessage() << TestLog::EndMessage; m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, error->getMessage()); return STOP; } m_iterNdx++; return CONTINUE; } else { m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); return STOP; } } private: const ContextType m_contextType; const SurfaceType m_surfaceType; const size_t m_iterCount; size_t m_iterNdx; EGLDisplay m_display; EGLConfig m_config; EGLSurface m_surface; EGLContext m_context; }; } // anonymous TestCaseGroup* createThreadCleanUpTest (EglTestContext& eglTestCtx) { de::MovePtr group (new TestCaseGroup(eglTestCtx, "thread_cleanup", "Thread cleanup tests")); group->addChild(new ThreadCleanUpTest(eglTestCtx, ThreadCleanUpTest::CONTEXTTYPE_SINGLE, ThreadCleanUpTest::SURFACETYPE_SINGLE)); group->addChild(new ThreadCleanUpTest(eglTestCtx, ThreadCleanUpTest::CONTEXTTYPE_MULTI, ThreadCleanUpTest::SURFACETYPE_SINGLE)); group->addChild(new ThreadCleanUpTest(eglTestCtx, ThreadCleanUpTest::CONTEXTTYPE_SINGLE, ThreadCleanUpTest::SURFACETYPE_MULTI)); group->addChild(new ThreadCleanUpTest(eglTestCtx, ThreadCleanUpTest::CONTEXTTYPE_MULTI, ThreadCleanUpTest::SURFACETYPE_MULTI)); return group.release(); } } // egl } // deqp