Changeset View
Changeset View
Standalone View
Standalone View
intern/ghost/intern/GHOST_ContextEGL.cpp
| Show All 31 Lines | |||||
| #include <cassert> | #include <cassert> | ||||
| #include <cstdio> | #include <cstdio> | ||||
| #include <cstring> | #include <cstring> | ||||
| #define CASE_CODE_RETURN_STR(code) \ | #define CASE_CODE_RETURN_STR(code) \ | ||||
| case code: \ | case code: \ | ||||
| return #code; | return #code; | ||||
| static const char *get_egl_error_enum_string(EGLenum error) | static const char *get_egl_error_enum_string(EGLint error) | ||||
| { | { | ||||
| switch (error) { | switch (error) { | ||||
| CASE_CODE_RETURN_STR(EGL_SUCCESS) | CASE_CODE_RETURN_STR(EGL_SUCCESS) | ||||
| CASE_CODE_RETURN_STR(EGL_NOT_INITIALIZED) | CASE_CODE_RETURN_STR(EGL_NOT_INITIALIZED) | ||||
| CASE_CODE_RETURN_STR(EGL_BAD_ACCESS) | CASE_CODE_RETURN_STR(EGL_BAD_ACCESS) | ||||
| CASE_CODE_RETURN_STR(EGL_BAD_ALLOC) | CASE_CODE_RETURN_STR(EGL_BAD_ALLOC) | ||||
| CASE_CODE_RETURN_STR(EGL_BAD_ATTRIBUTE) | CASE_CODE_RETURN_STR(EGL_BAD_ATTRIBUTE) | ||||
| CASE_CODE_RETURN_STR(EGL_BAD_CONTEXT) | CASE_CODE_RETURN_STR(EGL_BAD_CONTEXT) | ||||
| CASE_CODE_RETURN_STR(EGL_BAD_CONFIG) | CASE_CODE_RETURN_STR(EGL_BAD_CONFIG) | ||||
| CASE_CODE_RETURN_STR(EGL_BAD_CURRENT_SURFACE) | CASE_CODE_RETURN_STR(EGL_BAD_CURRENT_SURFACE) | ||||
| CASE_CODE_RETURN_STR(EGL_BAD_DISPLAY) | CASE_CODE_RETURN_STR(EGL_BAD_DISPLAY) | ||||
| CASE_CODE_RETURN_STR(EGL_BAD_SURFACE) | CASE_CODE_RETURN_STR(EGL_BAD_SURFACE) | ||||
| CASE_CODE_RETURN_STR(EGL_BAD_MATCH) | CASE_CODE_RETURN_STR(EGL_BAD_MATCH) | ||||
| CASE_CODE_RETURN_STR(EGL_BAD_PARAMETER) | CASE_CODE_RETURN_STR(EGL_BAD_PARAMETER) | ||||
| CASE_CODE_RETURN_STR(EGL_BAD_NATIVE_PIXMAP) | CASE_CODE_RETURN_STR(EGL_BAD_NATIVE_PIXMAP) | ||||
| CASE_CODE_RETURN_STR(EGL_BAD_NATIVE_WINDOW) | CASE_CODE_RETURN_STR(EGL_BAD_NATIVE_WINDOW) | ||||
| CASE_CODE_RETURN_STR(EGL_CONTEXT_LOST) | CASE_CODE_RETURN_STR(EGL_CONTEXT_LOST) | ||||
| default: | default: | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| } | } | ||||
| static const char *get_egl_error_message_string(EGLenum error) | static const char *get_egl_error_message_string(EGLint error) | ||||
| { | { | ||||
| switch (error) { | switch (error) { | ||||
| case EGL_SUCCESS: | case EGL_SUCCESS: | ||||
| return "The last function succeeded without error."; | return "The last function succeeded without error."; | ||||
| case EGL_NOT_INITIALIZED: | case EGL_NOT_INITIALIZED: | ||||
| return ( | return ( | ||||
| "EGL is not initialized, or could not be initialized, " | "EGL is not initialized, or could not be initialized, " | ||||
| ▲ Show 20 Lines • Show All 52 Lines • ▼ Show 20 Lines | switch (error) { | ||||
| default: | default: | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| } | } | ||||
| static bool egl_chk(bool result, const char *file = NULL, int line = 0, const char *text = NULL) | static bool egl_chk(bool result, const char *file = NULL, int line = 0, const char *text = NULL) | ||||
| { | { | ||||
| if (!result) { | if (!result) { | ||||
| EGLenum error = eglGetError(); | const EGLint error = eglGetError(); | ||||
| const char *code = get_egl_error_enum_string(error); | const char *code = get_egl_error_enum_string(error); | ||||
| const char *msg = get_egl_error_message_string(error); | const char *msg = get_egl_error_message_string(error); | ||||
| #ifndef NDEBUG | #ifndef NDEBUG | ||||
| fprintf(stderr, | fprintf(stderr, | ||||
| "%s(%d):[%s] -> EGL Error (0x%04X): %s: %s\n", | "%s(%d):[%s] -> EGL Error (0x%04X): %s: %s\n", | ||||
| file, | file, | ||||
| line, | line, | ||||
| text, | text, | ||||
| error, | static_cast<unsigned int>(error), | ||||
| code ? code : "<Unknown>", | code ? code : "<Unknown>", | ||||
| msg ? msg : "<Unknown>"); | msg ? msg : "<Unknown>"); | ||||
| #else | #else | ||||
| fprintf(stderr, | fprintf(stderr, | ||||
| "EGL Error (0x%04X): %s: %s\n", | "EGL Error (0x%04X): %s: %s\n", | ||||
| error, | static_cast<unsigned int>(error), | ||||
| code ? code : "<Unknown>", | code ? code : "<Unknown>", | ||||
| msg ? msg : "<Unknown>"); | msg ? msg : "<Unknown>"); | ||||
| #endif | #endif | ||||
| } | } | ||||
| return result; | return result; | ||||
| } | } | ||||
| #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) | static inline bool bindAPI(EGLenum api) | ||||
| { | { | ||||
| if (EGLEW_VERSION_1_2) { | if (EGLEW_VERSION_1_2) { | ||||
brecht: This is wrong because `EGL_VERSION_1_2` is a #define that indicates if the header file contains… | |||||
Done Inline ActionsGood point. The reasons for using glew+egl in place of eglew have been stated in the other comment. What would be the proper replacement for EGLEW_VERSION_* checks, when not using eglew? christian.rauch: Good point. The reasons for using glew+egl in place of eglew have been stated in the other… | |||||
| return (EGL_CHK(eglBindAPI(api)) == EGL_TRUE); | return (EGL_CHK(eglBindAPI(api)) == EGL_TRUE); | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| #ifdef WITH_GL_ANGLE | #ifdef WITH_GL_ANGLE | ||||
| HMODULE GHOST_ContextEGL::s_d3dcompiler = NULL; | HMODULE GHOST_ContextEGL::s_d3dcompiler = NULL; | ||||
| ▲ Show 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | : GHOST_Context(stereoVisual), | ||||
| m_context(EGL_NO_CONTEXT), | m_context(EGL_NO_CONTEXT), | ||||
| m_surface(EGL_NO_SURFACE), | m_surface(EGL_NO_SURFACE), | ||||
| m_display(EGL_NO_DISPLAY), | m_display(EGL_NO_DISPLAY), | ||||
| m_swap_interval(1), | m_swap_interval(1), | ||||
| m_sharedContext( | m_sharedContext( | ||||
| choose_api(api, s_gl_sharedContext, s_gles_sharedContext, s_vg_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)) | 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() | GHOST_ContextEGL::~GHOST_ContextEGL() | ||||
| { | { | ||||
| if (m_display != EGL_NO_DISPLAY) { | if (m_display != EGL_NO_DISPLAY) { | ||||
| bindAPI(m_api); | bindAPI(m_api); | ||||
| Show All 10 Lines | if (m_context != EGL_NO_CONTEXT) { | ||||
| m_sharedContext = EGL_NO_CONTEXT; | m_sharedContext = EGL_NO_CONTEXT; | ||||
| EGL_CHK(::eglDestroyContext(m_display, m_context)); | EGL_CHK(::eglDestroyContext(m_display, m_context)); | ||||
| } | } | ||||
| } | } | ||||
| if (m_surface != EGL_NO_SURFACE) | if (m_surface != EGL_NO_SURFACE) | ||||
| EGL_CHK(::eglDestroySurface(m_display, m_surface)); | EGL_CHK(::eglDestroySurface(m_display, m_surface)); | ||||
| EGL_CHK(::eglTerminate(m_display)); | |||||
| } | } | ||||
| } | } | ||||
| 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; | ||||
| } | } | ||||
| Show All 36 Lines | GHOST_TSuccess GHOST_ContextEGL::activateDrawingContext() | ||||
| } | } | ||||
| } | } | ||||
| GHOST_TSuccess GHOST_ContextEGL::releaseDrawingContext() | GHOST_TSuccess GHOST_ContextEGL::releaseDrawingContext() | ||||
| { | { | ||||
| if (m_display) { | if (m_display) { | ||||
| bindAPI(m_api); | bindAPI(m_api); | ||||
| return EGL_CHK(::eglMakeCurrent(m_display, None, None, NULL)) ? GHOST_kSuccess : | return EGL_CHK(::eglMakeCurrent( | ||||
| GHOST_kFailure; | m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT) | ||||
| ) ? GHOST_kSuccess : GHOST_kFailure; | |||||
| } | } | ||||
| else { | else { | ||||
| return GHOST_kFailure; | return GHOST_kFailure; | ||||
| } | } | ||||
| } | } | ||||
| void GHOST_ContextEGL::initContextEGLEW() | void GHOST_ContextEGL::initContextEGLEW() | ||||
| { | { | ||||
| Show All 16 Lines | GHOST_TSuccess GHOST_ContextEGL::initializeDrawingContext() | ||||
| 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. | ||||
| // we have to set this function now, to obtain a EGLDisplay for initContextEGLEW | |||||
| eglGetDisplay = (PFNEGLGETDISPLAYPROC)eglGetProcAddress("eglGetDisplay"); | |||||
| if (eglGetDisplay==nullptr || | |||||
| !EGL_CHK((m_display = ::eglGetDisplay(m_nativeDisplay)) != EGL_NO_DISPLAY)) | |||||
Done Inline ActionsCheck that eglGetDisplay is not NULL before calling it. brecht: Check that `eglGetDisplay` is not `NULL` before calling it. | |||||
| return GHOST_kFailure; | |||||
| // set egl functions | |||||
| initContextEGLEW(); | |||||
| #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 == NULL) { | if (s_d3dcompiler == NULL) { | ||||
| s_d3dcompiler = LoadLibrary(D3DCOMPILER); | s_d3dcompiler = LoadLibrary(D3DCOMPILER); | ||||
| WIN32_CHK(s_d3dcompiler != NULL); | WIN32_CHK(s_d3dcompiler != NULL); | ||||
| if (s_d3dcompiler == NULL) { | if (s_d3dcompiler == NULL) { | ||||
| 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(); | ||||
| m_display = ::eglGetDisplay(m_nativeDisplay); | |||||
| if (!EGL_CHK(m_display != EGL_NO_DISPLAY)) | |||||
| return GHOST_kFailure; | |||||
| EGLint egl_major, egl_minor; | EGLint egl_major, egl_minor; | ||||
| if (!EGL_CHK(::eglInitialize(m_display, &egl_major, &egl_minor))) | if (!EGL_CHK(::eglInitialize(m_display, &egl_major, &egl_minor))) | ||||
| goto error; | goto error; | ||||
| fprintf(stderr, "EGL Version %d.%d\n", egl_major, egl_minor); | 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))) | if (!EGL_CHK(::eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT))) | ||||
| Show All 38 Lines | if (!((m_contextMajorVersion == 1) || (m_contextMajorVersion == 2 && EGLEW_VERSION_1_3) || | ||||
| "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); | ||||
| } | } | ||||
| } | } | ||||
| else { | |||||
| attrib_list.push_back(EGL_RENDERABLE_TYPE); | |||||
| attrib_list.push_back(EGL_OPENGL_BIT); | |||||
| } | |||||
| attrib_list.push_back(EGL_RED_SIZE); | attrib_list.push_back(EGL_RED_SIZE); | ||||
| attrib_list.push_back(8); | attrib_list.push_back(8); | ||||
| attrib_list.push_back(EGL_GREEN_SIZE); | attrib_list.push_back(EGL_GREEN_SIZE); | ||||
| attrib_list.push_back(8); | attrib_list.push_back(8); | ||||
| attrib_list.push_back(EGL_BLUE_SIZE); | attrib_list.push_back(EGL_BLUE_SIZE); | ||||
| attrib_list.push_back(8); | attrib_list.push_back(8); | ||||
| #ifdef GHOST_OPENGL_ALPHA | #ifdef GHOST_OPENGL_ALPHA | ||||
| attrib_list.push_back(EGL_ALPHA_SIZE); | attrib_list.push_back(EGL_ALPHA_SIZE); | ||||
| attrib_list.push_back(8); | attrib_list.push_back(8); | ||||
| #endif | #endif | ||||
| if (m_nativeWindow==0) { | |||||
| // off-screen surface | |||||
| attrib_list.push_back(EGL_SURFACE_TYPE); | |||||
| attrib_list.push_back(EGL_PBUFFER_BIT); | |||||
| } | |||||
| attrib_list.push_back(EGL_NONE); | attrib_list.push_back(EGL_NONE); | ||||
| EGLConfig config; | EGLConfig config; | ||||
| if (!EGL_CHK(::eglChooseConfig(m_display, &(attrib_list[0]), &config, 1, &num_config))) | if (!EGL_CHK(::eglChooseConfig(m_display, &(attrib_list[0]), &config, 1, &num_config))) | ||||
| goto error; | goto error; | ||||
| // A common error is to assume that ChooseConfig worked because it returned EGL_TRUE | // A common error is to assume that ChooseConfig worked because it returned EGL_TRUE | ||||
| if (num_config != 1) // num_config should be exactly 1 | if (num_config != 1) // num_config should be exactly 1 | ||||
| goto error; | goto error; | ||||
| if (m_nativeWindow!=0) { | |||||
| m_surface = ::eglCreateWindowSurface(m_display, config, m_nativeWindow, NULL); | m_surface = ::eglCreateWindowSurface(m_display, config, m_nativeWindow, NULL); | ||||
| } | |||||
| else { | |||||
| static const EGLint pb_attrib_list[] = { | |||||
| EGL_WIDTH, 1, | |||||
| EGL_HEIGHT, 1, | |||||
| EGL_NONE, | |||||
| }; | |||||
| m_surface = ::eglCreatePbufferSurface(m_display, 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 (EGLEW_VERSION_1_5 || EGLEW_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) { | ||||
| ▲ Show 20 Lines • Show All 125 Lines • Show Last 20 Lines | |||||
This is wrong because EGL_VERSION_1_2 is a #define that indicates if the header file contains EGL 1.2 functions. If it doesn't, there would be a compile error here.
EGLEW_VERSION_1_2 on the other hand checks at runtime that EGL 1.2 is supported, which is what is needed here.