| /*------------------------------------------------------------------------- |
| * 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 "egluConfigFilter.hpp" |
| #include "eglwLibrary.hpp" |
| #include "eglwEnums.hpp" |
| #include "tcuCommandLine.hpp" |
| #include "deSTLUtil.hpp" |
| #include "deStringUtil.hpp" |
| #include "glwEnums.hpp" |
| |
| #include <algorithm> |
| #include <sstream> |
| |
| using std::string; |
| using std::vector; |
| |
| namespace eglu |
| { |
| |
| using namespace eglw; |
| |
| vector<EGLint> attribMapToList (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); |
| |
| return attribList; |
| } |
| |
| Version getVersion (const Library& egl, EGLDisplay display) |
| { |
| EGLint major, minor; |
| |
| // eglInitialize on already initialized displays just returns the version. |
| EGLU_CHECK_CALL(egl, initialize(display, &major, &minor)); |
| |
| return Version(major, minor); |
| } |
| |
| vector<string> getExtensions (const Library& egl, EGLDisplay display) |
| { |
| const char* const extensionStr = egl.queryString(display, EGL_EXTENSIONS); |
| |
| EGLU_CHECK_MSG(egl, "Querying extensions failed"); |
| |
| return de::splitString(extensionStr, ' '); |
| } |
| |
| bool hasExtension (const Library& egl, EGLDisplay display, const string& str) |
| { |
| const vector<string> extensions = getExtensions(egl, display); |
| return de::contains(extensions.begin(), extensions.end(), str); |
| } |
| |
| vector<string> getClientExtensions (const Library& egl) |
| { |
| const char* const extensionStr = egl.queryString(EGL_NO_DISPLAY, EGL_EXTENSIONS); |
| const EGLint eglError = egl.getError(); |
| if (eglError == EGL_BAD_DISPLAY && extensionStr == DE_NULL) { |
| // We do not support client extensions |
| TCU_THROW(NotSupportedError, "EGL_EXT_client_extensions not supported"); |
| } |
| |
| EGLU_CHECK_MSG(egl, "Querying extensions failed"); |
| |
| return de::splitString(extensionStr, ' '); |
| } |
| |
| vector<string> getDisplayExtensions (const Library& egl, EGLDisplay display) |
| { |
| DE_ASSERT(display != EGL_NO_DISPLAY); |
| |
| return getExtensions(egl, display); |
| } |
| |
| vector<EGLConfig> getConfigs (const Library& egl, EGLDisplay display) |
| { |
| vector<EGLConfig> configs; |
| EGLint configCount = 0; |
| EGLU_CHECK_CALL(egl, getConfigs(display, DE_NULL, 0, &configCount)); |
| |
| if (configCount > 0) |
| { |
| configs.resize(configCount); |
| EGLU_CHECK_CALL(egl, getConfigs(display, &(configs[0]), (EGLint)configs.size(), &configCount)); |
| } |
| |
| return configs; |
| } |
| |
| vector<EGLConfig> chooseConfigs (const Library& egl, EGLDisplay display, const EGLint* attribList) |
| { |
| EGLint numConfigs = 0; |
| |
| EGLU_CHECK_CALL(egl, chooseConfig(display, attribList, DE_NULL, 0, &numConfigs)); |
| |
| { |
| vector<EGLConfig> configs(numConfigs); |
| |
| if (numConfigs > 0) |
| EGLU_CHECK_CALL(egl, chooseConfig(display, attribList, &configs.front(), numConfigs, &numConfigs)); |
| |
| return configs; |
| } |
| } |
| |
| vector<EGLConfig> chooseConfigs (const Library& egl, EGLDisplay display, const FilterList& filters) |
| { |
| const vector<EGLConfig> allConfigs (getConfigs(egl, display)); |
| vector<EGLConfig> matchingConfigs; |
| |
| for (vector<EGLConfig>::const_iterator cfg = allConfigs.begin(); cfg != allConfigs.end(); ++cfg) |
| { |
| if (filters.match(egl, display, *cfg)) |
| matchingConfigs.push_back(*cfg); |
| } |
| |
| return matchingConfigs; |
| } |
| |
| EGLConfig chooseSingleConfig (const Library& egl, EGLDisplay display, const FilterList& filters) |
| { |
| const vector<EGLConfig> allConfigs (getConfigs(egl, display)); |
| |
| for (vector<EGLConfig>::const_iterator cfg = allConfigs.begin(); cfg != allConfigs.end(); ++cfg) |
| { |
| if (filters.match(egl, display, *cfg)) |
| return *cfg; |
| } |
| |
| TCU_THROW(NotSupportedError, "No matching EGL config found"); |
| } |
| |
| EGLConfig chooseSingleConfig (const Library& egl, EGLDisplay display, const EGLint* attribList) |
| { |
| const vector<EGLConfig> configs (chooseConfigs(egl, display, attribList)); |
| if (configs.empty()) |
| TCU_THROW(NotSupportedError, "No matching EGL config found"); |
| |
| return configs.front(); |
| } |
| |
| vector<EGLConfig> chooseConfigs (const Library& egl, EGLDisplay display, const AttribMap& attribs) |
| { |
| const vector<EGLint> attribList = attribMapToList(attribs); |
| return chooseConfigs(egl, display, &attribList.front()); |
| } |
| |
| EGLConfig chooseSingleConfig (const Library& egl, EGLDisplay display, const AttribMap& attribs) |
| { |
| const vector<EGLint> attribList = attribMapToList(attribs); |
| return chooseSingleConfig(egl, display, &attribList.front()); |
| } |
| |
| EGLConfig chooseConfigByID (const Library& egl, EGLDisplay display, EGLint id) |
| { |
| AttribMap attribs; |
| |
| attribs[EGL_CONFIG_ID] = id; |
| attribs[EGL_TRANSPARENT_TYPE] = EGL_DONT_CARE; |
| attribs[EGL_COLOR_BUFFER_TYPE] = EGL_DONT_CARE; |
| attribs[EGL_RENDERABLE_TYPE] = EGL_DONT_CARE; |
| attribs[EGL_SURFACE_TYPE] = EGL_DONT_CARE; |
| |
| return chooseSingleConfig(egl, display, attribs); |
| } |
| |
| EGLint getConfigAttribInt (const Library& egl, EGLDisplay display, EGLConfig config, EGLint attrib) |
| { |
| EGLint value = 0; |
| EGLU_CHECK_CALL(egl, getConfigAttrib(display, config, attrib, &value)); |
| return value; |
| } |
| |
| EGLint getConfigID (const Library& egl, EGLDisplay display, EGLConfig config) |
| { |
| return getConfigAttribInt(egl, display, config, EGL_CONFIG_ID); |
| } |
| |
| EGLint querySurfaceInt (const Library& egl, EGLDisplay display, EGLSurface surface, EGLint attrib) |
| { |
| EGLint value = 0; |
| EGLU_CHECK_CALL(egl, querySurface(display, surface, attrib, &value)); |
| return value; |
| } |
| |
| tcu::IVec2 getSurfaceSize (const Library& egl, EGLDisplay display, EGLSurface surface) |
| { |
| const EGLint width = querySurfaceInt(egl, display, surface, EGL_WIDTH); |
| const EGLint height = querySurfaceInt(egl, display, surface, EGL_HEIGHT); |
| return tcu::IVec2(width, height); |
| } |
| |
| tcu::IVec2 getSurfaceResolution (const Library& egl, EGLDisplay display, EGLSurface surface) |
| { |
| const EGLint hRes = querySurfaceInt(egl, display, surface, EGL_HORIZONTAL_RESOLUTION); |
| const EGLint vRes = querySurfaceInt(egl, 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 Library& egl = nativeDisplay.getLibrary(); |
| const bool supportsLegacyGetDisplay = (nativeDisplay.getCapabilities() & NativeDisplay::CAPABILITY_GET_DISPLAY_LEGACY) != 0; |
| bool maySupportPlatformGetDisplay = (nativeDisplay.getCapabilities() & NativeDisplay::CAPABILITY_GET_DISPLAY_PLATFORM) != 0; |
| bool maySupportPlatformGetDisplayEXT = (nativeDisplay.getCapabilities() & NativeDisplay::CAPABILITY_GET_DISPLAY_PLATFORM_EXT) != 0; |
| bool usePlatformExt = false; |
| EGLDisplay display = EGL_NO_DISPLAY; |
| |
| TCU_CHECK_INTERNAL(supportsLegacyGetDisplay || maySupportPlatformGetDisplay); |
| |
| if (maySupportPlatformGetDisplayEXT) |
| { |
| try |
| { |
| const vector<string> platformExts = eglu::getClientExtensions(egl); |
| usePlatformExt = de::contains(platformExts.begin(), platformExts.end(), string("EGL_EXT_platform_base")) && |
| nativeDisplay.getPlatformExtensionName() && |
| de::contains(platformExts.begin(), platformExts.end(), string(nativeDisplay.getPlatformExtensionName())); |
| |
| } |
| catch (const tcu::NotSupportedError&) |
| { |
| // If we can't get the client extension string we must not have EGL 1.5 support or the appropriate extensions. |
| maySupportPlatformGetDisplay = false; |
| maySupportPlatformGetDisplayEXT = false; |
| usePlatformExt = false; |
| } |
| } |
| |
| if (maySupportPlatformGetDisplay) |
| { |
| display = egl.getPlatformDisplay(nativeDisplay.getPlatformType(), nativeDisplay.getPlatformNative(), nativeDisplay.getPlatformAttributes()); |
| EGLU_CHECK_MSG(egl, "eglGetPlatformDisplay()"); |
| TCU_CHECK(display != EGL_NO_DISPLAY); |
| } |
| else if (usePlatformExt) |
| { |
| const vector<EGLint> legacyAttribs = toLegacyAttribList(nativeDisplay.getPlatformAttributes()); |
| |
| display = egl.getPlatformDisplayEXT(nativeDisplay.getPlatformType(), nativeDisplay.getPlatformNative(), &legacyAttribs[0]); |
| EGLU_CHECK_MSG(egl, "eglGetPlatformDisplayEXT()"); |
| TCU_CHECK(display != EGL_NO_DISPLAY); |
| } |
| else if (supportsLegacyGetDisplay) |
| { |
| display = egl.getDisplay(nativeDisplay.getLegacyNative()); |
| EGLU_CHECK_MSG(egl, "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; |
| } |
| |
| EGLDisplay getAndInitDisplay (NativeDisplay& nativeDisplay, Version* version) |
| { |
| const Library& egl = nativeDisplay.getLibrary(); |
| EGLDisplay display = getDisplay(nativeDisplay); |
| int major, minor; |
| |
| EGLU_CHECK_CALL(egl, initialize(display, &major, &minor)); |
| |
| if (version) |
| *version = Version(major, minor); |
| |
| return display; |
| } |
| |
| void terminateDisplay(const Library& egl, EGLDisplay display) |
| { |
| EGLU_CHECK_CALL(egl, terminate(display)); |
| } |
| |
| //! Create EGL window surface using eglCreatePlatformWindowSurface, eglCreateWindowSurface() or eglCreatePlatformWindowSurfaceEXT() |
| EGLSurface createWindowSurface (NativeDisplay& nativeDisplay, NativeWindow& window, EGLDisplay display, EGLConfig config, const EGLAttrib* attribList) |
| { |
| const Library& egl = nativeDisplay.getLibrary(); |
| const bool supportsLegacyCreate = (window.getCapabilities() & NativeWindow::CAPABILITY_CREATE_SURFACE_LEGACY) != 0; |
| bool maySupportPlatformCreate = ((window.getCapabilities() & NativeWindow::CAPABILITY_CREATE_SURFACE_PLATFORM) != 0 |
| && eglu::getVersion(egl, display) >= eglu::Version(1, 5)); |
| bool maySupportPlatformCreateExtension = (window.getCapabilities() & NativeWindow::CAPABILITY_CREATE_SURFACE_PLATFORM_EXTENSION) != 0; |
| bool usePlatformExt = false; |
| EGLSurface surface = EGL_NO_SURFACE; |
| |
| TCU_CHECK_INTERNAL(supportsLegacyCreate || maySupportPlatformCreateExtension || maySupportPlatformCreate); |
| |
| if (maySupportPlatformCreateExtension) |
| { |
| try |
| { |
| const vector<string> platformExts = eglu::getClientExtensions(egl); |
| usePlatformExt = de::contains(platformExts.begin(), platformExts.end(), string("EGL_EXT_platform_base")) && |
| nativeDisplay.getPlatformExtensionName() && |
| de::contains(platformExts.begin(), platformExts.end(), string(nativeDisplay.getPlatformExtensionName())); |
| |
| } |
| catch (const tcu::NotSupportedError&) |
| { |
| maySupportPlatformCreate = false; |
| maySupportPlatformCreateExtension = false; |
| usePlatformExt = false; |
| } |
| } |
| |
| if (maySupportPlatformCreate) |
| { |
| surface = egl.createPlatformWindowSurface(display, config, window.getPlatformNative(), attribList); |
| EGLU_CHECK_MSG(egl, "eglCreatePlatformWindowSurface()"); |
| TCU_CHECK(surface != EGL_NO_SURFACE); |
| } |
| else if (usePlatformExt) |
| { |
| const vector<EGLint> legacyAttribs = toLegacyAttribList(attribList); |
| surface = egl.createPlatformWindowSurfaceEXT(display, config, window.getPlatformExtension(), &legacyAttribs[0]); |
| EGLU_CHECK_MSG(egl, "eglCreatePlatformWindowSurfaceEXT()"); |
| TCU_CHECK(surface != EGL_NO_SURFACE); |
| } |
| else if (supportsLegacyCreate) |
| { |
| const vector<EGLint> legacyAttribs = toLegacyAttribList(attribList); |
| surface = egl.createWindowSurface(display, config, window.getLegacyNative(), &legacyAttribs[0]); |
| EGLU_CHECK_MSG(egl, "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 Library& egl = nativeDisplay.getLibrary(); |
| const bool supportsLegacyCreate = (pixmap.getCapabilities() & NativePixmap::CAPABILITY_CREATE_SURFACE_LEGACY) != 0; |
| bool maySupportPlatformCreateExtension = (pixmap.getCapabilities() & NativePixmap::CAPABILITY_CREATE_SURFACE_PLATFORM_EXTENSION) != 0; |
| bool maySupportPlatformCreate = ((pixmap.getCapabilities() & NativePixmap::CAPABILITY_CREATE_SURFACE_PLATFORM) != 0 |
| && eglu::getVersion(egl, display) >= eglu::Version(1, 5)); |
| bool usePlatformExt = false; |
| EGLSurface surface = EGL_NO_SURFACE; |
| |
| TCU_CHECK_INTERNAL(supportsLegacyCreate || maySupportPlatformCreateExtension || maySupportPlatformCreate); |
| |
| if (maySupportPlatformCreateExtension) |
| { |
| try |
| { |
| const vector<string> platformExts = eglu::getClientExtensions(egl); |
| usePlatformExt = de::contains(platformExts.begin(), platformExts.end(), string("EGL_EXT_platform_base")) && |
| nativeDisplay.getPlatformExtensionName() && |
| de::contains(platformExts.begin(), platformExts.end(), string(nativeDisplay.getPlatformExtensionName())); |
| |
| } |
| catch (const tcu::NotSupportedError&) |
| { |
| maySupportPlatformCreate = false; |
| maySupportPlatformCreateExtension = false; |
| usePlatformExt = false; |
| } |
| } |
| |
| if (maySupportPlatformCreate) |
| { |
| surface = egl.createPlatformPixmapSurface(display, config, pixmap.getPlatformNative(), attribList); |
| EGLU_CHECK_MSG(egl, "eglCreatePlatformPixmapSurface()"); |
| TCU_CHECK(surface != EGL_NO_SURFACE); |
| } |
| else if (usePlatformExt) |
| { |
| const vector<EGLint> legacyAttribs = toLegacyAttribList(attribList); |
| |
| surface = egl.createPlatformPixmapSurfaceEXT(display, config, pixmap.getPlatformExtension(), &legacyAttribs[0]); |
| EGLU_CHECK_MSG(egl, "eglCreatePlatformPixmapSurfaceEXT()"); |
| TCU_CHECK(surface != EGL_NO_SURFACE); |
| } |
| else if (supportsLegacyCreate) |
| { |
| const vector<EGLint> legacyAttribs = toLegacyAttribList(attribList); |
| surface = egl.createPixmapSurface(display, config, pixmap.getLegacyNative(), &legacyAttribs[0]); |
| EGLU_CHECK_MSG(egl, "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()); |
| } |
| |
| EGLenum parseClientAPI (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 |
| throw tcu::InternalError("Unknown EGL client API '" + api + "'"); |
| } |
| |
| vector<EGLenum> parseClientAPIs (const std::string& apiList) |
| { |
| const vector<string> apiStrs = de::splitString(apiList, ' '); |
| vector<EGLenum> apis; |
| |
| for (vector<string>::const_iterator api = apiStrs.begin(); api != apiStrs.end(); ++api) |
| apis.push_back(parseClientAPI(*api)); |
| |
| return apis; |
| } |
| |
| vector<EGLenum> getClientAPIs (const eglw::Library& egl, eglw::EGLDisplay display) |
| { |
| return parseClientAPIs(egl.queryString(display, EGL_CLIENT_APIS)); |
| } |
| |
| EGLint getRenderableAPIsMask (const eglw::Library& egl, eglw::EGLDisplay display) |
| { |
| const vector<EGLConfig> configs = getConfigs(egl, display); |
| EGLint allAPIs = 0; |
| |
| for (vector<EGLConfig>::const_iterator i = configs.begin(); i != configs.end(); ++i) |
| allAPIs |= getConfigAttribInt(egl, display, *i, EGL_RENDERABLE_TYPE); |
| |
| return allAPIs; |
| } |
| |
| 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; |
| } |
| |
| template<typename Factory> |
| static const Factory& selectFactory (const tcu::FactoryRegistry<Factory>& registry, const char* objectTypeName, const char* cmdLineArg) |
| { |
| if (cmdLineArg) |
| { |
| const Factory* factory = registry.getFactoryByName(cmdLineArg); |
| |
| if (factory) |
| return *factory; |
| else |
| { |
| tcu::print("ERROR: Unknown or unsupported EGL %s type '%s'", objectTypeName, cmdLineArg); |
| tcu::print("Available EGL %s types:\n", objectTypeName); |
| for (size_t ndx = 0; ndx < registry.getFactoryCount(); ndx++) |
| tcu::print(" %s: %s\n", registry.getFactoryByIndex(ndx)->getName(), registry.getFactoryByIndex(ndx)->getDescription()); |
| |
| TCU_THROW(NotSupportedError, (string("Unsupported or unknown EGL ") + objectTypeName + " type '" + cmdLineArg + "'").c_str()); |
| } |
| } |
| else if (!registry.empty()) |
| return *registry.getDefaultFactory(); |
| else |
| TCU_THROW(NotSupportedError, (string("No factory supporting EGL '") + objectTypeName + "' type").c_str()); |
| } |
| |
| const NativeDisplayFactory& selectNativeDisplayFactory (const NativeDisplayFactoryRegistry& registry, const tcu::CommandLine& cmdLine) |
| { |
| return selectFactory(registry, "display", cmdLine.getEGLDisplayType()); |
| } |
| |
| const NativeWindowFactory& selectNativeWindowFactory (const NativeDisplayFactory& factory, const tcu::CommandLine& cmdLine) |
| { |
| return selectFactory(factory.getNativeWindowRegistry(), "window", cmdLine.getEGLWindowType()); |
| } |
| |
| const NativePixmapFactory& selectNativePixmapFactory (const NativeDisplayFactory& factory, const tcu::CommandLine& cmdLine) |
| { |
| return selectFactory(factory.getNativePixmapRegistry(), "pixmap", cmdLine.getEGLPixmapType()); |
| } |
| |
| } // eglu |