510 lines
15 KiB
C++
510 lines
15 KiB
C++
/*-------------------------------------------------------------------------
|
|
* 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 (void)
|
|
: m_library (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 (void) const
|
|
{
|
|
return new VulkanLibrary();
|
|
}
|
|
|
|
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();
|
|
}
|