//------------------------------------------------------------------------------ // eglWaitClient //------------------------------------------------------------------------------ EGLAPI EGLBoolean EGLAPIENTRY eglWaitClient(void) { eglplus_egl_glx_Current& current = eglplus_egl_CurrentRef(); if(!current.context) { return EGL_TRUE; } if(!current.draw_surface) { eglplus_egl_SetErrorCode(EGL_BAD_SURFACE); return EGL_FALSE; } if(!current.read_surface) { eglplus_egl_SetErrorCode(EGL_BAD_SURFACE); return EGL_FALSE; } // TODO finish error handling ::glXWaitGL(); return EGL_TRUE; }
//------------------------------------------------------------------------------ // eglWaitNative //------------------------------------------------------------------------------ EGLAPI EGLBoolean EGLAPIENTRY eglWaitNative(EGLint engine) { eglplus_egl_glx_Current& current = eglplus_egl_CurrentRef(); if(!current.context) { return EGL_TRUE; } if(engine != EGL_CORE_NATIVE_ENGINE) { eglplus_egl_SetErrorCode(EGL_BAD_PARAMETER); return EGL_FALSE; } if(!current.draw_surface) { eglplus_egl_SetErrorCode(EGL_BAD_SURFACE); return EGL_FALSE; } if(!current.read_surface) { eglplus_egl_SetErrorCode(EGL_BAD_SURFACE); return EGL_FALSE; } // TODO finish error handling ::glXWaitX(); return EGL_TRUE; }
//------------------------------------------------------------------------------ // eglDestroyContext //------------------------------------------------------------------------------ EGLAPI EGLBoolean EGLAPIENTRY eglDestroyContext( EGLDisplay display, EGLContext context ) { if(!eglplus_egl_valid_display(display)) { eglplus_egl_SetErrorCode(EGL_BAD_DISPLAY); return EGL_FALSE; } if(!display->initialized()) { eglplus_egl_SetErrorCode(EGL_NOT_INITIALIZED); return EGL_FALSE; } if(!eglplus_egl_valid_context(context)) { eglplus_egl_SetErrorCode(EGL_BAD_CONTEXT); return EGL_FALSE; } context->_cleanup(display->_x_open_display); delete context; }
//------------------------------------------------------------------------------ // eglGetConfigs //------------------------------------------------------------------------------ EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigs( EGLDisplay display, EGLConfig * configs, EGLint config_size, EGLint * num_configs ) { if(!eglplus_egl_valid_display(display)) { eglplus_egl_SetErrorCode(EGL_BAD_DISPLAY); return EGL_FALSE; } if(!display->initialized()) { eglplus_egl_SetErrorCode(EGL_NOT_INITIALIZED); return EGL_FALSE; } if(!num_configs) { eglplus_egl_SetErrorCode(EGL_BAD_PARAMETER); return EGL_FALSE; } int num_glx_configs = 0; ::GLXFBConfig * glx_configs = ::glXGetFBConfigs( display->_x_open_display, DefaultScreen(display->_x_open_display), &num_glx_configs ); if(configs) { int n = (num_glx_configs < int(config_size))? num_glx_configs: int(config_size); for(int i=0; i<n; ++i) { configs[i]._glx_fb_config = static_cast<void*>(glx_configs[i]); } *num_configs = n>=0?n:0; } else *num_configs = EGLint(num_glx_configs); return EGL_TRUE; }
//------------------------------------------------------------------------------ // eglGetCurrentSurface //------------------------------------------------------------------------------ EGLAPI EGLSurface EGLAPIENTRY eglGetCurrentSurface(EGLint which) { switch(which) { case EGL_DRAW: { return eglplus_egl_CurrentRef().draw_surface; } case EGL_READ: { return eglplus_egl_CurrentRef().read_surface; } default:; } eglplus_egl_SetErrorCode(EGL_BAD_PARAMETER); return EGL_NO_SURFACE; }
//------------------------------------------------------------------------------ // eglCreateContext //------------------------------------------------------------------------------ EGLAPI EGLContext EGLAPIENTRY eglCreateContext( EGLDisplay display, EGLConfig config, EGLContext egl_share_context, const EGLint *egl_attrib_list ) { if(!eglplus_egl_valid_display(display)) { eglplus_egl_SetErrorCode(EGL_BAD_DISPLAY); return EGL_NO_CONTEXT; } if(!display->initialized()) { eglplus_egl_SetErrorCode(EGL_NOT_INITIALIZED); return EGL_NO_CONTEXT; } if(!config._glx_fb_config) { eglplus_egl_SetErrorCode(EGL_BAD_CONFIG); return EGL_NO_CONTEXT; } if(eglplus_egl_CurrentAPI != EGL_OPENGL_API) { eglplus_egl_SetErrorCode(EGL_BAD_MATCH); return EGL_NO_CONTEXT; } if(eglplus_egl_glXCreateContextAttribsARB == nullptr) { eglplus_egl_glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc) glXGetProcAddressARB((const unsigned char*)"glXCreateContextAttribsARB"); } if(eglplus_egl_glXCreateContextAttribsARB == nullptr) { eglplus_egl_SetErrorCode(EGL_BAD_DISPLAY); return EGL_NO_CONTEXT; } ::GLXContext glx_share_context = ::GLXContext(0); if(egl_share_context != EGL_NO_CONTEXT) { if(eglplus_egl_valid_context(egl_share_context)) { glx_share_context = egl_share_context->_glx_context; } else { eglplus_egl_SetErrorCode(EGL_BAD_CONFIG); return EGL_NO_CONTEXT; } } EGLint empty_list = EGL_NONE; if(!egl_attrib_list) { egl_attrib_list = &empty_list; } int glx_attrib_count = 0; if(*egl_attrib_list != EGL_NONE) { const EGLint* tmp_attrib_list = egl_attrib_list; while(*tmp_attrib_list != EGL_NONE) { bool bad_attrib = false; switch(*tmp_attrib_list++) { case 0x3098: //EGL_CONTEXT_MAJOR_VERSION_KHR case 0x30FB: //EGL_CONTEXT_MINOR_VERSION_KHR break; case 0x30FC: //EGL_CONTEXT_FLAGS_KHR { if((*tmp_attrib_list & ~0x07) != 0) { bad_attrib = true; } break; } case 0x31BD: //EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR { switch(*tmp_attrib_list) { case 0x31BE: case 0x31BF: break; default: bad_attrib = true; } break; } case 0x30FD: //EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR { if((*tmp_attrib_list & ~0x03) != 0) { bad_attrib = true; } break; } default: bad_attrib = true; } if(bad_attrib) { eglplus_egl_SetErrorCode(EGL_BAD_ATTRIBUTE); return EGL_NO_CONTEXT; } ++tmp_attrib_list; glx_attrib_count += 2; } } std::vector<int> glx_attrib_list(glx_attrib_count+1); glx_attrib_count = 0; if(*egl_attrib_list != EGL_NONE) { const EGLint* tmp_attrib_list = egl_attrib_list; while(*tmp_attrib_list != EGL_NONE) { switch(*tmp_attrib_list++) { case 0x3098: //EGL_CONTEXT_MAJOR_VERSION_KHR { glx_attrib_list[glx_attrib_count++] = //GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091; glx_attrib_list[glx_attrib_count++] = int(*tmp_attrib_list++); break; } case 0x30FB: //EGL_CONTEXT_MINOR_VERSION_KHR { glx_attrib_list[glx_attrib_count++] = //GLX_CONTEXT_MINOR_VERSION_ARB 0x2092; glx_attrib_list[glx_attrib_count++] = int(*tmp_attrib_list++); break; } case 0x30FC: //EGL_CONTEXT_FLAGS_KHR { glx_attrib_list[glx_attrib_count++] = //GLX_CONTEXT_FLAGS_ARB 0x2094; EGLint egl_flags = *tmp_attrib_list++; int glx_flags = 0; // EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR if((egl_flags & 0x00000001) == 0x00000001) glx_flags |= 0x0001; // EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR if((egl_flags & 0x00000002) == 0x00000002) glx_flags |= 0x0002; // EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR // TODO: currently ignored glx_attrib_list[glx_attrib_count++] = glx_flags; break; } case 0x31BD: //EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR { // TODO: currently ignored break; } case 0x30FD: //EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR { glx_attrib_list[glx_attrib_count++] = //GLX_CONTEXT_PROFILE_MASK_ARB 0x9126; EGLint egl_flags = *tmp_attrib_list++; int glx_flags = 0; // EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR if((egl_flags & 0x00000001) == 0x00000001) glx_flags |= 0x0001; // EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR if((egl_flags & 0x00000002) == 0x00000002) glx_flags |= 0x0002; glx_attrib_list[glx_attrib_count++] = glx_flags; break; } default:; } } } glx_attrib_list[glx_attrib_count] = None; ::GLXContext context = eglplus_egl_glXCreateContextAttribsARB( display->_x_open_display, static_cast< ::GLXFBConfig>(config._glx_fb_config), glx_share_context, True, // direct rendering glx_attrib_list.data() ); if(context == ::GLXContext(0)) { eglplus_egl_SetErrorCode(EGL_BAD_ALLOC); return EGL_NO_CONTEXT; } ::XSync(display->_x_open_display, False); int empty_surf_attr[] = { GLX_PBUFFER_WIDTH, 0, GLX_PBUFFER_HEIGHT, 0, GLX_PRESERVED_CONTENTS, False, None }; ::GLXPbuffer empty_surf = ::glXCreatePbuffer( display->_x_open_display, static_cast< ::GLXFBConfig>(config._glx_fb_config), empty_surf_attr ); try { return new eglplus_egl_glx_ContextImpl(context, empty_surf); } catch(...) { eglplus_egl_SetErrorCode(EGL_BAD_ALLOC); return EGL_NO_CONTEXT; } }
//------------------------------------------------------------------------------ // eglQueryContext //------------------------------------------------------------------------------ EGLAPI EGLBoolean EGLAPIENTRY eglQueryContext( EGLDisplay display, EGLContext context, EGLint egl_attribute, EGLint *egl_attrib_value ) { if(!eglplus_egl_valid_display(display)) { eglplus_egl_SetErrorCode(EGL_BAD_DISPLAY); return EGL_FALSE; } if(!display->initialized()) { eglplus_egl_SetErrorCode(EGL_NOT_INITIALIZED); return EGL_FALSE; } if(!eglplus_egl_valid_context(context)) { eglplus_egl_SetErrorCode(EGL_BAD_CONTEXT); return EGL_FALSE; } int glx_attribute = 0; switch(egl_attribute) { case EGL_CONTEXT_CLIENT_TYPE: { if(egl_attrib_value) *egl_attrib_value = EGL_OPENGL_BIT; return EGL_TRUE; } case EGL_CONTEXT_CLIENT_VERSION: { if(egl_attrib_value) *egl_attrib_value = 3; return EGL_TRUE; } case EGL_RENDER_BUFFER: { //TODO if(egl_attrib_value) *egl_attrib_value = EGL_BACK_BUFFER; return EGL_TRUE; } case EGL_CONFIG_ID: { glx_attribute = GLX_FBCONFIG_ID; break; } default: { eglplus_egl_SetErrorCode(EGL_BAD_ATTRIBUTE); return EGL_FALSE; } } int glx_attrib_value = 0; if(glXQueryContext( display->_x_open_display, context->_glx_context, glx_attribute, &glx_attrib_value ) != 0) { return EGL_FALSE; } switch(egl_attribute) { default: { if(egl_attrib_value) *egl_attrib_value = glx_attrib_value; } } return EGL_TRUE; }
//------------------------------------------------------------------------------ // eglMakeCurrent //------------------------------------------------------------------------------ EGLAPI EGLBoolean EGLAPIENTRY eglMakeCurrent( EGLDisplay display, EGLSurface egl_draw, EGLSurface egl_read, EGLContext context ) { if(!eglplus_egl_valid_display(display)) { eglplus_egl_SetErrorCode(EGL_BAD_DISPLAY); return EGL_FALSE; } ::GLXContext glx_context = ::GLXContext(0); ::GLXDrawable glx_draw = ::GLXDrawable(0); ::GLXDrawable glx_read = ::GLXDrawable(0); if(context != EGL_NO_CONTEXT) { if(!eglplus_egl_valid_context(context)) { eglplus_egl_SetErrorCode(EGL_BAD_CONTEXT); return EGL_FALSE; } if((egl_draw == EGL_NO_SURFACE) != (egl_read == EGL_NO_SURFACE)) { eglplus_egl_SetErrorCode(EGL_BAD_MATCH); return EGL_FALSE; } if(egl_draw != EGL_NO_SURFACE) { if(!eglplus_egl_valid_surface(egl_draw)) { eglplus_egl_SetErrorCode(EGL_BAD_SURFACE); return EGL_FALSE; } glx_draw = egl_draw->_glx_drawable; } else if(context->_glx_empty_surf) { // KHR_surfaceless_context glx_draw = context->_glx_empty_surf; } else { eglplus_egl_SetErrorCode(EGL_BAD_SURFACE); return EGL_FALSE; } if(egl_read != EGL_NO_SURFACE) { if(!eglplus_egl_valid_surface(egl_read)) { eglplus_egl_SetErrorCode(EGL_BAD_SURFACE); return EGL_FALSE; } glx_read = egl_read->_glx_drawable; } else if(context->_glx_empty_surf) { // KHR_surfaceless_context glx_read = context->_glx_empty_surf; } else { eglplus_egl_SetErrorCode(EGL_BAD_SURFACE); return EGL_FALSE; } if(!display->initialized()) { eglplus_egl_SetErrorCode(EGL_NOT_INITIALIZED); return EGL_FALSE; } glx_context = context->_glx_context; } else { if(egl_draw != EGL_NO_SURFACE) { eglplus_egl_SetErrorCode(EGL_BAD_MATCH); return EGL_FALSE; } if(egl_read != EGL_NO_SURFACE) { eglplus_egl_SetErrorCode(EGL_BAD_MATCH); return EGL_FALSE; } } if(::glXMakeContextCurrent( display->_x_open_display, glx_draw, glx_read, glx_context ) != True) { return EGL_FALSE; } eglplus_egl_glx_Current& current = eglplus_egl_CurrentRef(); current.display = display; current.draw_surface = egl_draw; current.read_surface = egl_read; current.context = context; return EGL_TRUE; }
//------------------------------------------------------------------------------ // eglGetConfigAttrib //------------------------------------------------------------------------------ EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigAttrib( EGLDisplay display, EGLConfig config, EGLint egl_attrib_name, EGLint *egl_attrib_value ) { if(!eglplus_egl_valid_display(display)) { eglplus_egl_SetErrorCode(EGL_BAD_DISPLAY); return EGL_FALSE; } if(!display->initialized()) { eglplus_egl_SetErrorCode(EGL_NOT_INITIALIZED); return EGL_FALSE; } if(!egl_attrib_value) { eglplus_egl_SetErrorCode(EGL_BAD_PARAMETER); return EGL_FALSE; } int glx_attrib_name; switch(egl_attrib_name) { case EGL_COLOR_BUFFER_TYPE: { *egl_attrib_value = EGL_RGB_BUFFER; // TODO: are luminance buffers supported by GLX? return EGL_TRUE; } case EGL_RENDERABLE_TYPE: case EGL_CONFORMANT: { *egl_attrib_value = EGL_OPENGL_BIT; //TODO | EGL_OPENGL_ES3_BIT_KHR; return EGL_TRUE; } case EGL_SAMPLES: case EGL_SAMPLE_BUFFERS: case EGL_LUMINANCE_SIZE: case EGL_ALPHA_MASK_SIZE: case EGL_MIN_SWAP_INTERVAL: case EGL_MAX_SWAP_INTERVAL: { *egl_attrib_value = 0; return EGL_TRUE; } default: { if(!eglplus_egl_glx_TranslateAttribName( egl_attrib_name, glx_attrib_name )) { eglplus_egl_SetErrorCode(EGL_BAD_ATTRIBUTE); return EGL_FALSE; } } } int glx_attrib_value = 0; int glx_result = ::glXGetFBConfigAttrib( display->_x_open_display, static_cast< ::GLXFBConfig>(config._glx_fb_config), glx_attrib_name, &glx_attrib_value ); if(glx_result == Success) { eglplus_egl_glx_TranslateAttribBack( egl_attrib_name, *egl_attrib_value, glx_attrib_value ); return EGL_TRUE; } else if(glx_result == GLX_BAD_ATTRIBUTE) { eglplus_egl_SetErrorCode(EGL_BAD_ATTRIBUTE); } else { eglplus_egl_SetErrorCode(EGL_BAD_DISPLAY); } return EGL_FALSE; }
//------------------------------------------------------------------------------ // eglChooseConfig //------------------------------------------------------------------------------ EGLAPI EGLBoolean EGLAPIENTRY eglChooseConfig( EGLDisplay display, const EGLint *egl_attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_configs ) { if(!eglplus_egl_valid_display(display)) { eglplus_egl_SetErrorCode(EGL_BAD_DISPLAY); return EGL_FALSE; } if(!display->initialized()) { eglplus_egl_SetErrorCode(EGL_NOT_INITIALIZED); return EGL_FALSE; } EGLint empty_list = EGL_NONE; if(!egl_attrib_list) { egl_attrib_list = &empty_list; } std::vector<int> glx_attrib_list(1); bool unsupported_config = false; if(*egl_attrib_list != EGL_NONE) { unsigned attr_count = 0; const EGLint *egl_attrib = egl_attrib_list; while(*egl_attrib != EGL_NONE) { switch(*(++egl_attrib)) { case EGL_NONE: { eglplus_egl_SetErrorCode(EGL_BAD_ATTRIBUTE); return EGL_FALSE; } case EGL_SURFACE_TYPE: case EGL_COLOR_BUFFER_TYPE: { attr_count += 2; break; } default: ++attr_count; } ++egl_attrib; } glx_attrib_list.resize(2*attr_count+1); attr_count = 0; egl_attrib = egl_attrib_list; while(*egl_attrib != EGL_NONE) { EGLint egl_attrib_name = *(egl_attrib++); EGLint egl_attrib_value= *(egl_attrib++); int glx_attrib_name, glx_attrib_value; bool special_attrib = true; bool unsupported_attrib = false; switch(egl_attrib_name) { case EGL_MIN_SWAP_INTERVAL: case EGL_MAX_SWAP_INTERVAL: { // just skip this break; } case EGL_SAMPLES: case EGL_SAMPLE_BUFFERS: case EGL_ALPHA_MASK_SIZE: case EGL_LUMINANCE_SIZE: { // must be zero (or don't care) if(egl_attrib_value != 0) unsupported_attrib = true; break; } case EGL_RENDERABLE_TYPE: { if(egl_attrib_value != EGL_OPENGL_BIT) unsupported_attrib = true; break; } case EGL_SURFACE_TYPE: { bool doublebuffer = (egl_attrib_value & EGL_WINDOW_BIT)|| (egl_attrib_value & EGL_PBUFFER_BIT); glx_attrib_list[attr_count++] = GLX_DOUBLEBUFFER; glx_attrib_list[attr_count++] = doublebuffer?True:False; break; } case EGL_COLOR_BUFFER_TYPE: { if(egl_attrib_value == EGL_RGB_BUFFER) { glx_attrib_list[attr_count++] = GLX_RENDER_TYPE; glx_attrib_list[attr_count++] = GLX_RGBA_BIT; glx_attrib_list[attr_count++] = GLX_X_VISUAL_TYPE; glx_attrib_list[attr_count++] = GLX_TRUE_COLOR; } else unsupported_attrib = true; break; } default: special_attrib = false; } if(special_attrib) { if(unsupported_attrib) { if(egl_attrib_value != EGL_DONT_CARE) { unsupported_config = true; break; } } } else if(eglplus_egl_glx_TranslateAttrib( egl_attrib_name, egl_attrib_value, glx_attrib_name, glx_attrib_value )) { glx_attrib_list[attr_count++] = glx_attrib_name; glx_attrib_list[attr_count++] = glx_attrib_value; } else { eglplus_egl_SetErrorCode(EGL_BAD_ATTRIBUTE); return EGL_FALSE; } } glx_attrib_list.resize(2*attr_count+1); } glx_attrib_list.back() = None; if(unsupported_config) { *num_configs = 0; return EGL_TRUE; } int num_glx_configs = 0; ::GLXFBConfig * glx_configs = ::glXChooseFBConfig( display->_x_open_display, DefaultScreen(display->_x_open_display), glx_attrib_list.data(), &num_glx_configs ); if(configs) { int n = (num_glx_configs < int(config_size))? num_glx_configs: int(config_size); for(int i=0; i<n; ++i) { configs[i]._glx_fb_config = static_cast<void*>(glx_configs[i]); } *num_configs = n>=0?n:0; } else *num_configs = EGLint(num_glx_configs); return EGL_TRUE; }