--- /dev/null
+/*-------------------------------------------------------------------------
+ * 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<eglu::Error>& 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;
+ }
+ }
+
+private:
+ const Library& m_egl;
+ const EGLDisplay m_display;
+ const EGLSurface m_surface;
+ const EGLContext m_context;
+ const EGLConfig m_config;
+ tcu::Maybe<eglu::Error>& 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)
+ {
+ }
+
+ ~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<eglu::Error> 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<TestCaseGroup> 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