/*-------------------------------------------------------------------------
* 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 EGL Test Case
*//*--------------------------------------------------------------------*/
#include "teglTestCase.hpp"
#include "tcuPlatform.hpp"
#include "egluUtil.hpp"
#include "egluGLFunctionLoader.hpp"
#include "egluPlatform.hpp"
#include "gluRenderContext.hpp"
#include "glwInitFunctions.hpp"
#include <set>
using std::vector;
using std::set;
namespace deqp
{
namespace egl
{
namespace
{
void split (std::vector<std::string>& dst, const std::string& src)
{
size_t start = 0;
size_t end = std::string::npos;
while ((end = src.find(' ', start)) != std::string::npos)
{
dst.push_back(src.substr(start, end-start));
start = end+1;
}
if (start < end)
dst.push_back(src.substr(start, end-start));
}
EGLint parseAPI (const std::string& api)
{
if (api == "OpenGL")
return EGL_OPENGL_API;
else if (api == "OpenGL_ES")
return EGL_OPENGL_ES_API;
else if (api == "OpenVG")
return EGL_OPENVG_API;
else
{
tcu::print("Warning: Unknown API '%s'", api.c_str());
return 0;
}
}
} // anonymous
EglTestContext::EglTestContext (tcu::TestContext& testCtx, const eglu::NativeDisplayFactory& displayFactory, const eglu::NativeWindowFactory* windowFactory, const eglu::NativePixmapFactory* pixmapFactory)
: m_testCtx (testCtx)
, m_displayFactory (displayFactory)
, m_windowFactory (windowFactory)
, m_pixmapFactory (pixmapFactory)
, m_defaultNativeDisplay (DE_NULL)
, m_defaultEGLDisplay (DE_NULL)
{
// Temporarily allocate default display for storing config list
try
{
EGLDisplay eglDisplay = EGL_NO_DISPLAY;
EGLint majorVersion;
EGLint minorVersion;
m_defaultNativeDisplay = m_displayFactory.createDisplay();
eglDisplay = eglu::getDisplay(*m_defaultNativeDisplay);
TCU_CHECK_EGL_CALL(eglInitialize(eglDisplay, &majorVersion, &minorVersion));
m_defaultEGLDisplay = new tcu::egl::Display(eglDisplay, majorVersion, minorVersion);
// Create config list
{
vector<EGLConfig> configs;
set<EGLint> idSet; // For checking for duplicate config IDs
m_defaultEGLDisplay->getConfigs(configs);
m_configs.resize(configs.size());
for (int ndx = 0; ndx < (int)configs.size(); ndx++)
{
m_defaultEGLDisplay->describeConfig(configs[ndx], m_configs[ndx]);
EGLint id = m_configs[ndx].configId;
if (idSet.find(id) != idSet.end())
tcu::print("Warning: Duplicate config ID %d\n", id);
idSet.insert(id);
}
}
// Query supported APIs
{
const char* clientAPIs = eglQueryString(eglDisplay, EGL_CLIENT_APIS);
std::vector<std::string> apis;
TCU_CHECK(clientAPIs);
split(apis, clientAPIs);
for (std::vector<std::string>::const_iterator apiIter = apis.begin(); apiIter != apis.end(); apiIter++)
{
EGLint parsedAPI = parseAPI(*apiIter);
if (parsedAPI != 0)
m_supportedAPIs.insert(parsedAPI);
}
}
delete m_defaultEGLDisplay;
m_defaultEGLDisplay = DE_NULL;
delete m_defaultNativeDisplay;
m_defaultNativeDisplay = DE_NULL;
}
catch (...)
{
delete m_defaultEGLDisplay;
m_defaultEGLDisplay = DE_NULL;
delete m_defaultNativeDisplay;
m_defaultNativeDisplay = DE_NULL;
throw;
}
}
EglTestContext::~EglTestContext (void)
{
for (GLLibraryMap::iterator iter = m_glLibraries.begin(); iter != m_glLibraries.end(); ++iter)
delete iter->second;
delete m_defaultEGLDisplay;
delete m_defaultNativeDisplay;
}
void EglTestContext::createDefaultDisplay (void)
{
EGLDisplay eglDisplay = EGL_NO_DISPLAY;
EGLint majorVersion;
EGLint minorVersion;
DE_ASSERT(!m_defaultEGLDisplay);
DE_ASSERT(!m_defaultNativeDisplay);
try
{
m_defaultNativeDisplay = m_displayFactory.createDisplay();
eglDisplay = eglu::getDisplay(*m_defaultNativeDisplay);
TCU_CHECK_EGL_CALL(eglInitialize(eglDisplay, &majorVersion, &minorVersion));
m_defaultEGLDisplay = new tcu::egl::Display(eglDisplay, majorVersion, minorVersion);
}
catch (const std::exception&)
{
delete m_defaultEGLDisplay;
m_defaultEGLDisplay = DE_NULL;
delete m_defaultNativeDisplay;
m_defaultNativeDisplay = DE_NULL;
throw;
}
}
const eglu::NativeWindowFactory& EglTestContext::getNativeWindowFactory (void) const
{
if (m_windowFactory)
return *m_windowFactory;
else
throw tcu::NotSupportedError("No default native window factory available", "", __FILE__, __LINE__);
}
const eglu::NativePixmapFactory& EglTestContext::getNativePixmapFactory (void) const
{
if (m_pixmapFactory)
return *m_pixmapFactory;
else
throw tcu::NotSupportedError("No default native pixmap factory available", "", __FILE__, __LINE__);
}
void EglTestContext::destroyDefaultDisplay (void)
{
DE_ASSERT(m_defaultEGLDisplay);
DE_ASSERT(m_defaultNativeDisplay);
delete m_defaultEGLDisplay;
m_defaultEGLDisplay = DE_NULL;
delete m_defaultNativeDisplay;
m_defaultNativeDisplay = DE_NULL;
}
eglu::NativeWindow* EglTestContext::createNativeWindow (EGLDisplay display, EGLConfig config, const EGLAttrib* attribList, int width, int height, eglu::WindowParams::Visibility visibility)
{
if (!m_windowFactory)
throw tcu::NotSupportedError("Windows not supported", "", __FILE__, __LINE__);
return m_windowFactory->createWindow(m_defaultNativeDisplay, display, config, attribList, eglu::WindowParams(width, height, visibility));
}
eglu::NativePixmap* EglTestContext::createNativePixmap (EGLDisplay display, EGLConfig config, const EGLAttrib* attribList, int width, int height)
{
if (!m_pixmapFactory)
throw tcu::NotSupportedError("Pixmaps not supported", "", __FILE__, __LINE__);
return m_pixmapFactory->createPixmap(m_defaultNativeDisplay, display, config, attribList, width, height);
}
// \todo [2014-10-06 pyry] Quite hacky, expose ApiType internals?
static deUint32 makeKey (glu::ApiType apiType)
{
return (apiType.getMajorVersion() << 8) | (apiType.getMinorVersion() << 4) | apiType.getProfile();
}
const tcu::FunctionLibrary* EglTestContext::getGLLibrary (glu::ApiType apiType) const
{
tcu::FunctionLibrary* library = DE_NULL;
const deUint32 key = makeKey(apiType);
GLLibraryMap::iterator iter = m_glLibraries.find(key);
if (iter == m_glLibraries.end())
{
library = m_testCtx.getPlatform().getEGLPlatform().createDefaultGLFunctionLibrary(apiType, m_testCtx.getCommandLine());
m_glLibraries.insert(std::make_pair(key, library));
}
else
library = iter->second;
return library;
}
deFunctionPtr EglTestContext::getGLFunction (glu::ApiType apiType, const char* name) const
{
// \todo [2014-03-11 pyry] This requires fall-back to eglGetProcAddress(), right?
const tcu::FunctionLibrary* const library = getGLLibrary(apiType);
return library->getFunction(name);
}
void EglTestContext::getGLFunctions (glw::Functions& gl, glu::ApiType apiType) const
{
const tcu::FunctionLibrary* const library = getGLLibrary(apiType);
const eglu::GLFunctionLoader loader (library);
// \note There may not be current context, so we can't use initFunctions().
glu::initCoreFunctions(&gl, &loader, apiType);
}
TestCaseGroup::TestCaseGroup (EglTestContext& eglTestCtx, const char* name, const char* description)
: tcu::TestCaseGroup (eglTestCtx.getTestContext(), name, description)
, m_eglTestCtx (eglTestCtx)
{
}
TestCaseGroup::~TestCaseGroup (void)
{
}
TestCase::TestCase (EglTestContext& eglTestCtx, const char* name, const char* description)
: tcu::TestCase (eglTestCtx.getTestContext(), name, description)
, m_eglTestCtx (eglTestCtx)
{
}
TestCase::TestCase (EglTestContext& eglTestCtx, tcu::TestNodeType type, const char* name, const char* description)
: tcu::TestCase (eglTestCtx.getTestContext(), type, name, description)
, m_eglTestCtx (eglTestCtx)
{
}
TestCase::~TestCase (void)
{
}
} // egl
} // deqp