Changeset View
Changeset View
Standalone View
Standalone View
intern/ghost/intern/GHOST_ContextEGL.cpp
| Show First 20 Lines • Show All 145 Lines • ▼ Show 20 Lines | |||||
| } | } | ||||
| #ifndef NDEBUG | #ifndef NDEBUG | ||||
| # define EGL_CHK(x) egl_chk((x), __FILE__, __LINE__, # x) | # define EGL_CHK(x) egl_chk((x), __FILE__, __LINE__, # x) | ||||
| #else | #else | ||||
| # define EGL_CHK(x) egl_chk(x) | # define EGL_CHK(x) egl_chk(x) | ||||
| #endif | #endif | ||||
| static inline bool bindAPI(EGLenum api) | |||||
| { | |||||
| if (EGLEW_VERSION_1_2) { | |||||
| return (EGL_CHK(eglBindAPI(api)) == EGL_TRUE); | |||||
| } | |||||
| return false; | |||||
| } | |||||
| #ifdef WITH_GL_ANGLE | #ifdef WITH_GL_ANGLE | ||||
| HMODULE GHOST_ContextEGL::s_d3dcompiler = nullptr; | HMODULE GHOST_ContextEGL::s_d3dcompiler = nullptr; | ||||
| #endif | #endif | ||||
| EGLContext GHOST_ContextEGL::s_gl_sharedContext = EGL_NO_CONTEXT; | EGLContext GHOST_ContextEGL::s_gl_sharedContext = EGL_NO_CONTEXT; | ||||
| EGLint GHOST_ContextEGL::s_gl_sharedCount = 0; | EGLint GHOST_ContextEGL::s_gl_sharedCount = 0; | ||||
| EGLContext GHOST_ContextEGL::s_gles_sharedContext = EGL_NO_CONTEXT; | EGLContext GHOST_ContextEGL::s_gles_sharedContext = EGL_NO_CONTEXT; | ||||
| ▲ Show 20 Lines • Show All 80 Lines • ▼ Show 20 Lines | |||||
| GHOST_TSuccess GHOST_ContextEGL::swapBuffers() | GHOST_TSuccess GHOST_ContextEGL::swapBuffers() | ||||
| { | { | ||||
| return EGL_CHK(::eglSwapBuffers(m_display, m_surface)) ? GHOST_kSuccess : GHOST_kFailure; | return EGL_CHK(::eglSwapBuffers(m_display, m_surface)) ? GHOST_kSuccess : GHOST_kFailure; | ||||
| } | } | ||||
| GHOST_TSuccess GHOST_ContextEGL::setSwapInterval(int interval) | GHOST_TSuccess GHOST_ContextEGL::setSwapInterval(int interval) | ||||
| { | { | ||||
| if (EGLEW_VERSION_1_1) { | if (epoxy_egl_version(m_display) >= 11) { | ||||
| if (EGL_CHK(::eglSwapInterval(m_display, interval))) { | if (EGL_CHK(::eglSwapInterval(m_display, interval))) { | ||||
| m_swap_interval = interval; | m_swap_interval = interval; | ||||
| return GHOST_kSuccess; | return GHOST_kSuccess; | ||||
| } | } | ||||
| return GHOST_kFailure; | return GHOST_kFailure; | ||||
| } | } | ||||
| return GHOST_kFailure; | return GHOST_kFailure; | ||||
| Show All 40 Lines | if (m_display) { | ||||
| return EGL_CHK(::eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) ? | return EGL_CHK(::eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) ? | ||||
| GHOST_kSuccess : | GHOST_kSuccess : | ||||
| GHOST_kFailure; | GHOST_kFailure; | ||||
| } | } | ||||
| return GHOST_kFailure; | return GHOST_kFailure; | ||||
| } | } | ||||
| bool GHOST_ContextEGL::initContextEGLEW() | inline bool GHOST_ContextEGL::bindAPI(EGLenum api) | ||||
| { | { | ||||
| /* We have to manually get this function before we can call eglewInit, since | if (epoxy_egl_version(m_display) >= 12) { | ||||
| * it requires a display argument. glewInit() does the same, but we only want | return (EGL_CHK(eglBindAPI(api)) == EGL_TRUE); | ||||
| * to initialize EGLEW here. */ | |||||
| eglGetDisplay = (PFNEGLGETDISPLAYPROC)eglGetProcAddress("eglGetDisplay"); | |||||
| if (eglGetDisplay == nullptr) { | |||||
| return false; | |||||
| } | |||||
| if (!EGL_CHK((m_display = ::eglGetDisplay(m_nativeDisplay)) != EGL_NO_DISPLAY)) { | |||||
| return false; | |||||
| } | } | ||||
| if (GLEW_CHK(eglewInit(m_display)) != GLEW_OK) { | |||||
| fprintf(stderr, "Warning! EGLEW failed to initialize properly.\n"); | |||||
| return false; | return false; | ||||
| } | } | ||||
| return true; | |||||
| } | |||||
| static const std::string &api_string(EGLenum api) | static const std::string &api_string(EGLenum api) | ||||
| { | { | ||||
| static const std::string a("OpenGL"); | static const std::string a("OpenGL"); | ||||
| static const std::string b("OpenGL ES"); | static const std::string b("OpenGL ES"); | ||||
| static const std::string c("OpenVG"); | static const std::string c("OpenVG"); | ||||
| return choose_api(api, a, b, c); | return choose_api(api, a, b, c); | ||||
| } | } | ||||
| GHOST_TSuccess GHOST_ContextEGL::initializeDrawingContext() | GHOST_TSuccess GHOST_ContextEGL::initializeDrawingContext() | ||||
| { | { | ||||
| /* Objects have to be declared here due to the use of `goto`. */ | /* Objects have to be declared here due to the use of `goto`. */ | ||||
| std::vector<EGLint> attrib_list; | std::vector<EGLint> attrib_list; | ||||
| EGLint num_config = 0; | EGLint num_config = 0; | ||||
| if (m_stereoVisual) { | if (m_stereoVisual) { | ||||
| fprintf(stderr, "Warning! Stereo OpenGL ES contexts are not supported.\n"); | fprintf(stderr, "Warning! Stereo OpenGL ES contexts are not supported.\n"); | ||||
| } | } | ||||
| m_stereoVisual = false; /* It doesn't matter what the Window wants. */ | m_stereoVisual = false; /* It doesn't matter what the Window wants. */ | ||||
| if (!initContextEGLEW()) { | |||||
| return GHOST_kFailure; | |||||
| } | |||||
| #ifdef WITH_GL_ANGLE | #ifdef WITH_GL_ANGLE | ||||
| /* `d3dcompiler_XX.dll` needs to be loaded before ANGLE will work. */ | /* `d3dcompiler_XX.dll` needs to be loaded before ANGLE will work. */ | ||||
| if (s_d3dcompiler == nullptr) { | if (s_d3dcompiler == nullptr) { | ||||
| s_d3dcompiler = LoadLibrary(D3DCOMPILER); | s_d3dcompiler = LoadLibrary(D3DCOMPILER); | ||||
| WIN32_CHK(s_d3dcompiler != nullptr); | WIN32_CHK(s_d3dcompiler != nullptr); | ||||
| if (s_d3dcompiler == nullptr) { | if (s_d3dcompiler == nullptr) { | ||||
| fprintf(stderr, "LoadLibrary(\"" D3DCOMPILER "\") failed!\n"); | fprintf(stderr, "LoadLibrary(\"" D3DCOMPILER "\") failed!\n"); | ||||
| return GHOST_kFailure; | return GHOST_kFailure; | ||||
| } | } | ||||
| } | } | ||||
| #endif | #endif | ||||
| EGLDisplay prev_display = eglGetCurrentDisplay(); | EGLDisplay prev_display = eglGetCurrentDisplay(); | ||||
| EGLSurface prev_draw = eglGetCurrentSurface(EGL_DRAW); | EGLSurface prev_draw = eglGetCurrentSurface(EGL_DRAW); | ||||
| EGLSurface prev_read = eglGetCurrentSurface(EGL_READ); | EGLSurface prev_read = eglGetCurrentSurface(EGL_READ); | ||||
| EGLContext prev_context = eglGetCurrentContext(); | EGLContext prev_context = eglGetCurrentContext(); | ||||
| EGLint egl_major, egl_minor; | EGLint egl_major, egl_minor; | ||||
| if (!EGL_CHK((m_display = ::eglGetDisplay(m_nativeDisplay)) != EGL_NO_DISPLAY)) { | |||||
| goto error; | |||||
| } | |||||
| if (!EGL_CHK(::eglInitialize(m_display, &egl_major, &egl_minor))) { | if (!EGL_CHK(::eglInitialize(m_display, &egl_major, &egl_minor))) { | ||||
| goto error; | goto error; | ||||
| } | } | ||||
| #ifdef WITH_GHOST_DEBUG | #ifdef WITH_GHOST_DEBUG | ||||
| fprintf(stderr, "EGL Version %d.%d\n", egl_major, egl_minor); | fprintf(stderr, "EGL Version %d.%d\n", egl_major, egl_minor); | ||||
| #endif | #endif | ||||
| if (!EGL_CHK(::eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT))) { | if (!EGL_CHK(::eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT))) { | ||||
| goto error; | goto error; | ||||
| } | } | ||||
| if (!bindAPI(m_api)) { | if (!bindAPI(m_api)) { | ||||
| goto error; | goto error; | ||||
| } | } | ||||
| /* Build attribute list. */ | /* Build attribute list. */ | ||||
| attrib_list.reserve(20); | attrib_list.reserve(20); | ||||
| if (m_api == EGL_OPENGL_ES_API && EGLEW_VERSION_1_2) { | if (m_api == EGL_OPENGL_ES_API && epoxy_egl_version(m_display) >= 12) { | ||||
| /* According to the spec it seems that you are required to set EGL_RENDERABLE_TYPE, | /* According to the spec it seems that you are required to set EGL_RENDERABLE_TYPE, | ||||
| * but some implementations (ANGLE) do not seem to care. */ | * but some implementations (ANGLE) do not seem to care. */ | ||||
| if (m_contextMajorVersion == 1) { | if (m_contextMajorVersion == 1) { | ||||
| attrib_list.push_back(EGL_RENDERABLE_TYPE); | attrib_list.push_back(EGL_RENDERABLE_TYPE); | ||||
| attrib_list.push_back(EGL_OPENGL_ES_BIT); | attrib_list.push_back(EGL_OPENGL_ES_BIT); | ||||
| } | } | ||||
| else if (m_contextMajorVersion == 2) { | else if (m_contextMajorVersion == 2) { | ||||
| attrib_list.push_back(EGL_RENDERABLE_TYPE); | attrib_list.push_back(EGL_RENDERABLE_TYPE); | ||||
| attrib_list.push_back(EGL_OPENGL_ES2_BIT); | attrib_list.push_back(EGL_OPENGL_ES2_BIT); | ||||
| } | } | ||||
| else if (m_contextMajorVersion == 3) { | else if (m_contextMajorVersion == 3) { | ||||
| attrib_list.push_back(EGL_RENDERABLE_TYPE); | attrib_list.push_back(EGL_RENDERABLE_TYPE); | ||||
| attrib_list.push_back(EGL_OPENGL_ES3_BIT_KHR); | attrib_list.push_back(EGL_OPENGL_ES3_BIT_KHR); | ||||
| } | } | ||||
| else { | else { | ||||
| fprintf(stderr, | fprintf(stderr, | ||||
| "Warning! Unable to request an ES context of version %d.%d\n", | "Warning! Unable to request an ES context of version %d.%d\n", | ||||
| m_contextMajorVersion, | m_contextMajorVersion, | ||||
| m_contextMinorVersion); | m_contextMinorVersion); | ||||
| } | } | ||||
| if (!((m_contextMajorVersion == 1) || (m_contextMajorVersion == 2 && EGLEW_VERSION_1_3) || | if (!((m_contextMajorVersion == 1) || | ||||
| (m_contextMajorVersion == 3 && /*EGLEW_VERSION_1_4 &&*/ EGLEW_KHR_create_context) || | (m_contextMajorVersion == 2 && epoxy_egl_version(m_display) >= 13) || | ||||
| (m_contextMajorVersion == 3 && EGLEW_VERSION_1_5))) { | (m_contextMajorVersion == 3 && | ||||
| epoxy_has_egl_extension(m_display, "KHR_create_context")) || | |||||
| (m_contextMajorVersion == 3 && epoxy_egl_version(m_display) >= 15))) { | |||||
| fprintf(stderr, | fprintf(stderr, | ||||
| "Warning! May not be able to create a version %d.%d ES context with version %d.%d " | "Warning! May not be able to create a version %d.%d ES context with version %d.%d " | ||||
| "of EGL\n", | "of EGL\n", | ||||
| m_contextMajorVersion, | m_contextMajorVersion, | ||||
| m_contextMinorVersion, | m_contextMinorVersion, | ||||
| egl_major, | egl_major, | ||||
| egl_minor); | egl_minor); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | else { | ||||
| m_surface = ::eglCreatePbufferSurface(m_display, m_config, pb_attrib_list); | m_surface = ::eglCreatePbufferSurface(m_display, m_config, pb_attrib_list); | ||||
| } | } | ||||
| if (!EGL_CHK(m_surface != EGL_NO_SURFACE)) { | if (!EGL_CHK(m_surface != EGL_NO_SURFACE)) { | ||||
| goto error; | goto error; | ||||
| } | } | ||||
| attrib_list.clear(); | attrib_list.clear(); | ||||
| if (EGLEW_VERSION_1_5 || EGLEW_KHR_create_context) { | if (epoxy_egl_version(m_display) >= 15 || | ||||
| epoxy_has_egl_extension(m_display, "KHR_create_context")) { | |||||
| if (m_api == EGL_OPENGL_API || m_api == EGL_OPENGL_ES_API) { | if (m_api == EGL_OPENGL_API || m_api == EGL_OPENGL_ES_API) { | ||||
| if (m_contextMajorVersion != 0) { | if (m_contextMajorVersion != 0) { | ||||
| attrib_list.push_back(EGL_CONTEXT_MAJOR_VERSION_KHR); | attrib_list.push_back(EGL_CONTEXT_MAJOR_VERSION_KHR); | ||||
| attrib_list.push_back(m_contextMajorVersion); | attrib_list.push_back(m_contextMajorVersion); | ||||
| } | } | ||||
| if (m_contextMinorVersion != 0) { | if (m_contextMinorVersion != 0) { | ||||
| attrib_list.push_back(EGL_CONTEXT_MINOR_VERSION_KHR); | attrib_list.push_back(EGL_CONTEXT_MINOR_VERSION_KHR); | ||||
| Show All 25 Lines | if (epoxy_egl_version(m_display) >= 15 || | ||||
| } | } | ||||
| else { | else { | ||||
| if (m_contextProfileMask != 0) { | if (m_contextProfileMask != 0) { | ||||
| fprintf( | fprintf( | ||||
| stderr, "Warning! Cannot select profile for %s contexts.", api_string(m_api).c_str()); | 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_api == EGL_OPENGL_API || epoxy_egl_version(m_display) >= 15) { | ||||
| if (m_contextResetNotificationStrategy != 0) { | if (m_contextResetNotificationStrategy != 0) { | ||||
| attrib_list.push_back(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR); | attrib_list.push_back(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR); | ||||
| attrib_list.push_back(m_contextResetNotificationStrategy); | attrib_list.push_back(m_contextResetNotificationStrategy); | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| if (m_contextResetNotificationStrategy != 0) { | if (m_contextResetNotificationStrategy != 0) { | ||||
| fprintf(stderr, | fprintf(stderr, | ||||
| ▲ Show 20 Lines • Show All 51 Lines • ▼ Show 20 Lines | #endif | ||||
| } | } | ||||
| m_sharedCount++; | m_sharedCount++; | ||||
| if (!EGL_CHK(::eglMakeCurrent(m_display, m_surface, m_surface, m_context))) { | if (!EGL_CHK(::eglMakeCurrent(m_display, m_surface, m_surface, m_context))) { | ||||
| goto error; | goto error; | ||||
| } | } | ||||
| initContextGLEW(); | |||||
| initClearGL(); | initClearGL(); | ||||
| ::eglSwapBuffers(m_display, m_surface); | ::eglSwapBuffers(m_display, m_surface); | ||||
| return GHOST_kSuccess; | return GHOST_kSuccess; | ||||
| error: | error: | ||||
| if (prev_display != EGL_NO_DISPLAY) { | if (prev_display != EGL_NO_DISPLAY) { | ||||
| EGL_CHK(eglMakeCurrent(prev_display, prev_draw, prev_read, prev_context)); | EGL_CHK(eglMakeCurrent(prev_display, prev_draw, prev_read, prev_context)); | ||||
| Show All 11 Lines | |||||