| /*------------------------------------------------------------------------- |
| * drawElements Quality Program Tester Core |
| * ---------------------------------------- |
| * |
| * Copyright 2015 Intel Corporation |
| * |
| * 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 surfaceless platform |
| *//*--------------------------------------------------------------------*/ |
| |
| #include "tcuSurfacelessPlatform.hpp" |
| |
| #include <string> |
| #include <vector> |
| #include <sys/utsname.h> |
| |
| #include "deDynamicLibrary.hpp" |
| #include "deMemory.h" |
| #include "deSTLUtil.hpp" |
| #include "egluUtil.hpp" |
| #include "egluGLUtil.hpp" |
| #include "eglwEnums.hpp" |
| #include "eglwLibrary.hpp" |
| #include "gluPlatform.hpp" |
| #include "gluRenderConfig.hpp" |
| #include "glwInitES20Direct.hpp" |
| #include "glwInitES30Direct.hpp" |
| #include "glwInitFunctions.hpp" |
| #include "tcuFunctionLibrary.hpp" |
| #include "tcuPixelFormat.hpp" |
| #include "tcuPlatform.hpp" |
| #include "tcuRenderTarget.hpp" |
| #include "vkPlatform.hpp" |
| |
| #include <EGL/egl.h> |
| |
| using std::string; |
| using std::vector; |
| |
| #if !defined(EGL_KHR_create_context) |
| #define EGL_CONTEXT_FLAGS_KHR 0x30FC |
| #define EGL_CONTEXT_MAJOR_VERSION_KHR 0x3098 |
| #define EGL_CONTEXT_MINOR_VERSION_KHR 0x30FB |
| #define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR 0x00000002 |
| #define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR 0x00000001 |
| #define EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR 0x00000001 |
| #define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR 0x00000002 |
| #define EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR 0x30FD |
| #define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR 0x31BD |
| #define EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR 0x00000004 |
| #define EGL_KHR_create_context 1 |
| #define EGL_LOSE_CONTEXT_ON_RESET_KHR 0x31BF |
| #define EGL_NO_RESET_NOTIFICATION_KHR 0x31BE |
| #define EGL_OPENGL_ES3_BIT_KHR 0x00000040 |
| #endif // EGL_KHR_create_context |
| |
| // Default library names |
| #if !defined(DEQP_GLES2_LIBRARY_PATH) |
| # define DEQP_GLES2_LIBRARY_PATH "libGLESv2.so" |
| #endif |
| |
| #if !defined(DEQP_GLES3_LIBRARY_PATH) |
| # define DEQP_GLES3_LIBRARY_PATH DEQP_GLES2_LIBRARY_PATH |
| #endif |
| |
| #if !defined(DEQP_OPENGL_LIBRARY_PATH) |
| # define DEQP_OPENGL_LIBRARY_PATH "libGL.so" |
| #endif |
| |
| #if !defined(DEQP_VULKAN_LIBRARY_PATH) |
| # if (DE_OS == DE_OS_ANDROID) |
| # define DEQP_VULKAN_LIBRARY_PATH "libvulkan.so" |
| # else |
| # define DEQP_VULKAN_LIBRARY_PATH "libvulkan.so.1" |
| # endif |
| #endif |
| |
| namespace tcu |
| { |
| namespace surfaceless |
| { |
| |
| class VulkanLibrary : public vk::Library |
| { |
| public: |
| VulkanLibrary (const char* libraryPath) |
| : m_library (libraryPath != DE_NULL ? libraryPath : DEQP_VULKAN_LIBRARY_PATH) |
| , m_driver (m_library) |
| { |
| } |
| |
| const vk::PlatformInterface& getPlatformInterface (void) const |
| { |
| return m_driver; |
| } |
| const tcu::FunctionLibrary& getFunctionLibrary (void) const |
| { |
| return m_library; |
| } |
| private: |
| const tcu::DynamicFunctionLibrary m_library; |
| const vk::PlatformDriver m_driver; |
| }; |
| |
| // Copied from tcuX11Platform.cpp |
| class VulkanPlatform : public vk::Platform |
| { |
| public: |
| vk::Library* createLibrary (const char* libraryPath) const |
| { |
| return new VulkanLibrary(libraryPath); |
| } |
| |
| void describePlatform (std::ostream& dst) const |
| { |
| utsname sysInfo; |
| |
| deMemset(&sysInfo, 0, sizeof(sysInfo)); |
| |
| if (uname(&sysInfo) != 0) |
| throw std::runtime_error("uname() failed"); |
| |
| dst << "OS: " << sysInfo.sysname << " " << sysInfo.release << " " << sysInfo.version << "\n"; |
| dst << "CPU: " << sysInfo.machine << "\n"; |
| } |
| }; |
| |
| bool isEGLExtensionSupported( |
| const eglw::Library& egl, |
| eglw::EGLDisplay, |
| const std::string& extName) |
| { |
| const vector<string> exts = eglu::getClientExtensions(egl); |
| return de::contains(exts.begin(), exts.end(), extName); |
| } |
| |
| class GetProcFuncLoader : public glw::FunctionLoader |
| { |
| public: |
| GetProcFuncLoader(const eglw::Library& egl): m_egl(egl) |
| { |
| } |
| |
| glw::GenericFuncType get(const char* name) const |
| { |
| return (glw::GenericFuncType)m_egl.getProcAddress(name); |
| } |
| protected: |
| const eglw::Library& m_egl; |
| }; |
| |
| class DynamicFuncLoader : public glw::FunctionLoader |
| { |
| public: |
| DynamicFuncLoader(de::DynamicLibrary* library): m_library(library) |
| { |
| } |
| |
| glw::GenericFuncType get(const char* name) const |
| { |
| return (glw::GenericFuncType)m_library->getFunction(name); |
| } |
| |
| private: |
| de::DynamicLibrary* m_library; |
| }; |
| |
| class Platform : public tcu::Platform, public glu::Platform |
| { |
| public: |
| Platform (void); |
| const glu::Platform& getGLPlatform (void) const { return *this; } |
| const vk::Platform& getVulkanPlatform (void) const { return m_vkPlatform; } |
| |
| private: |
| VulkanPlatform m_vkPlatform; |
| }; |
| |
| class ContextFactory : public glu::ContextFactory |
| { |
| public: |
| ContextFactory (void); |
| glu::RenderContext* createContext (const glu::RenderConfig& config, const tcu::CommandLine&, const glu::RenderContext*) const; |
| }; |
| |
| class EglRenderContext : public glu::RenderContext |
| { |
| public: |
| EglRenderContext(const glu::RenderConfig& config, const tcu::CommandLine& cmdLine); |
| ~EglRenderContext(void); |
| |
| glu::ContextType getType (void) const { return m_contextType; } |
| const glw::Functions& getFunctions (void) const { return m_glFunctions; } |
| const tcu::RenderTarget& getRenderTarget (void) const; |
| void postIterate (void); |
| |
| virtual glw::GenericFuncType getProcAddress (const char* name) const { return m_egl.getProcAddress(name); } |
| |
| private: |
| const eglw::DefaultLibrary m_egl; |
| const glu::ContextType m_contextType; |
| eglw::EGLDisplay m_eglDisplay; |
| eglw::EGLContext m_eglContext; |
| de::DynamicLibrary* m_glLibrary; |
| glw::Functions m_glFunctions; |
| tcu::RenderTarget m_renderTarget; |
| }; |
| |
| Platform::Platform(void) |
| { |
| m_contextFactoryRegistry.registerFactory(new ContextFactory()); |
| } |
| |
| ContextFactory::ContextFactory() |
| : glu::ContextFactory("default", "EGL surfaceless context") |
| {} |
| |
| glu::RenderContext* ContextFactory::createContext(const glu::RenderConfig& config, const tcu::CommandLine& cmdLine, const glu::RenderContext*) const |
| { |
| return new EglRenderContext(config, cmdLine); |
| } |
| |
| EglRenderContext::EglRenderContext(const glu::RenderConfig& config, const tcu::CommandLine& cmdLine) |
| : m_egl("libEGL.so") |
| , m_contextType(config.type) |
| , m_eglDisplay(EGL_NO_DISPLAY) |
| , m_eglContext(EGL_NO_CONTEXT) |
| , m_renderTarget( |
| config.width, |
| config.height, |
| tcu::PixelFormat( |
| config.redBits, |
| config.greenBits, |
| config.blueBits, |
| config.alphaBits), |
| config.depthBits, |
| config.stencilBits, |
| config.numSamples) |
| |
| { |
| vector<eglw::EGLint> context_attribs; |
| vector<eglw::EGLint> frame_buffer_attribs; |
| vector<eglw::EGLint> surface_attribs; |
| |
| const glu::ContextType& contextType = config.type; |
| eglw::EGLint eglMajorVersion; |
| eglw::EGLint eglMinorVersion; |
| eglw::EGLint flags = 0; |
| eglw::EGLint num_configs; |
| eglw::EGLConfig egl_config = NULL; |
| eglw::EGLSurface egl_surface; |
| |
| (void) cmdLine; |
| |
| m_eglDisplay = m_egl.getDisplay(NULL); |
| EGLU_CHECK_MSG(m_egl, "eglGetDisplay()"); |
| if (m_eglDisplay == EGL_NO_DISPLAY) |
| throw tcu::ResourceError("eglGetDisplay() failed"); |
| |
| EGLU_CHECK_CALL(m_egl, initialize(m_eglDisplay, &eglMajorVersion, &eglMinorVersion)); |
| |
| frame_buffer_attribs.push_back(EGL_RENDERABLE_TYPE); |
| switch(contextType.getMajorVersion()) |
| { |
| case 3: |
| frame_buffer_attribs.push_back(EGL_OPENGL_ES3_BIT); |
| break; |
| case 2: |
| frame_buffer_attribs.push_back(EGL_OPENGL_ES2_BIT); |
| break; |
| default: |
| frame_buffer_attribs.push_back(EGL_OPENGL_ES_BIT); |
| } |
| |
| frame_buffer_attribs.push_back(EGL_SURFACE_TYPE); |
| switch (config.surfaceType) |
| { |
| case glu::RenderConfig::SURFACETYPE_DONT_CARE: |
| frame_buffer_attribs.push_back(EGL_DONT_CARE); |
| break; |
| case glu::RenderConfig::SURFACETYPE_OFFSCREEN_NATIVE: |
| case glu::RenderConfig::SURFACETYPE_OFFSCREEN_GENERIC: |
| frame_buffer_attribs.push_back(EGL_PBUFFER_BIT); |
| surface_attribs.push_back(EGL_WIDTH); |
| surface_attribs.push_back(config.width); |
| surface_attribs.push_back(EGL_HEIGHT); |
| surface_attribs.push_back(config.height); |
| break; |
| case glu::RenderConfig::SURFACETYPE_WINDOW: |
| throw tcu::NotSupportedError("surfaceless platform does not support --deqp-surface-type=window"); |
| case glu::RenderConfig::SURFACETYPE_LAST: |
| TCU_CHECK_INTERNAL(false); |
| } |
| |
| surface_attribs.push_back(EGL_NONE); |
| |
| frame_buffer_attribs.push_back(EGL_RED_SIZE); |
| frame_buffer_attribs.push_back(config.redBits); |
| |
| frame_buffer_attribs.push_back(EGL_GREEN_SIZE); |
| frame_buffer_attribs.push_back(config.greenBits); |
| |
| frame_buffer_attribs.push_back(EGL_BLUE_SIZE); |
| frame_buffer_attribs.push_back(config.blueBits); |
| |
| frame_buffer_attribs.push_back(EGL_ALPHA_SIZE); |
| frame_buffer_attribs.push_back(config.alphaBits); |
| |
| frame_buffer_attribs.push_back(EGL_DEPTH_SIZE); |
| frame_buffer_attribs.push_back(config.depthBits); |
| |
| frame_buffer_attribs.push_back(EGL_STENCIL_SIZE); |
| frame_buffer_attribs.push_back(config.stencilBits); |
| |
| frame_buffer_attribs.push_back(EGL_SAMPLES); |
| frame_buffer_attribs.push_back(config.numSamples); |
| |
| frame_buffer_attribs.push_back(EGL_NONE); |
| |
| if (!eglChooseConfig(m_eglDisplay, &frame_buffer_attribs[0], NULL, 0, &num_configs)) |
| throw tcu::ResourceError("surfaceless couldn't find any config"); |
| |
| eglw::EGLConfig all_configs[num_configs]; |
| |
| if (!eglChooseConfig(m_eglDisplay, &frame_buffer_attribs[0], all_configs, num_configs, &num_configs)) |
| throw tcu::ResourceError("surfaceless couldn't find any config"); |
| |
| for (int i = 0; i < num_configs; i++) { |
| EGLint red, green, blue, alpha, depth, stencil, samples; |
| eglGetConfigAttrib(m_eglDisplay, all_configs[i], EGL_RED_SIZE, &red); |
| eglGetConfigAttrib(m_eglDisplay, all_configs[i], EGL_GREEN_SIZE, &green); |
| eglGetConfigAttrib(m_eglDisplay, all_configs[i], EGL_BLUE_SIZE, &blue); |
| eglGetConfigAttrib(m_eglDisplay, all_configs[i], EGL_ALPHA_SIZE, &alpha); |
| eglGetConfigAttrib(m_eglDisplay, all_configs[i], EGL_DEPTH_SIZE, &depth); |
| eglGetConfigAttrib(m_eglDisplay, all_configs[i], EGL_STENCIL_SIZE, &stencil); |
| eglGetConfigAttrib(m_eglDisplay, all_configs[i], EGL_SAMPLES, &samples); |
| |
| if ( |
| (glu::RenderConfig::DONT_CARE == config.redBits || red == config.redBits) && |
| (glu::RenderConfig::DONT_CARE == config.greenBits || green == config.greenBits) && |
| (glu::RenderConfig::DONT_CARE == config.blueBits || blue == config.blueBits) && |
| (glu::RenderConfig::DONT_CARE == config.alphaBits || alpha == config.alphaBits) && |
| (glu::RenderConfig::DONT_CARE == config.depthBits || depth == config.depthBits) && |
| (glu::RenderConfig::DONT_CARE == config.stencilBits || stencil == config.stencilBits) && |
| (glu::RenderConfig::DONT_CARE == config.numSamples || samples == config.numSamples)) { |
| egl_config = all_configs[i]; |
| break; |
| } |
| } |
| |
| if (!egl_config) |
| throw tcu::ResourceError("surfaceless couldn't find a matching config"); |
| |
| switch (config.surfaceType) |
| { |
| case glu::RenderConfig::SURFACETYPE_DONT_CARE: |
| egl_surface = EGL_NO_SURFACE; |
| break; |
| case glu::RenderConfig::SURFACETYPE_OFFSCREEN_NATIVE: |
| case glu::RenderConfig::SURFACETYPE_OFFSCREEN_GENERIC: |
| egl_surface = eglCreatePbufferSurface(m_eglDisplay, egl_config, &surface_attribs[0]); |
| break; |
| case glu::RenderConfig::SURFACETYPE_WINDOW: |
| case glu::RenderConfig::SURFACETYPE_LAST: |
| TCU_CHECK_INTERNAL(false); |
| } |
| |
| context_attribs.push_back(EGL_CONTEXT_MAJOR_VERSION_KHR); |
| context_attribs.push_back(contextType.getMajorVersion()); |
| context_attribs.push_back(EGL_CONTEXT_MINOR_VERSION_KHR); |
| context_attribs.push_back(contextType.getMinorVersion()); |
| |
| switch (contextType.getProfile()) |
| { |
| case glu::PROFILE_ES: |
| EGLU_CHECK_CALL(m_egl, bindAPI(EGL_OPENGL_ES_API)); |
| break; |
| case glu::PROFILE_CORE: |
| EGLU_CHECK_CALL(m_egl, bindAPI(EGL_OPENGL_API)); |
| context_attribs.push_back(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR); |
| context_attribs.push_back(EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR); |
| break; |
| case glu::PROFILE_COMPATIBILITY: |
| EGLU_CHECK_CALL(m_egl, bindAPI(EGL_OPENGL_API)); |
| context_attribs.push_back(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR); |
| context_attribs.push_back(EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR); |
| break; |
| case glu::PROFILE_LAST: |
| TCU_CHECK_INTERNAL(false); |
| } |
| |
| if ((contextType.getFlags() & glu::CONTEXT_DEBUG) != 0) |
| flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR; |
| |
| if ((contextType.getFlags() & glu::CONTEXT_ROBUST) != 0) |
| flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR; |
| |
| if ((contextType.getFlags() & glu::CONTEXT_FORWARD_COMPATIBLE) != 0) |
| flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR; |
| |
| context_attribs.push_back(EGL_CONTEXT_FLAGS_KHR); |
| context_attribs.push_back(flags); |
| |
| context_attribs.push_back(EGL_NONE); |
| |
| m_eglContext = m_egl.createContext(m_eglDisplay, egl_config, EGL_NO_CONTEXT, &context_attribs[0]); |
| EGLU_CHECK_MSG(m_egl, "eglCreateContext()"); |
| if (!m_eglContext) |
| throw tcu::ResourceError("eglCreateContext failed"); |
| |
| EGLU_CHECK_CALL(m_egl, makeCurrent(m_eglDisplay, egl_surface, egl_surface, m_eglContext)); |
| |
| if ((eglMajorVersion == 1 && eglMinorVersion >= 5) || |
| isEGLExtensionSupported(m_egl, m_eglDisplay, "EGL_KHR_get_all_proc_addresses") || |
| isEGLExtensionSupported(m_egl, EGL_NO_DISPLAY, "EGL_KHR_client_get_all_proc_addresses")) |
| { |
| // Use eglGetProcAddress() for core functions |
| GetProcFuncLoader funcLoader(m_egl); |
| glu::initCoreFunctions(&m_glFunctions, &funcLoader, contextType.getAPI()); |
| } |
| #if !defined(DEQP_GLES2_RUNTIME_LOAD) |
| else if (contextType.getAPI() == glu::ApiType::es(2,0)) |
| { |
| glw::initES20Direct(&m_glFunctions); |
| } |
| #endif |
| #if !defined(DEQP_GLES3_RUNTIME_LOAD) |
| else if (contextType.getAPI() == glu::ApiType::es(3,0)) |
| { |
| glw::initES30Direct(&m_glFunctions); |
| } |
| #endif |
| else |
| { |
| const char* libraryPath = NULL; |
| |
| if (glu::isContextTypeES(contextType)) |
| { |
| if (contextType.getMinorVersion() <= 2) |
| libraryPath = DEQP_GLES2_LIBRARY_PATH; |
| else |
| libraryPath = DEQP_GLES3_LIBRARY_PATH; |
| } |
| else |
| { |
| libraryPath = DEQP_OPENGL_LIBRARY_PATH; |
| } |
| |
| m_glLibrary = new de::DynamicLibrary(libraryPath); |
| |
| DynamicFuncLoader funcLoader(m_glLibrary); |
| glu::initCoreFunctions(&m_glFunctions, &funcLoader, contextType.getAPI()); |
| } |
| |
| { |
| GetProcFuncLoader extLoader(m_egl); |
| glu::initExtensionFunctions(&m_glFunctions, &extLoader, contextType.getAPI()); |
| } |
| } |
| |
| EglRenderContext::~EglRenderContext(void) |
| { |
| try |
| { |
| if (m_eglDisplay != EGL_NO_DISPLAY) |
| { |
| EGLU_CHECK_CALL(m_egl, makeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)); |
| |
| if (m_eglContext != EGL_NO_CONTEXT) |
| EGLU_CHECK_CALL(m_egl, destroyContext(m_eglDisplay, m_eglContext)); |
| } |
| |
| EGLU_CHECK_CALL(m_egl, terminate(m_eglDisplay)); |
| } |
| catch (...) |
| { |
| } |
| } |
| |
| const tcu::RenderTarget& EglRenderContext::getRenderTarget(void) const |
| { |
| return m_renderTarget; |
| } |
| |
| void EglRenderContext::postIterate(void) |
| { |
| this->getFunctions().finish(); |
| } |
| |
| } // namespace surfaceless |
| } // namespace tcu |
| |
| tcu::Platform* createPlatform(void) |
| { |
| return new tcu::surfaceless::Platform(); |
| } |