2014-10-07 20:46:19 +00:00
|
|
|
/*
|
|
|
|
* ***** BEGIN GPL LICENSE BLOCK *****
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*
|
|
|
|
* The Original Code is Copyright (C) 2013 Blender Foundation.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* The Original Code is: all of this file.
|
|
|
|
*
|
|
|
|
* Contributor(s): Jason Wilkins
|
|
|
|
*
|
|
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
|
|
*/
|
|
|
|
|
|
|
|
/** \file ghost/intern/GHOST_ContextEGL.cpp
|
|
|
|
* \ingroup GHOST
|
|
|
|
*
|
|
|
|
* Definition of GHOST_ContextEGL class.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "GHOST_ContextEGL.h"
|
|
|
|
|
|
|
|
#include <set>
|
|
|
|
#include <sstream>
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
#include <cassert>
|
|
|
|
#include <cstdio>
|
|
|
|
#include <cstring>
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef WITH_GLEW_MX
|
|
|
|
EGLEWContext *eglewContext = NULL;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
#define CASE_CODE_RETURN_STR(code) case code: return #code;
|
|
|
|
|
|
|
|
static const char *get_egl_error_enum_string(EGLenum error)
|
|
|
|
{
|
|
|
|
switch (error) {
|
|
|
|
CASE_CODE_RETURN_STR(EGL_SUCCESS)
|
|
|
|
CASE_CODE_RETURN_STR(EGL_NOT_INITIALIZED)
|
|
|
|
CASE_CODE_RETURN_STR(EGL_BAD_ACCESS)
|
|
|
|
CASE_CODE_RETURN_STR(EGL_BAD_ALLOC)
|
|
|
|
CASE_CODE_RETURN_STR(EGL_BAD_ATTRIBUTE)
|
|
|
|
CASE_CODE_RETURN_STR(EGL_BAD_CONTEXT)
|
|
|
|
CASE_CODE_RETURN_STR(EGL_BAD_CONFIG)
|
|
|
|
CASE_CODE_RETURN_STR(EGL_BAD_CURRENT_SURFACE)
|
|
|
|
CASE_CODE_RETURN_STR(EGL_BAD_DISPLAY)
|
|
|
|
CASE_CODE_RETURN_STR(EGL_BAD_SURFACE)
|
|
|
|
CASE_CODE_RETURN_STR(EGL_BAD_MATCH)
|
|
|
|
CASE_CODE_RETURN_STR(EGL_BAD_PARAMETER)
|
|
|
|
CASE_CODE_RETURN_STR(EGL_BAD_NATIVE_PIXMAP)
|
|
|
|
CASE_CODE_RETURN_STR(EGL_BAD_NATIVE_WINDOW)
|
|
|
|
CASE_CODE_RETURN_STR(EGL_CONTEXT_LOST)
|
|
|
|
default:
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char *get_egl_error_message_string(EGLenum error)
|
|
|
|
{
|
|
|
|
switch (error) {
|
|
|
|
case EGL_SUCCESS:
|
|
|
|
return "The last function succeeded without error.";
|
|
|
|
|
|
|
|
case EGL_NOT_INITIALIZED:
|
|
|
|
return ("EGL is not initialized, or could not be initialized, "
|
|
|
|
"for the specified EGL display connection.");
|
|
|
|
|
|
|
|
case EGL_BAD_ACCESS:
|
|
|
|
return ("EGL cannot access a requested resource "
|
|
|
|
"(for example a context is bound in another thread).");
|
|
|
|
|
|
|
|
case EGL_BAD_ALLOC:
|
|
|
|
return "EGL failed to allocate resources for the requested operation.";
|
|
|
|
|
|
|
|
case EGL_BAD_ATTRIBUTE:
|
|
|
|
return "An unrecognized attribute or attribute value was passed in the attribute list.";
|
|
|
|
|
|
|
|
case EGL_BAD_CONTEXT:
|
|
|
|
return "An EGLContext argument does not name a valid EGL rendering context.";
|
|
|
|
|
|
|
|
case EGL_BAD_CONFIG:
|
|
|
|
return "An EGLConfig argument does not name a valid EGL frame buffer configuration.";
|
|
|
|
|
|
|
|
case EGL_BAD_CURRENT_SURFACE:
|
|
|
|
return ("The current surface of the calling thread is a window, "
|
|
|
|
"pixel buffer or pixmap that is no longer valid.");
|
|
|
|
|
|
|
|
case EGL_BAD_DISPLAY:
|
|
|
|
return "An EGLDisplay argument does not name a valid EGL display connection.";
|
|
|
|
|
|
|
|
case EGL_BAD_SURFACE:
|
|
|
|
return ("An EGLSurface argument does not name a valid surface "
|
|
|
|
"(window, pixel buffer or pixmap) configured for GL rendering.");
|
|
|
|
|
|
|
|
case EGL_BAD_MATCH:
|
|
|
|
return ("Arguments are inconsistent "
|
|
|
|
"(for example, a valid context requires buffers not supplied by a valid surface).");
|
|
|
|
|
|
|
|
case EGL_BAD_PARAMETER:
|
|
|
|
return "One or more argument values are invalid.";
|
|
|
|
|
|
|
|
case EGL_BAD_NATIVE_PIXMAP:
|
|
|
|
return "A NativePixmapType argument does not refer to a valid native pixmap.";
|
|
|
|
|
|
|
|
case EGL_BAD_NATIVE_WINDOW:
|
|
|
|
return "A NativeWindowType argument does not refer to a valid native window.";
|
|
|
|
|
|
|
|
case EGL_CONTEXT_LOST:
|
|
|
|
return ("A power management event has occurred. "
|
|
|
|
"The application must destroy all contexts and reinitialise OpenGL ES state "
|
|
|
|
"and objects to continue rendering.");
|
|
|
|
|
|
|
|
default:
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static bool egl_chk(bool result, const char *file = NULL, int line = 0, const char *text = NULL)
|
|
|
|
{
|
|
|
|
if (!result) {
|
|
|
|
EGLenum error = eglGetError();
|
|
|
|
|
|
|
|
const char *code = get_egl_error_enum_string(error);
|
|
|
|
const char *msg = get_egl_error_message_string(error);
|
|
|
|
|
|
|
|
#ifndef NDEBUG
|
|
|
|
fprintf(stderr,
|
|
|
|
"%s(%d):[%s] -> EGL Error (0x%04X): %s: %s\n",
|
|
|
|
file, line, text, error,
|
|
|
|
code ? code : "<Unknown>",
|
|
|
|
msg ? msg : "<Unknown>");
|
|
|
|
#else
|
|
|
|
fprintf(stderr,
|
|
|
|
"EGL Error (0x%04X): %s: %s\n",
|
|
|
|
error,
|
|
|
|
code ? code : "<Unknown>",
|
|
|
|
msg ? msg : "<Unknown>");
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef NDEBUG
|
|
|
|
#define EGL_CHK(x) egl_chk((x), __FILE__, __LINE__, #x)
|
|
|
|
#else
|
|
|
|
#define EGL_CHK(x) egl_chk(x)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
static inline bool bindAPI(EGLenum api)
|
|
|
|
{
|
|
|
|
#ifdef WITH_GLEW_MX
|
|
|
|
if (eglewContext != NULL)
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
if (EGLEW_VERSION_1_2) {
|
|
|
|
return (EGL_CHK(eglBindAPI(api)) == EGL_TRUE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef WITH_GL_ANGLE
|
|
|
|
HMODULE GHOST_ContextEGL::s_d3dcompiler = NULL;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
EGLContext GHOST_ContextEGL::s_gl_sharedContext = EGL_NO_CONTEXT;
|
|
|
|
EGLint GHOST_ContextEGL::s_gl_sharedCount = 0;
|
|
|
|
|
|
|
|
EGLContext GHOST_ContextEGL::s_gles_sharedContext = EGL_NO_CONTEXT;
|
|
|
|
EGLint GHOST_ContextEGL::s_gles_sharedCount = 0;
|
|
|
|
|
|
|
|
EGLContext GHOST_ContextEGL::s_vg_sharedContext = EGL_NO_CONTEXT;
|
|
|
|
EGLint GHOST_ContextEGL::s_vg_sharedCount = 0;
|
|
|
|
|
|
|
|
|
|
|
|
#pragma warning(disable : 4715)
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
T &choose_api(EGLenum api, T &a, T &b, T &c)
|
|
|
|
{
|
|
|
|
switch (api) {
|
|
|
|
case EGL_OPENGL_API:
|
|
|
|
return a;
|
|
|
|
case EGL_OPENGL_ES_API:
|
|
|
|
return b;
|
|
|
|
case EGL_OPENVG_API:
|
|
|
|
return c;
|
|
|
|
default:
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
GHOST_ContextEGL::GHOST_ContextEGL(
|
|
|
|
bool stereoVisual,
|
|
|
|
GHOST_TUns16 numOfAASamples,
|
|
|
|
EGLNativeWindowType nativeWindow,
|
|
|
|
EGLNativeDisplayType nativeDisplay,
|
|
|
|
EGLint contextProfileMask,
|
|
|
|
EGLint contextMajorVersion,
|
|
|
|
EGLint contextMinorVersion,
|
|
|
|
EGLint contextFlags,
|
|
|
|
EGLint contextResetNotificationStrategy,
|
|
|
|
EGLenum api)
|
|
|
|
: GHOST_Context(stereoVisual, numOfAASamples),
|
|
|
|
m_nativeDisplay(nativeDisplay),
|
|
|
|
m_nativeWindow (nativeWindow),
|
|
|
|
m_contextProfileMask(contextProfileMask),
|
|
|
|
m_contextMajorVersion(contextMajorVersion),
|
|
|
|
m_contextMinorVersion(contextMinorVersion),
|
|
|
|
m_contextFlags(contextFlags),
|
|
|
|
m_contextResetNotificationStrategy(contextResetNotificationStrategy),
|
|
|
|
m_api(api),
|
|
|
|
m_context(EGL_NO_CONTEXT),
|
|
|
|
m_surface(EGL_NO_SURFACE),
|
|
|
|
m_display(EGL_NO_DISPLAY),
|
|
|
|
m_swap_interval(1),
|
|
|
|
#ifdef WITH_GLEW_MX
|
|
|
|
m_eglewContext(NULL),
|
|
|
|
#endif
|
|
|
|
m_sharedContext(choose_api(api, s_gl_sharedContext, s_gles_sharedContext, s_vg_sharedContext)),
|
|
|
|
m_sharedCount (choose_api(api, s_gl_sharedCount, s_gles_sharedCount, s_vg_sharedCount))
|
|
|
|
{
|
|
|
|
assert(m_nativeWindow != 0);
|
|
|
|
assert(m_nativeDisplay != NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
GHOST_ContextEGL::~GHOST_ContextEGL()
|
|
|
|
{
|
|
|
|
if (m_display != EGL_NO_DISPLAY) {
|
|
|
|
activateEGLEW();
|
|
|
|
|
|
|
|
bindAPI(m_api);
|
|
|
|
|
|
|
|
if (m_context != EGL_NO_CONTEXT) {
|
|
|
|
if (m_context == ::eglGetCurrentContext())
|
|
|
|
EGL_CHK(::eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
|
|
|
|
|
|
|
|
if (m_context != m_sharedContext || m_sharedCount == 1) {
|
|
|
|
assert(m_sharedCount > 0);
|
|
|
|
|
|
|
|
m_sharedCount--;
|
|
|
|
|
|
|
|
if (m_sharedCount == 0)
|
|
|
|
m_sharedContext = EGL_NO_CONTEXT;
|
|
|
|
|
|
|
|
EGL_CHK(::eglDestroyContext(m_display, m_context));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_surface != EGL_NO_SURFACE)
|
|
|
|
EGL_CHK(::eglDestroySurface(m_display, m_surface));
|
|
|
|
|
|
|
|
EGL_CHK(::eglTerminate(m_display));
|
|
|
|
|
|
|
|
#ifdef WITH_GLEW_MX
|
|
|
|
delete m_eglewContext;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
GHOST_TSuccess GHOST_ContextEGL::swapBuffers()
|
|
|
|
{
|
|
|
|
return EGL_CHK(::eglSwapBuffers(m_display, m_surface)) ? GHOST_kSuccess : GHOST_kFailure;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
GHOST_TSuccess GHOST_ContextEGL::setSwapInterval(int interval)
|
|
|
|
{
|
|
|
|
if (EGLEW_VERSION_1_1) {
|
|
|
|
if (EGL_CHK(::eglSwapInterval(m_display, interval))) {
|
|
|
|
m_swap_interval = interval;
|
|
|
|
|
|
|
|
return GHOST_kSuccess;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return GHOST_kFailure;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return GHOST_kFailure;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
GHOST_TSuccess GHOST_ContextEGL::getSwapInterval(int &intervalOut)
|
|
|
|
{
|
2014-10-23 01:03:25 +00:00
|
|
|
// This is a bit of a kludge because there does not seem to
|
|
|
|
// be a way to query the swap interval with EGL.
|
|
|
|
intervalOut = m_swap_interval;
|
2014-10-07 20:46:19 +00:00
|
|
|
|
|
|
|
return GHOST_kSuccess;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
GHOST_TSuccess GHOST_ContextEGL::activateDrawingContext()
|
|
|
|
{
|
|
|
|
if (m_display) {
|
|
|
|
activateEGLEW();
|
|
|
|
activateGLEW();
|
|
|
|
|
|
|
|
bindAPI(m_api);
|
|
|
|
|
|
|
|
return EGL_CHK(::eglMakeCurrent(m_display, m_surface, m_surface, m_context)) ? GHOST_kSuccess : GHOST_kFailure;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return GHOST_kFailure;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void GHOST_ContextEGL::initContextEGLEW()
|
|
|
|
{
|
|
|
|
#ifdef WITH_GLEW_MX
|
|
|
|
eglewContext = new EGLEWContext;
|
|
|
|
memset(eglewContext, 0, sizeof(EGLEWContext));
|
|
|
|
|
|
|
|
delete m_eglewContext;
|
|
|
|
m_eglewContext = eglewContext;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (GLEW_CHK(eglewInit(m_display)) != GLEW_OK)
|
|
|
|
fprintf(stderr, "Warning! EGLEW failed to initialize properly.\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static const std::string &api_string(EGLenum api)
|
|
|
|
{
|
|
|
|
static const std::string a("OpenGL");
|
|
|
|
static const std::string b("OpenGL ES");
|
|
|
|
static const std::string c("OpenVG");
|
|
|
|
|
|
|
|
return choose_api(api, a, b, c);
|
|
|
|
}
|
|
|
|
|
|
|
|
GHOST_TSuccess GHOST_ContextEGL::initializeDrawingContext()
|
|
|
|
{
|
|
|
|
// objects have to be declared here due to the use of goto
|
|
|
|
std::vector<EGLint> attrib_list;
|
|
|
|
EGLint num_config = 0;
|
|
|
|
|
|
|
|
if (m_stereoVisual)
|
|
|
|
fprintf(stderr, "Warning! Stereo OpenGL ES contexts are not supported.\n");
|
|
|
|
|
|
|
|
m_stereoVisual = false; // It doesn't matter what the Window wants.
|
|
|
|
|
|
|
|
#ifdef WITH_GL_ANGLE
|
|
|
|
// d3dcompiler_XX.dll needs to be loaded before ANGLE will work
|
|
|
|
if (s_d3dcompiler == NULL) {
|
|
|
|
s_d3dcompiler = LoadLibrary(D3DCOMPILER);
|
|
|
|
|
|
|
|
WIN32_CHK(s_d3dcompiler != NULL);
|
|
|
|
|
|
|
|
if (s_d3dcompiler == NULL) {
|
|
|
|
fprintf(stderr, "LoadLibrary(\"" D3DCOMPILER "\") failed!\n");
|
|
|
|
return GHOST_kFailure;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
EGLDisplay prev_display = eglGetCurrentDisplay();
|
|
|
|
EGLSurface prev_draw = eglGetCurrentSurface(EGL_DRAW);
|
|
|
|
EGLSurface prev_read = eglGetCurrentSurface(EGL_READ);
|
|
|
|
EGLContext prev_context = eglGetCurrentContext();
|
|
|
|
|
|
|
|
m_display = ::eglGetDisplay(m_nativeDisplay);
|
|
|
|
|
|
|
|
if (!EGL_CHK(m_display != EGL_NO_DISPLAY))
|
|
|
|
return GHOST_kFailure;
|
|
|
|
|
|
|
|
EGLint egl_major, egl_minor;
|
|
|
|
|
|
|
|
if (!EGL_CHK(::eglInitialize(m_display, &egl_major, &egl_minor)))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
fprintf(stderr, "EGL Version %d.%d\n", egl_major, egl_minor);
|
|
|
|
|
|
|
|
if (!EGL_CHK(::eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
initContextEGLEW();
|
|
|
|
|
|
|
|
if (!bindAPI(m_api))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
|
|
|
|
// build attribute list
|
|
|
|
|
|
|
|
attrib_list.reserve(20);
|
|
|
|
|
|
|
|
if (m_api == EGL_OPENGL_ES_API && EGLEW_VERSION_1_2) {
|
|
|
|
// According to the spec it seems that you are required to set EGL_RENDERABLE_TYPE,
|
|
|
|
// but some implementations (ANGLE) do not seem to care.
|
|
|
|
|
|
|
|
if (m_contextMajorVersion == 1) {
|
|
|
|
attrib_list.push_back(EGL_RENDERABLE_TYPE);
|
|
|
|
attrib_list.push_back(EGL_OPENGL_ES_BIT);
|
|
|
|
}
|
|
|
|
else if (m_contextMajorVersion == 2) {
|
|
|
|
attrib_list.push_back(EGL_RENDERABLE_TYPE);
|
|
|
|
attrib_list.push_back(EGL_OPENGL_ES2_BIT);
|
|
|
|
}
|
|
|
|
else if (m_contextMajorVersion == 3) {
|
|
|
|
attrib_list.push_back(EGL_RENDERABLE_TYPE);
|
|
|
|
attrib_list.push_back(EGL_OPENGL_ES3_BIT_KHR);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
fprintf(stderr,
|
|
|
|
"Warning! Unable to request an ES context of version %d.%d\n",
|
|
|
|
m_contextMajorVersion, m_contextMinorVersion);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!((m_contextMajorVersion == 1) ||
|
|
|
|
(m_contextMajorVersion == 2 && EGLEW_VERSION_1_3) ||
|
|
|
|
(m_contextMajorVersion == 3 && /*EGLEW_VERSION_1_4 &&*/ EGLEW_KHR_create_context) ||
|
|
|
|
(m_contextMajorVersion == 3 && EGLEW_VERSION_1_5)))
|
|
|
|
{
|
|
|
|
fprintf(stderr,
|
|
|
|
"Warning! May not be able to create a version %d.%d ES context with version %d.%d of EGL\n",
|
|
|
|
m_contextMajorVersion, m_contextMinorVersion, egl_major, egl_minor);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
attrib_list.push_back(EGL_RED_SIZE);
|
|
|
|
attrib_list.push_back(8);
|
|
|
|
|
|
|
|
attrib_list.push_back(EGL_GREEN_SIZE);
|
|
|
|
attrib_list.push_back(8);
|
|
|
|
|
|
|
|
attrib_list.push_back(EGL_BLUE_SIZE);
|
|
|
|
attrib_list.push_back(8);
|
|
|
|
|
|
|
|
#ifdef GHOST_OPENGL_ALPHA
|
|
|
|
attrib_list.push_back(EGL_ALPHA_SIZE);
|
|
|
|
attrib_list.push_back(8);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
attrib_list.push_back(EGL_DEPTH_SIZE);
|
|
|
|
attrib_list.push_back(24);
|
|
|
|
|
|
|
|
#ifdef GHOST_OPENGL_STENCIL
|
|
|
|
attrib_list.push_back(EGL_STENCIL_SIZE);
|
|
|
|
attrib_list.push_back(8);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (m_numOfAASamples > 0) {
|
|
|
|
attrib_list.push_back(EGL_SAMPLE_BUFFERS);
|
|
|
|
attrib_list.push_back(1);
|
|
|
|
|
|
|
|
attrib_list.push_back(EGL_SAMPLES);
|
|
|
|
attrib_list.push_back(m_numOfAASamples);
|
|
|
|
}
|
|
|
|
|
|
|
|
attrib_list.push_back(EGL_NONE);
|
|
|
|
|
|
|
|
EGLConfig config;
|
|
|
|
|
|
|
|
if (!EGL_CHK(::eglChooseConfig(m_display, &(attrib_list[0]), &config, 1, &num_config)))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
// A common error is to assume that ChooseConfig worked because it returned EGL_TRUE
|
|
|
|
if (num_config != 1) // num_config should be exactly 1
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (m_numOfAASamples > 0) {
|
|
|
|
EGLint actualSamples;
|
|
|
|
|
|
|
|
if (!EGL_CHK(::eglGetConfigAttrib(m_display, config, EGL_SAMPLE_BUFFERS, &actualSamples)))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (m_numOfAASamples != actualSamples) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"Warning! Unable to find a multisample pixel format that supports exactly %d samples. "
|
|
|
|
"Substituting one that uses %d samples.\n",
|
|
|
|
m_numOfAASamples,
|
|
|
|
actualSamples);
|
|
|
|
|
|
|
|
m_numOfAASamples = (GHOST_TUns16)actualSamples;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
m_surface = ::eglCreateWindowSurface(m_display, config, m_nativeWindow, NULL);
|
|
|
|
|
|
|
|
if (!EGL_CHK(m_surface != EGL_NO_SURFACE))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
attrib_list.clear();
|
|
|
|
|
|
|
|
if (EGLEW_VERSION_1_5 || EGLEW_KHR_create_context) {
|
|
|
|
if (m_api == EGL_OPENGL_API || m_api == EGL_OPENGL_ES_API) {
|
|
|
|
if (m_contextMajorVersion != 0) {
|
|
|
|
attrib_list.push_back(EGL_CONTEXT_MAJOR_VERSION_KHR);
|
|
|
|
attrib_list.push_back(m_contextMajorVersion);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_contextMinorVersion != 0) {
|
|
|
|
attrib_list.push_back(EGL_CONTEXT_MINOR_VERSION_KHR);
|
|
|
|
attrib_list.push_back(m_contextMinorVersion);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_contextFlags != 0) {
|
|
|
|
attrib_list.push_back(EGL_CONTEXT_FLAGS_KHR);
|
|
|
|
attrib_list.push_back(m_contextFlags);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (m_contextMajorVersion != 0 || m_contextMinorVersion != 0) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"Warning! Cannot request specific versions of %s contexts.",
|
|
|
|
api_string(m_api).c_str());
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_contextFlags != 0) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"Warning! Flags cannot be set on %s contexts.",
|
|
|
|
api_string(m_api).c_str());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_api == EGL_OPENGL_API) {
|
|
|
|
if (m_contextProfileMask != 0) {
|
|
|
|
attrib_list.push_back(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR);
|
|
|
|
attrib_list.push_back(m_contextProfileMask);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (m_contextProfileMask != 0)
|
|
|
|
fprintf(stderr,
|
|
|
|
"Warning! Cannot select profile for %s contexts.",
|
|
|
|
api_string(m_api).c_str());
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_api == EGL_OPENGL_API || EGLEW_VERSION_1_5) {
|
|
|
|
if (m_contextResetNotificationStrategy != 0) {
|
|
|
|
attrib_list.push_back(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR);
|
|
|
|
attrib_list.push_back(m_contextResetNotificationStrategy);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (m_contextResetNotificationStrategy != 0) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"Warning! EGL %d.%d cannot set the reset notification strategy on %s contexts.",
|
|
|
|
egl_major, egl_minor, api_string(m_api).c_str());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (m_api == EGL_OPENGL_ES_API) {
|
|
|
|
if (m_contextMajorVersion != 0) {
|
|
|
|
attrib_list.push_back(EGL_CONTEXT_CLIENT_VERSION);
|
|
|
|
attrib_list.push_back(m_contextMajorVersion);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (m_contextMajorVersion != 0 || m_contextMinorVersion != 0) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"Warning! EGL %d.%d is unable to select between versions of %s.",
|
|
|
|
egl_major, egl_minor, api_string(m_api).c_str());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_contextFlags != 0) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"Warning! EGL %d.%d is unable to set context flags.",
|
|
|
|
egl_major, egl_minor);
|
|
|
|
}
|
|
|
|
if (m_contextProfileMask != 0) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"Warning! EGL %d.%d is unable to select between profiles.",
|
|
|
|
egl_major, egl_minor);
|
|
|
|
}
|
|
|
|
if (m_contextResetNotificationStrategy != 0) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"Warning! EGL %d.%d is unable to set the reset notification strategies.",
|
|
|
|
egl_major, egl_minor);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
attrib_list.push_back(EGL_NONE);
|
|
|
|
|
|
|
|
m_context = ::eglCreateContext(m_display, config, m_sharedContext, &(attrib_list[0]));
|
|
|
|
|
|
|
|
if (!EGL_CHK(m_context != EGL_NO_CONTEXT))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (m_sharedContext == EGL_NO_CONTEXT)
|
|
|
|
m_sharedContext = m_context;
|
|
|
|
|
|
|
|
m_sharedCount++;
|
|
|
|
|
|
|
|
if (!EGL_CHK(::eglMakeCurrent(m_display, m_surface, m_surface, m_context)))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
initContextGLEW();
|
|
|
|
|
|
|
|
initClearGL();
|
|
|
|
::eglSwapBuffers(m_display, m_surface);
|
|
|
|
|
|
|
|
return GHOST_kSuccess;
|
|
|
|
|
|
|
|
error:
|
|
|
|
if (prev_display != EGL_NO_DISPLAY)
|
|
|
|
EGL_CHK(eglMakeCurrent(prev_display, prev_draw, prev_read, prev_context));
|
|
|
|
|
|
|
|
return GHOST_kFailure;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
GHOST_TSuccess GHOST_ContextEGL::releaseNativeHandles()
|
|
|
|
{
|
|
|
|
m_nativeWindow = 0;
|
|
|
|
m_nativeDisplay = NULL;
|
|
|
|
|
|
|
|
return GHOST_kSuccess;
|
|
|
|
}
|