/*-------------------------------------------------------------------------
* 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)
, 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<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