/*-------------------------------------------------------------------------
* 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 Config query tests.
*//*--------------------------------------------------------------------*/
#include "teglQueryContextTests.hpp"
#include "teglSimpleConfigCase.hpp"
#include "teglRenderCase.hpp"
#include "egluCallLogWrapper.hpp"
#include "egluStrUtil.hpp"
#include "tcuCommandLine.hpp"
#include "tcuTestLog.hpp"
#include "tcuTestContext.hpp"
#include "egluUtil.hpp"
#include "egluNativeDisplay.hpp"
#include "egluNativeWindow.hpp"
#include "egluNativePixmap.hpp"
#include "deUniquePtr.hpp"
#include <vector>
#include <EGL/eglext.h>
#if !defined(EGL_OPENGL_ES3_BIT_KHR)
# define EGL_OPENGL_ES3_BIT_KHR 0x0040
#endif
#if !defined(EGL_CONTEXT_MAJOR_VERSION_KHR)
# define EGL_CONTEXT_MAJOR_VERSION_KHR EGL_CONTEXT_CLIENT_VERSION
#endif
namespace deqp
{
namespace egl
{
using eglu::ConfigInfo;
using tcu::TestLog;
struct ContextCaseInfo
{
EGLint surfaceType;
EGLint clientType;
EGLint clientVersion;
};
class ContextCase : public SimpleConfigCase, protected eglu::CallLogWrapper
{
public:
ContextCase (EglTestContext& eglTestCtx, const char* name, const char* description, const std::vector<EGLint>& configIds, EGLint surfaceTypeMask);
virtual ~ContextCase (void);
void executeForConfig (tcu::egl::Display& display, EGLConfig config);
void executeForSurface (tcu::egl::Display& display, EGLConfig config, EGLSurface surface, ContextCaseInfo& info);
virtual void executeForContext (tcu::egl::Display& display, EGLConfig config, EGLSurface surface, EGLContext context, ContextCaseInfo& info) = 0;
private:
EGLint m_surfaceTypeMask;
};
ContextCase::ContextCase (EglTestContext& eglTestCtx, const char* name, const char* description, const std::vector<EGLint>& configIds, EGLint surfaceTypeMask)
: SimpleConfigCase (eglTestCtx, name, description, configIds)
, CallLogWrapper (eglTestCtx.getTestContext().getLog())
, m_surfaceTypeMask (surfaceTypeMask)
{
}
ContextCase::~ContextCase (void)
{
}
void ContextCase::executeForConfig (tcu::egl::Display& display, EGLConfig config)
{
tcu::TestLog& log = m_testCtx.getLog();
const int width = 64;
const int height = 64;
const EGLint configId = display.getConfigAttrib(config, EGL_CONFIG_ID);
eglu::NativeDisplay& nativeDisplay = m_eglTestCtx.getNativeDisplay();
bool isOk = true;
std::string failReason = "";
if (m_surfaceTypeMask & EGL_WINDOW_BIT)
{
log << TestLog::Message << "Creating window surface with config ID " << configId << TestLog::EndMessage;
try
{
de::UniquePtr<eglu::NativeWindow> window (m_eglTestCtx.createNativeWindow(display.getEGLDisplay(), config, DE_NULL, width, height, eglu::parseWindowVisibility(m_testCtx.getCommandLine())));
tcu::egl::WindowSurface surface (display, eglu::createWindowSurface(nativeDisplay, *window, display.getEGLDisplay(), config, DE_NULL));
ContextCaseInfo info;
info.surfaceType = EGL_WINDOW_BIT;
executeForSurface(m_eglTestCtx.getDisplay(), config, surface.getEGLSurface(), info);
}
catch (const tcu::TestError& e)
{
log << e;
isOk = false;
failReason = e.what();
}
log << TestLog::Message << TestLog::EndMessage;
}
if (m_surfaceTypeMask & EGL_PIXMAP_BIT)
{
log << TestLog::Message << "Creating pixmap surface with config ID " << configId << TestLog::EndMessage;
try
{
de::UniquePtr<eglu::NativePixmap> pixmap (m_eglTestCtx.createNativePixmap(display.getEGLDisplay(), config, DE_NULL, width, height));
tcu::egl::PixmapSurface surface (display, eglu::createPixmapSurface(nativeDisplay, *pixmap, display.getEGLDisplay(), config, DE_NULL));
ContextCaseInfo info;
info.surfaceType = EGL_PIXMAP_BIT;
executeForSurface(display, config, surface.getEGLSurface(), info);
}
catch (const tcu::TestError& e)
{
log << e;
isOk = false;
failReason = e.what();
}
log << TestLog::Message << TestLog::EndMessage;
}
if (m_surfaceTypeMask & EGL_PBUFFER_BIT)
{
log << TestLog::Message << "Creating pbuffer surface with config ID " << configId << TestLog::EndMessage;
try
{
const EGLint surfaceAttribs[] =
{
EGL_WIDTH, width,
EGL_HEIGHT, height,
EGL_NONE
};
tcu::egl::PbufferSurface surface(display, config, surfaceAttribs);
ContextCaseInfo info;
info.surfaceType = EGL_PBUFFER_BIT;
executeForSurface(display, config, surface.getEGLSurface(), info);
}
catch (const tcu::TestError& e)
{
log << e;
isOk = false;
failReason = e.what();
}
log << TestLog::Message << TestLog::EndMessage;
}
if (!isOk && m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, failReason.c_str());
}
void ContextCase::executeForSurface (tcu::egl::Display& display, EGLConfig config, EGLSurface surface, ContextCaseInfo& info)
{
TestLog& log = m_testCtx.getLog();
EGLint apiBits = display.getConfigAttrib(config, EGL_RENDERABLE_TYPE);
static const EGLint es1Attrs[] = { EGL_CONTEXT_CLIENT_VERSION, 1, EGL_NONE };
static const EGLint es2Attrs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
static const EGLint es3Attrs[] = { EGL_CONTEXT_MAJOR_VERSION_KHR, 3, EGL_NONE };
static const struct
{
const char* name;
EGLenum api;
EGLint apiBit;
const EGLint* ctxAttrs;
EGLint apiVersion;
} apis[] =
{
{ "OpenGL", EGL_OPENGL_API, EGL_OPENGL_BIT, DE_NULL, 0 },
{ "OpenGL ES 1", EGL_OPENGL_ES_API, EGL_OPENGL_ES_BIT, es1Attrs, 1 },
{ "OpenGL ES 2", EGL_OPENGL_ES_API, EGL_OPENGL_ES2_BIT, es2Attrs, 2 },
{ "OpenGL ES 3", EGL_OPENGL_ES_API, EGL_OPENGL_ES3_BIT_KHR, es3Attrs, 3 },
{ "OpenVG", EGL_OPENVG_API, EGL_OPENVG_BIT, DE_NULL, 0 }
};
for (int apiNdx = 0; apiNdx < (int)DE_LENGTH_OF_ARRAY(apis); apiNdx++)
{
if ((apiBits & apis[apiNdx].apiBit) == 0)
continue; // Not supported API
TCU_CHECK_EGL_CALL(eglBindAPI(apis[apiNdx].api));
log << TestLog::Message << "Creating " << apis[apiNdx].name << " context" << TestLog::EndMessage;
const EGLContext context = eglCreateContext(display.getEGLDisplay(), config, EGL_NO_CONTEXT, apis[apiNdx].ctxAttrs);
TCU_CHECK_EGL();
TCU_CHECK(context != EGL_NO_CONTEXT);
TCU_CHECK_EGL_CALL(eglMakeCurrent(display.getEGLDisplay(), surface, surface, context));
info.clientType = apis[apiNdx].api;
info.clientVersion = apis[apiNdx].apiVersion;
executeForContext(display, config, surface, context, info);
// Destroy
TCU_CHECK_EGL_CALL(eglMakeCurrent(display.getEGLDisplay(), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
TCU_CHECK_EGL_CALL(eglDestroyContext(display.getEGLDisplay(), context));
}
}
class GetCurrentContextCase : public ContextCase
{
public:
GetCurrentContextCase (EglTestContext& eglTestCtx, const char* name, const char* description, const std::vector<EGLint>& configIds, EGLint surfaceTypeMask)
: ContextCase(eglTestCtx, name, description, configIds, surfaceTypeMask)
{
}
void executeForContext (tcu::egl::Display& display, EGLConfig config, EGLSurface surface, EGLContext context, ContextCaseInfo& info)
{
TestLog& log = m_testCtx.getLog();
DE_UNREF(display);
DE_UNREF(config && surface);
DE_UNREF(info);
enableLogging(true);
const EGLContext gotContext = eglGetCurrentContext();
TCU_CHECK_EGL();
if (gotContext == context)
{
log << TestLog::Message << " Pass" << TestLog::EndMessage;
}
else if (gotContext == EGL_NO_CONTEXT)
{
log << TestLog::Message << " Fail, got EGL_NO_CONTEXT" << TestLog::EndMessage;
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Unexpected EGL_NO_CONTEXT");
}
else if (gotContext != context)
{
log << TestLog::Message << " Fail, call returned the wrong context. Expected: " << tcu::toHex(context) << ", got: " << tcu::toHex(gotContext) << TestLog::EndMessage;
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid context");
}
enableLogging(false);
}
};
class GetCurrentSurfaceCase : public ContextCase
{
public:
GetCurrentSurfaceCase (EglTestContext& eglTestCtx, const char* name, const char* description, const std::vector<EGLint>& configIds, EGLint surfaceTypeMask)
: ContextCase(eglTestCtx, name, description, configIds, surfaceTypeMask)
{
}
void executeForContext (tcu::egl::Display& display, EGLConfig config, EGLSurface surface, EGLContext context, ContextCaseInfo& info)
{
TestLog& log = m_testCtx.getLog();
DE_UNREF(display);
DE_UNREF(config && context);
DE_UNREF(info);
enableLogging(true);
const EGLContext gotReadSurface = eglGetCurrentSurface(EGL_READ);
TCU_CHECK_EGL();
const EGLContext gotDrawSurface = eglGetCurrentSurface(EGL_DRAW);
TCU_CHECK_EGL();
if (gotReadSurface == surface && gotDrawSurface == surface)
{
log << TestLog::Message << " Pass" << TestLog::EndMessage;
}
else
{
log << TestLog::Message << " Fail, read surface: " << tcu::toHex(gotReadSurface)
<< ", draw surface: " << tcu::toHex(gotDrawSurface)
<< ", expected: " << tcu::toHex(surface) << TestLog::EndMessage;
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid surface");
}
enableLogging(false);
}
};
class GetCurrentDisplayCase : public ContextCase
{
public:
GetCurrentDisplayCase (EglTestContext& eglTestCtx, const char* name, const char* description, const std::vector<EGLint>& configIds, EGLint surfaceTypeMask)
: ContextCase(eglTestCtx, name, description, configIds, surfaceTypeMask)
{
}
void executeForContext (tcu::egl::Display& display, EGLConfig config, EGLSurface surface, EGLContext context, ContextCaseInfo& info)
{
TestLog& log = m_testCtx.getLog();
DE_UNREF(config && surface && context);
DE_UNREF(info);
enableLogging(true);
const EGLDisplay gotDisplay = eglGetCurrentDisplay();
TCU_CHECK_EGL();
if (gotDisplay == display.getEGLDisplay())
{
log << TestLog::Message << " Pass" << TestLog::EndMessage;
}
else if (gotDisplay == EGL_NO_DISPLAY)
{
log << TestLog::Message << " Fail, got EGL_NO_DISPLAY" << TestLog::EndMessage;
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Unexpected EGL_NO_DISPLAY");
}
else if (gotDisplay != display.getEGLDisplay())
{
log << TestLog::Message << " Fail, call returned the wrong display. Expected: " << tcu::toHex(display.getEGLDisplay()) << ", got: " << tcu::toHex(gotDisplay) << TestLog::EndMessage;
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid display");
}
enableLogging(false);
}
};
class QueryContextCase : public ContextCase
{
public:
QueryContextCase (EglTestContext& eglTestCtx, const char* name, const char* description, const std::vector<EGLint>& configIds, EGLint surfaceTypeMask)
: ContextCase(eglTestCtx, name, description, configIds, surfaceTypeMask)
{
}
EGLint getContextAttrib (tcu::egl::Display& display, EGLContext context, EGLint attrib)
{
EGLint value;
TCU_CHECK_EGL_CALL(eglQueryContext(display.getEGLDisplay(), context, attrib, &value));
return value;
}
void executeForContext (tcu::egl::Display& display, EGLConfig config, EGLSurface surface, EGLContext context, ContextCaseInfo& info)
{
TestLog& log = m_testCtx.getLog();
const eglu::Version version (display.getEGLMajorVersion(), display.getEGLMinorVersion());
DE_UNREF(surface);
enableLogging(true);
// Config ID
{
const EGLint configID = getContextAttrib(display, context, EGL_CONFIG_ID);
const EGLint surfaceConfigID = display.getConfigAttrib(config, EGL_CONFIG_ID);
if (configID != surfaceConfigID)
{
log << TestLog::Message << " Fail, config ID doesn't match the one used to create the context." << TestLog::EndMessage;
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid config ID");
}
}
// Client API type
if (version >= eglu::Version(1, 2))
{
const EGLint clientType = getContextAttrib(display, context, EGL_CONTEXT_CLIENT_TYPE);
if (clientType != info.clientType)
{
log << TestLog::Message << " Fail, client API type doesn't match." << TestLog::EndMessage;
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid client API type");
}
}
// Client API version
if (version >= eglu::Version(1, 3))
{
const EGLint clientVersion = getContextAttrib(display, context, EGL_CONTEXT_CLIENT_VERSION);
if (info.clientType == EGL_OPENGL_ES_API && clientVersion != info.clientVersion)
{
log << TestLog::Message << " Fail, client API version doesn't match." << TestLog::EndMessage;
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid client API version");
}
}
// Render buffer
if (version >= eglu::Version(1, 2))
{
const EGLint renderBuffer = getContextAttrib(display, context, EGL_RENDER_BUFFER);
if (info.surfaceType == EGL_PIXMAP_BIT && renderBuffer != EGL_SINGLE_BUFFER)
{
log << TestLog::Message << " Fail, render buffer should be EGL_SINGLE_BUFFER for a pixmap surface." << TestLog::EndMessage;
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid render buffer");
}
else if (info.surfaceType == EGL_PBUFFER_BIT && renderBuffer != EGL_BACK_BUFFER)
{
log << TestLog::Message << " Fail, render buffer should be EGL_BACK_BUFFER for a pbuffer surface." << TestLog::EndMessage;
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid render buffer");
}
else if (info.surfaceType == EGL_WINDOW_BIT && renderBuffer != EGL_SINGLE_BUFFER && renderBuffer != EGL_BACK_BUFFER)
{
log << TestLog::Message << " Fail, render buffer should be either EGL_SINGLE_BUFFER or EGL_BACK_BUFFER for a window surface." << TestLog::EndMessage;
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid render buffer");
}
}
enableLogging(false);
log << TestLog::Message << " Pass" << TestLog::EndMessage;
}
};
class QueryAPICase : public TestCase, protected eglu::CallLogWrapper
{
public:
QueryAPICase (EglTestContext& eglTestCtx, const char* name, const char* description)
: TestCase(eglTestCtx, name, description)
, CallLogWrapper(eglTestCtx.getTestContext().getLog())
{
}
void init (void)
{
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
}
IterateResult iterate (void)
{
tcu::TestLog& log = m_testCtx.getLog();
const EGLenum apis[] = { EGL_OPENGL_API, EGL_OPENGL_ES_API, EGL_OPENVG_API };
enableLogging(true);
{
const EGLenum api = eglQueryAPI();
if (api != EGL_OPENGL_ES_API && m_eglTestCtx.isAPISupported(EGL_OPENGL_ES_API))
{
log << TestLog::Message << " Fail, initial value should be EGL_OPENGL_ES_API if OpenGL ES is supported." << TestLog::EndMessage;
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid default value");
}
else if(api != EGL_NONE && !m_eglTestCtx.isAPISupported(EGL_OPENGL_ES_API))
{
log << TestLog::Message << " Fail, initial value should be EGL_NONE if OpenGL ES is not supported." << TestLog::EndMessage;
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid default value");
}
}
for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(apis); ndx++)
{
const EGLenum api = apis[ndx];
log << TestLog::Message << TestLog::EndMessage;
if (m_eglTestCtx.isAPISupported(api))
{
eglBindAPI(api);
if (api != eglQueryAPI())
{
log << TestLog::Message << " Fail, return value does not match previously bound API." << TestLog::EndMessage;
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid return value");
}
}
else
{
log << TestLog::Message << eglu::getAPIStr(api) << " not supported." << TestLog::EndMessage;
}
}
enableLogging(false);
return STOP;
}
};
QueryContextTests::QueryContextTests (EglTestContext& eglTestCtx)
: TestCaseGroup(eglTestCtx, "query_context", "Rendering context query tests")
{
}
QueryContextTests::~QueryContextTests (void)
{
}
template<class QueryContextClass>
void createQueryContextGroups (EglTestContext& eglTestCtx, tcu::TestCaseGroup* group)
{
std::vector<RenderConfigIdSet> configSets;
eglu::FilterList filters;
getDefaultRenderConfigIdSets(configSets, eglTestCtx.getConfigs(), filters);
for (std::vector<RenderConfigIdSet>::const_iterator setIter = configSets.begin(); setIter != configSets.end(); setIter++)
group->addChild(new QueryContextClass(eglTestCtx, setIter->getName(), "", setIter->getConfigIds(), setIter->getSurfaceTypeMask()));
}
void QueryContextTests::init (void)
{
{
tcu::TestCaseGroup* simpleGroup = new tcu::TestCaseGroup(m_testCtx, "simple", "Simple API tests");
addChild(simpleGroup);
simpleGroup->addChild(new QueryAPICase(m_eglTestCtx, "query_api", "eglQueryAPI() test"));
}
// eglGetCurrentContext
{
tcu::TestCaseGroup* getCurrentContextGroup = new tcu::TestCaseGroup(m_testCtx, "get_current_context", "eglGetCurrentContext() tests");
addChild(getCurrentContextGroup);
createQueryContextGroups<GetCurrentContextCase>(m_eglTestCtx, getCurrentContextGroup);
}
// eglGetCurrentSurface
{
tcu::TestCaseGroup* getCurrentSurfaceGroup = new tcu::TestCaseGroup(m_testCtx, "get_current_surface", "eglGetCurrentSurface() tests");
addChild(getCurrentSurfaceGroup);
createQueryContextGroups<GetCurrentSurfaceCase>(m_eglTestCtx, getCurrentSurfaceGroup);
}
// eglGetCurrentDisplay
{
tcu::TestCaseGroup* getCurrentDisplayGroup = new tcu::TestCaseGroup(m_testCtx, "get_current_display", "eglGetCurrentDisplay() tests");
addChild(getCurrentDisplayGroup);
createQueryContextGroups<GetCurrentDisplayCase>(m_eglTestCtx, getCurrentDisplayGroup);
}
// eglQueryContext
{
tcu::TestCaseGroup* queryContextGroup = new tcu::TestCaseGroup(m_testCtx, "query_context", "eglQueryContext() tests");
addChild(queryContextGroup);
createQueryContextGroups<QueryContextCase>(m_eglTestCtx, queryContextGroup);
}
}
} // egl
} // deqp