blob: 428223410d8a837c8bd655b754dec7f012afdf1e [file] [log] [blame]
/*-------------------------------------------------------------------------
* drawElements Quality Program Tester Core
* ----------------------------------------
*
* 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 utilities
*//*--------------------------------------------------------------------*/
#include "egluUtil.hpp"
#include "egluDefs.hpp"
#include "egluNativeDisplay.hpp"
#include "tcuCommandLine.hpp"
#include "deSTLUtil.hpp"
#include <algorithm>
#include <sstream>
using std::string;
using std::vector;
#if !defined(EGL_EXT_platform_base)
# define EGL_EXT_platform_base 1
typedef EGLDisplay (EGLAPIENTRYP PFNEGLGETPLATFORMDISPLAYEXTPROC) (EGLenum platform, void *native_display, const EGLint *attrib_list);
typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC) (EGLDisplay dpy, EGLConfig config, void *native_window, const EGLint *attrib_list);
typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPLATFORMPIXMAPSURFACEEXTPROC) (EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLint *attrib_list);
#endif // EGL_EXT_platform_base
namespace eglu
{
vector<string> getPlatformExtensions (void)
{
const char* const extensionStr = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
const EGLint result = eglGetError();
if (result == EGL_SUCCESS)
{
std::istringstream stream (extensionStr);
string currentExtension;
vector<string> extensions;
while (std::getline(stream, currentExtension, ' '))
extensions.push_back(currentExtension);
return extensions;
}
else if (result != EGL_BAD_DISPLAY)
throw Error(result, "eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS)", DE_NULL, __FILE__, __LINE__);
else
return vector<string>();
}
vector<string> getClientExtensions (EGLDisplay display)
{
const char* const extensionStr = eglQueryString(display, EGL_EXTENSIONS);
const EGLint result = eglGetError();
if (result == EGL_SUCCESS)
{
std::istringstream stream (extensionStr);
string currentExtension;
vector<string> extensions;
while (std::getline(stream, currentExtension, ' '))
extensions.push_back(currentExtension);
return extensions;
}
else
throw Error(result, "eglQueryString(display, EGL_EXTENSIONS)", DE_NULL, __FILE__, __LINE__);
}
vector<EGLConfig> getConfigs (EGLDisplay display)
{
vector<EGLConfig> configs;
EGLint configCount = 0;
EGLU_CHECK_CALL(eglGetConfigs(display, DE_NULL, 0, &configCount));
if (configCount > 0)
{
configs.resize(configCount);
EGLU_CHECK_CALL(eglGetConfigs(display, &(configs[0]), (EGLint)configs.size(), &configCount));
}
return configs;
}
vector<EGLConfig> chooseConfig (EGLDisplay display, const AttribMap& attribs)
{
vector<EGLint> attribList;
for (AttribMap::const_iterator it = attribs.begin(); it != attribs.end(); ++it)
{
attribList.push_back(it->first);
attribList.push_back(it->second);
}
attribList.push_back(EGL_NONE);
{
EGLint numConfigs = 0;
EGLU_CHECK_CALL(eglChooseConfig(display, &attribList.front(), DE_NULL, 0, &numConfigs));
{
vector<EGLConfig> configs(numConfigs);
if (numConfigs > 0)
EGLU_CHECK_CALL(eglChooseConfig(display, &attribList.front(), &configs.front(), numConfigs, &numConfigs));
return configs;
}
}
}
EGLConfig chooseSingleConfig (EGLDisplay display, const AttribMap& attribs)
{
vector<EGLConfig> configs (chooseConfig(display, attribs));
if (configs.empty())
TCU_THROW(NotSupportedError, "No suitable EGL configuration found");
return configs.front();
}
EGLint getConfigAttribInt (EGLDisplay display, EGLConfig config, EGLint attrib)
{
EGLint value = 0;
EGLU_CHECK_CALL(eglGetConfigAttrib(display, config, attrib, &value));
return value;
}
EGLint querySurfaceInt (EGLDisplay display, EGLSurface surface, EGLint attrib)
{
EGLint value = 0;
EGLU_CHECK_CALL(eglQuerySurface(display, surface, attrib, &value));
return value;
}
tcu::IVec2 getSurfaceSize (EGLDisplay display, EGLSurface surface)
{
const EGLint width = querySurfaceInt(display, surface, EGL_WIDTH);
const EGLint height = querySurfaceInt(display, surface, EGL_HEIGHT);
return tcu::IVec2(width, height);
}
tcu::IVec2 getSurfaceResolution (EGLDisplay display, EGLSurface surface)
{
const EGLint hRes = querySurfaceInt(display, surface, EGL_HORIZONTAL_RESOLUTION);
const EGLint vRes = querySurfaceInt(display, surface, EGL_VERTICAL_RESOLUTION);
if (hRes == EGL_UNKNOWN || vRes == EGL_UNKNOWN)
TCU_THROW(NotSupportedError, "Surface doesn't support pixel density queries");
return tcu::IVec2(hRes, vRes);
}
//! Get EGLdisplay using eglGetDisplay() or eglGetPlatformDisplayEXT()
EGLDisplay getDisplay (NativeDisplay& nativeDisplay)
{
const bool supportsLegacyGetDisplay = (nativeDisplay.getCapabilities() & NativeDisplay::CAPABILITY_GET_DISPLAY_LEGACY) != 0;
const bool supportsPlatformGetDisplay = (nativeDisplay.getCapabilities() & NativeDisplay::CAPABILITY_GET_DISPLAY_PLATFORM) != 0;
bool usePlatformExt = false;
EGLDisplay display = EGL_NO_DISPLAY;
TCU_CHECK_INTERNAL(supportsLegacyGetDisplay || supportsPlatformGetDisplay);
if (supportsPlatformGetDisplay)
{
const vector<string> platformExts = getPlatformExtensions();
usePlatformExt = de::contains(platformExts.begin(), platformExts.end(), string("EGL_EXT_platform_base")) &&
de::contains(platformExts.begin(), platformExts.end(), string(nativeDisplay.getPlatformExtensionName()));
}
if (usePlatformExt)
{
const PFNEGLGETPLATFORMDISPLAYEXTPROC getPlatformDisplay = (PFNEGLGETPLATFORMDISPLAYEXTPROC)eglGetProcAddress("eglGetPlatformDisplayEXT");
EGLU_CHECK_MSG("eglGetProcAddress()");
TCU_CHECK(getPlatformDisplay);
display = getPlatformDisplay(nativeDisplay.getPlatformType(), nativeDisplay.getPlatformNative(), DE_NULL);
EGLU_CHECK_MSG("eglGetPlatformDisplayEXT()");
TCU_CHECK(display != EGL_NO_DISPLAY);
}
else if (supportsLegacyGetDisplay)
{
display = eglGetDisplay(nativeDisplay.getLegacyNative());
EGLU_CHECK_MSG("eglGetDisplay()");
TCU_CHECK(display != EGL_NO_DISPLAY);
}
else
throw tcu::InternalError("No supported way to get EGL display", DE_NULL, __FILE__, __LINE__);
DE_ASSERT(display != EGL_NO_DISPLAY);
return display;
}
//! Create EGL window surface using eglCreateWindowSurface() or eglCreatePlatformWindowSurfaceEXT()
EGLSurface createWindowSurface (NativeDisplay& nativeDisplay, NativeWindow& window, EGLDisplay display, EGLConfig config, const EGLAttrib* attribList)
{
const bool supportsLegacyCreate = (window.getCapabilities() & NativeWindow::CAPABILITY_CREATE_SURFACE_LEGACY) != 0;
const bool supportsPlatformCreate = (window.getCapabilities() & NativeWindow::CAPABILITY_CREATE_SURFACE_PLATFORM) != 0;
bool usePlatformExt = false;
EGLSurface surface = EGL_NO_SURFACE;
TCU_CHECK_INTERNAL(supportsLegacyCreate || supportsPlatformCreate);
if (supportsPlatformCreate)
{
const vector<string> platformExts = getPlatformExtensions();
usePlatformExt = de::contains(platformExts.begin(), platformExts.end(), string("EGL_EXT_platform_base")) &&
de::contains(platformExts.begin(), platformExts.end(), string(nativeDisplay.getPlatformExtensionName()));
}
// \todo [2014-03-13 pyry] EGL 1.5 core support
if (usePlatformExt)
{
const PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC createPlatformWindowSurface = (PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC)eglGetProcAddress("eglCreatePlatformWindowSurfaceEXT");
const vector<EGLint> legacyAttribs = toLegacyAttribList(attribList);
EGLU_CHECK_MSG("eglGetProcAddress()");
TCU_CHECK(createPlatformWindowSurface);
surface = createPlatformWindowSurface(display, config, window.getPlatformNative(), &legacyAttribs[0]);
EGLU_CHECK_MSG("eglCreatePlatformWindowSurfaceEXT()");
TCU_CHECK(surface != EGL_NO_SURFACE);
}
else if (supportsLegacyCreate)
{
const vector<EGLint> legacyAttribs = toLegacyAttribList(attribList);
surface = eglCreateWindowSurface(display, config, window.getLegacyNative(), &legacyAttribs[0]);
EGLU_CHECK_MSG("eglCreateWindowSurface()");
TCU_CHECK(surface != EGL_NO_SURFACE);
}
else
throw tcu::InternalError("No supported way to create EGL window surface", DE_NULL, __FILE__, __LINE__);
DE_ASSERT(surface != EGL_NO_SURFACE);
return surface;
}
//! Create EGL pixmap surface using eglCreatePixmapSurface() or eglCreatePlatformPixmapSurfaceEXT()
EGLSurface createPixmapSurface (NativeDisplay& nativeDisplay, NativePixmap& pixmap, EGLDisplay display, EGLConfig config, const EGLAttrib* attribList)
{
const bool supportsLegacyCreate = (pixmap.getCapabilities() & NativePixmap::CAPABILITY_CREATE_SURFACE_LEGACY) != 0;
const bool supportsPlatformCreate = (pixmap.getCapabilities() & NativePixmap::CAPABILITY_CREATE_SURFACE_PLATFORM) != 0;
bool usePlatformExt = false;
EGLSurface surface = EGL_NO_SURFACE;
TCU_CHECK_INTERNAL(supportsLegacyCreate || supportsPlatformCreate);
if (supportsPlatformCreate)
{
const vector<string> platformExts = getPlatformExtensions();
usePlatformExt = de::contains(platformExts.begin(), platformExts.end(), string("EGL_EXT_platform_base")) &&
de::contains(platformExts.begin(), platformExts.end(), string(nativeDisplay.getPlatformExtensionName()));
}
if (usePlatformExt)
{
const PFNEGLCREATEPLATFORMPIXMAPSURFACEEXTPROC createPlatformPixmapSurface = (PFNEGLCREATEPLATFORMPIXMAPSURFACEEXTPROC)eglGetProcAddress("eglCreatePlatformPixmapSurfaceEXT");
const vector<EGLint> legacyAttribs = toLegacyAttribList(attribList);
EGLU_CHECK_MSG("eglGetProcAddress()");
TCU_CHECK(createPlatformPixmapSurface);
surface = createPlatformPixmapSurface(display, config, pixmap.getPlatformNative(), &legacyAttribs[0]);
EGLU_CHECK_MSG("eglCreatePlatformPixmapSurfaceEXT()");
TCU_CHECK(surface != EGL_NO_SURFACE);
}
else if (supportsLegacyCreate)
{
const vector<EGLint> legacyAttribs = toLegacyAttribList(attribList);
surface = eglCreatePixmapSurface(display, config, pixmap.getLegacyNative(), &legacyAttribs[0]);
EGLU_CHECK_MSG("eglCreatePixmapSurface()");
TCU_CHECK(surface != EGL_NO_SURFACE);
}
else
throw tcu::InternalError("No supported way to create EGL pixmap surface", DE_NULL, __FILE__, __LINE__);
DE_ASSERT(surface != EGL_NO_SURFACE);
return surface;
}
static WindowParams::Visibility getWindowVisibility (tcu::WindowVisibility visibility)
{
switch (visibility)
{
case tcu::WINDOWVISIBILITY_WINDOWED: return WindowParams::VISIBILITY_VISIBLE;
case tcu::WINDOWVISIBILITY_FULLSCREEN: return WindowParams::VISIBILITY_FULLSCREEN;
case tcu::WINDOWVISIBILITY_HIDDEN: return WindowParams::VISIBILITY_HIDDEN;
default:
DE_ASSERT(false);
return WindowParams::VISIBILITY_DONT_CARE;
}
}
WindowParams::Visibility parseWindowVisibility (const tcu::CommandLine& commandLine)
{
return getWindowVisibility(commandLine.getVisibility());
}
vector<EGLint> toLegacyAttribList (const EGLAttrib* attribs)
{
const deUint64 attribMask = 0xffffffffull; //!< Max bits that can be used
vector<EGLint> legacyAttribs;
if (attribs)
{
for (const EGLAttrib* attrib = attribs; *attrib != EGL_NONE; attrib += 2)
{
if ((attrib[0] & ~attribMask) || (attrib[1] & ~attribMask))
throw tcu::InternalError("Failed to translate EGLAttrib to EGLint", DE_NULL, __FILE__, __LINE__);
legacyAttribs.push_back((EGLint)attrib[0]);
legacyAttribs.push_back((EGLint)attrib[1]);
}
}
legacyAttribs.push_back(EGL_NONE);
return legacyAttribs;
}
} // eglu