/****************************************************************************** @File KEGL/PVRShellAPI.cpp @Title KEGL/PVRShellAPI @Version @Copyright Copyright (c) Imagination Technologies Limited. @Platform Independent @Description Makes programming for 3D APIs easier by wrapping surface initialization, Texture allocation and other functions for use by a demo. ******************************************************************************/ #include #include #include #include #include "PVRShell.h" #include "PVRShellAPI.h" #include "PVRShellOS.h" #include "PVRShellImpl.h" // No Doxygen for CPP files, due to documentation duplication /// @cond NO_DOXYGEN #ifndef EGL_CONTEXT_LOST_IMG /*! Extended error code EGL_CONTEXT_LOST_IMG generated when power management event has occurred. */ #define EGL_CONTEXT_LOST_IMG 0x300E #endif #ifndef EGL_CONTEXT_PRIORITY_LEVEL_IMG /*! An extensions added to the list of attributes for the context to give it a priority hint */ #define EGL_CONTEXT_PRIORITY_LEVEL_IMG 0x3100 /*! Request the context is created with high priority */ #define EGL_CONTEXT_PRIORITY_HIGH_IMG 0x3101 /*! Request the context is created with medium priority */ #define EGL_CONTEXT_PRIORITY_MEDIUM_IMG 0x3102 /*! Request the context is created with low priority */ #define EGL_CONTEXT_PRIORITY_LOW_IMG 0x3103 #endif /***************************************************************************** Declarations *****************************************************************************/ static bool PVRShellIsExtensionSupported(EGLDisplay dpy, const char *extension); #if defined GL_ES_VERSION_2_0 && !defined EGL_VERSION_1_3 #error OpenGL ES 2 requires egl.h version 1.3 or higher #endif /**************************************************************************** ** Class: PVRShellInitAPI ****************************************************************************/ /***************************************************************************** * Function Name : ActivatePreferences * Description : Activates the user set preferences (like v-sync) *****************************************************************************/ void PVRShellInit::ApiActivatePreferences() { #ifdef EGL_VERSION_1_1 eglSwapInterval(m_EGLDisplay, m_pShell->m_pShellData->nSwapInterval); #endif } /***************************************************************************** * Function Name : ApiInitAPI * Returns : true for success * Description : Initialise the 3D API *****************************************************************************/ bool PVRShellInit::ApiInitAPI() { int bDone; m_NDT = (EGLNativeDisplayType)OsGetNativeDisplayType(); m_NPT = (EGLNativePixmapType) OsGetNativePixmapType(); m_NWT = (EGLNativeWindowType) OsGetNativeWindowType(); m_EGLContext = 0; do { bDone = true; m_EGLDisplay = eglGetDisplay(m_NDT); if(m_EGLDisplay == EGL_NO_DISPLAY) { #if defined(BUILD_OGLES2) || defined(BUILD_OGLES3) m_EGLDisplay = eglGetDisplay((EGLNativeDisplayType)EGL_DEFAULT_DISPLAY); #else m_EGLDisplay = eglGetDisplay((NativeDisplayType)EGL_DEFAULT_DISPLAY); #endif } if(!eglInitialize(m_EGLDisplay, &m_MajorVersion, &m_MinorVersion)) { m_pShell->PVRShellSet(prefExitMessage, "PVRShell: Unable to initialise EGL\n"); m_pShell->PVRShellOutputDebug("PVRShell: EGL Error (%s)\n", StringFrom_eglGetError()); return false; } m_pShell->PVRShellOutputDebug("PVRShell: EGL %d.%d initialized\n", m_MajorVersion, m_MinorVersion); // Check Extension availability after EGL initialization if (m_MajorVersion > 1 || (m_MajorVersion == 1 && m_MinorVersion >= 1)) { m_bPowerManagementSupported = true; } else { m_bPowerManagementSupported = PVRShellIsExtensionSupported(m_EGLDisplay,"EGL_IMG_power_management"); } do { #if defined(BUILD_OGL) if(!eglBindAPI(EGL_OPENGL_API)) { m_pShell->PVRShellSet(prefExitMessage, "PVRShell: Failed to bind OpenGL API\n"); return false; } #else #if defined EGL_VERSION_1_3 && defined GL_ES_VERSION_2_0 if(!eglBindAPI(EGL_OPENGL_ES_API)) { m_pShell->PVRShellSet(prefExitMessage, "PVRShell: Failed to bind OpenGL ES API\n"); return false; } #endif #endif // Find an EGL config m_EGLConfig = SelectEGLConfiguration(m_pShell->m_pShellData); eglGetConfigAttrib(m_EGLDisplay, m_EGLConfig, EGL_CONFIG_ID, &m_iConfig); // Destroy the context if we already created one if (m_EGLContext) { eglDestroyContext(m_EGLDisplay, m_EGLContext); } // Attempt to create a context EGLint ai32ContextAttribs[48]; int i = 0; #if defined(BUILD_OGLES3) ai32ContextAttribs[i++] = EGL_CONTEXT_CLIENT_VERSION; ai32ContextAttribs[i++] = 3; #else #if defined(EGL_VERSION_1_3) && defined(GL_ES_VERSION_2_0) ai32ContextAttribs[i++] = EGL_CONTEXT_CLIENT_VERSION; ai32ContextAttribs[i++] = 2; #endif #endif #if defined(BUILD_OGL) //Attempt to create an OpenGL 3.2 context. if (PVRShellIsExtensionSupported(m_EGLDisplay, "EGL_KHR_create_context")) { ai32ContextAttribs[i++] = EGL_CONTEXT_MAJOR_VERSION_KHR; ai32ContextAttribs[i++] = 3; ai32ContextAttribs[i++] = EGL_CONTEXT_MINOR_VERSION_KHR; ai32ContextAttribs[i++] = 2; ai32ContextAttribs[i++] = EGL_CONTEXT_FLAGS_KHR; ai32ContextAttribs[i++] = EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR; ai32ContextAttribs[i++] = EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR; ai32ContextAttribs[i++] = EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR; } #endif #if defined(BUILD_OGLES) || defined(BUILD_OGLES2) || defined(BUILD_OGLES3) if(PVRShellIsExtensionSupported(m_EGLDisplay,"EGL_IMG_context_priority")) { ai32ContextAttribs[i++] = EGL_CONTEXT_PRIORITY_LEVEL_IMG; switch(m_pShell->PVRShellGet(prefPriority)) { case 0: ai32ContextAttribs[i++] = EGL_CONTEXT_PRIORITY_LOW_IMG; break; case 1: ai32ContextAttribs[i++] = EGL_CONTEXT_PRIORITY_MEDIUM_IMG; break; default:ai32ContextAttribs[i++] = EGL_CONTEXT_PRIORITY_HIGH_IMG; break; } } #endif ai32ContextAttribs[i] = EGL_NONE; if (m_EGLContext == EGL_NO_CONTEXT) { m_EGLContext = eglCreateContext(m_EGLDisplay, m_EGLConfig, NULL, ai32ContextAttribs); } if(m_EGLContext == EGL_NO_CONTEXT) { if(m_iRequestedConfig > 0) { // We failed to create a context m_pShell->PVRShellSet(prefExitMessage, "PVRShell: Unable to create a context\n"); return false; } else if(m_pShell->m_pShellData->bNeedPbuffer) { // Disable P-buffer and try again m_pShell->m_pShellData->bNeedPbuffer = false; } else if(m_pShell->m_pShellData->bNeedStencilBuffer) { // Disable Stencil Buffer and try again m_pShell->m_pShellData->bNeedStencilBuffer = false; } else if(m_pShell->m_pShellData->nAASamples > 0) { // Still failing, reduce the AA samples and try again --m_pShell->m_pShellData->nAASamples; } else { m_pShell->PVRShellSet(prefExitMessage, "PVRShell: Unable to create a context\n"); return false; } } } while(m_EGLContext == EGL_NO_CONTEXT); #if defined(__QNXNTO__) int format = SCREEN_FORMAT_RGBX8888; if(screen_set_window_property_iv((_screen_window*) m_NWT, SCREEN_PROPERTY_FORMAT, &format)) { m_pShell->PVRShellSet(prefExitMessage, "PVRShell: Failed to set window property SCREEN_PROPERTY_FORMAT\n"); return false; } #if defined(BUILD_OGLES2) int usage = SCREEN_USAGE_OPENGL_ES2; #else #if defined(BUILD_OGLES) int usage = SCREEN_USAGE_OPENGL_ES1; #endif #endif if(screen_set_window_property_iv((_screen_window*) m_NWT, SCREEN_PROPERTY_USAGE, &usage)) { m_pShell->PVRShellSet(prefExitMessage, "PVRShell: Failed to set window property SCREEN_PROPERTY_USAGE\n"); return false; } if(screen_create_window_buffers((_screen_window*) m_NWT, 2)) { m_pShell->PVRShellSet(prefExitMessage, "PVRShell: Failed to create window buffers\n"); return false; } #endif EGLint attrib_list[16]; int i = 0; #if defined(EGL_VERSION_1_2) if(m_pShell->m_pShellData->bNeedAlphaFormatPre) // The default is EGL_ALPHA_FORMAT_NONPRE { attrib_list[i++] = EGL_ALPHA_FORMAT; attrib_list[i++] = EGL_ALPHA_FORMAT_PRE; } #endif // Terminate the attribute list with EGL_NONE attrib_list[i] = EGL_NONE; if(m_pShell->m_pShellData->bNeedPixmap) { m_pShell->PVRShellOutputDebug("InitAPI() Using pixmaps, about to create egl surface\n"); m_EGLWindow = eglCreatePixmapSurface(m_EGLDisplay, m_EGLConfig, m_NPT, attrib_list); } else { #if defined(ANDROID) EGLint visualID; eglGetConfigAttrib(m_EGLDisplay, m_EGLConfig, EGL_NATIVE_VISUAL_ID, &visualID); // Change the format of our window to match our config ANativeWindow_setBuffersGeometry(m_NWT, 0, 0, visualID); #endif m_EGLWindow = eglCreateWindowSurface(m_EGLDisplay, m_EGLConfig, m_NWT, attrib_list); // If we have failed to create a surface then try using Null if(m_EGLWindow == EGL_NO_SURFACE) { m_EGLWindow = eglCreateWindowSurface(m_EGLDisplay, m_EGLConfig, NULL, attrib_list); } } if (m_EGLWindow == EGL_NO_SURFACE) { m_pShell->PVRShellSet(prefExitMessage, "PVRShell: Unable to create surface\n"); return false; } if (!eglMakeCurrent(m_EGLDisplay, m_EGLWindow, m_EGLWindow, m_EGLContext)) { #ifdef EGL_VERSION_1_3 if((eglGetError() == EGL_CONTEXT_LOST)) #else if((eglGetError() == EGL_CONTEXT_LOST_IMG) && m_bPowerManagementSupported) #endif { bDone = false; } else { m_pShell->PVRShellSet(prefExitMessage, "PVRShell: Unable to make context current\n"); return false; } } } while(!bDone); /* Get correct screen width and height and save them into m_pShell->m_pShellData->nShellDimX and m_pShell->m_pShellData->nShellDimY */ eglQuerySurface(m_EGLDisplay, m_EGLWindow, EGL_WIDTH, (EGLint*)&m_pShell->m_pShellData->nShellDimX ); eglQuerySurface(m_EGLDisplay, m_EGLWindow, EGL_HEIGHT, (EGLint*)&m_pShell->m_pShellData->nShellDimY ); #if defined(ANDROID) glViewport(0, 0, m_pShell->m_pShellData->nShellDimX, m_pShell->m_pShellData->nShellDimY); #endif /* Done - activate requested features */ #if defined(BUILD_OGLES) || defined(BUILD_OGLES2) //Get the discardframebufferEXT function. { //Get the gl extension string const char* strExtensions = (const char*)glGetString(GL_EXTENSIONS); //Get the length of the string we're searching for const size_t strLength = strlen("GL_EXT_discard_framebuffer"); //Get the string position const char* position = strstr(strExtensions,"GL_EXT_discard_framebuffer"); //Loop through until we find the actual extension, avoiding substrings. while (position!=NULL && position[strLength]!='\0' && position[strLength]!=' ') { position = strstr(position+strLength,"GL_EXT_discard_framebuffer"); } //Initialise the extension if it's found. if (position != NULL) { glDiscardFramebufferEXT = (PFNGLDISCARDFRAMEBUFFEREXTPROC)eglGetProcAddress("glDiscardFramebufferEXT"); } else { glDiscardFramebufferEXT = NULL; } } #endif ApiActivatePreferences(); return true; } /*!*********************************************************************** @Function OutputAPIInfo @description When prefOutputInfo is set to true this function outputs various pieces of API dependent information via PVRShellOutputDebug. *************************************************************************/ void PVRShellInit::OutputAPIInfo() { // Output API dependent information if(m_pShell->PVRShellGet(prefOutputInfo)) { EGLint i32Values[5]; m_pShell->PVRShellOutputDebug("\n"); m_pShell->PVRShellOutputDebug("GL:\n"); m_pShell->PVRShellOutputDebug(" Vendor: %s\n", (char*) glGetString(GL_VENDOR)); m_pShell->PVRShellOutputDebug(" Renderer: %s\n", (char*) glGetString(GL_RENDERER)); m_pShell->PVRShellOutputDebug(" Version: %s\n", (char*) glGetString(GL_VERSION)); m_pShell->PVRShellOutputDebug(" Extensions: "); #if defined(BUILD_OGL) //Get the glGetString process. typedef const GLubyte* (KHRONOS_APIENTRY * PFNGLGETSTRINGIPROC)(GLenum name, GLuint index); PFNGLGETSTRINGIPROC glGetStringi = (PFNGLGETSTRINGIPROC)eglGetProcAddress("glGetStringi"); //If we've successfully got the new way to query the string, then go ahead and use this. if (glGetStringi) { #ifndef GL_NUM_EXTENSIONS #define GL_NUM_EXTENSIONS 0x821D #endif GLint numExtensions; glGetIntegerv(GL_NUM_EXTENSIONS,&numExtensions); for (GLint i=0; iPVRShellOutputDebug((const char*)glGetStringi(GL_EXTENSIONS,i)); m_pShell->PVRShellOutputDebug(" "); } } #else m_pShell->PVRShellOutputDebug("%s\n", (char*) glGetString(GL_EXTENSIONS)); #endif m_pShell->PVRShellOutputDebug("\n"); m_pShell->PVRShellOutputDebug("\n"); m_pShell->PVRShellOutputDebug("EGL:\n"); m_pShell->PVRShellOutputDebug(" Vendor: %s\n" , (char*) eglQueryString(m_EGLDisplay, EGL_VENDOR)); m_pShell->PVRShellOutputDebug(" Version: %s\n" , (char*) eglQueryString(m_EGLDisplay, EGL_VERSION)); m_pShell->PVRShellOutputDebug(" Extensions: %s\n" , (char*) eglQueryString(m_EGLDisplay, EGL_EXTENSIONS)); if(eglQueryContext(m_EGLDisplay, m_EGLContext, EGL_CONTEXT_PRIORITY_LEVEL_IMG, &i32Values[0])) { switch(i32Values[0]) { case EGL_CONTEXT_PRIORITY_HIGH_IMG: m_pShell->PVRShellOutputDebug(" Context priority: High\n"); break; case EGL_CONTEXT_PRIORITY_MEDIUM_IMG: m_pShell->PVRShellOutputDebug(" Context priority: Medium\n");break; case EGL_CONTEXT_PRIORITY_LOW_IMG: m_pShell->PVRShellOutputDebug(" Context priority: Low\n"); break; default: m_pShell->PVRShellOutputDebug(" Context priority: Unrecognised.\n"); break; } } else { eglGetError(); // Clear error m_pShell->PVRShellOutputDebug(" Context priority: Unsupported\n"); } #ifdef EGL_VERSION_1_2 m_pShell->PVRShellOutputDebug(" Client APIs: %s\n" , (char*) eglQueryString(m_EGLDisplay, EGL_CLIENT_APIS)); #endif m_pShell->PVRShellOutputDebug("\n"); m_pShell->PVRShellOutputDebug("Window Width: %i\n" , m_pShell->PVRShellGet(prefWidth)); m_pShell->PVRShellOutputDebug("Window Height: %i\n" , m_pShell->PVRShellGet(prefHeight)); m_pShell->PVRShellOutputDebug("Is Rotated: %s\n", m_pShell->PVRShellGet(prefIsRotated) ? "Yes" : "No"); m_pShell->PVRShellOutputDebug("\n"); // EGLSurface details m_pShell->PVRShellOutputDebug("EGL Surface:\n"); eglGetConfigAttrib(m_EGLDisplay, m_EGLConfig, EGL_CONFIG_ID , &i32Values[0]); m_pShell->PVRShellOutputDebug(" Config ID: %i\n", i32Values[0]); // Colour buffer eglGetConfigAttrib(m_EGLDisplay, m_EGLConfig, EGL_BUFFER_SIZE , &i32Values[0]); eglGetConfigAttrib(m_EGLDisplay, m_EGLConfig, EGL_RED_SIZE , &i32Values[1]); eglGetConfigAttrib(m_EGLDisplay, m_EGLConfig, EGL_GREEN_SIZE , &i32Values[2]); eglGetConfigAttrib(m_EGLDisplay, m_EGLConfig, EGL_BLUE_SIZE , &i32Values[3]); eglGetConfigAttrib(m_EGLDisplay, m_EGLConfig, EGL_ALPHA_SIZE , &i32Values[4]); m_pShell->PVRShellOutputDebug(" Colour Buffer: %i bits (R%i G%i B%i A%i)\n", i32Values[0],i32Values[1],i32Values[2],i32Values[3],i32Values[4]); // Depth buffer eglGetConfigAttrib(m_EGLDisplay, m_EGLConfig, EGL_DEPTH_SIZE , &i32Values[0]); m_pShell->PVRShellOutputDebug(" Depth Buffer: %i bits\n", i32Values[0]); // Stencil Buffer eglGetConfigAttrib(m_EGLDisplay, m_EGLConfig, EGL_STENCIL_SIZE , &i32Values[0]); m_pShell->PVRShellOutputDebug(" Stencil Buffer: %i bits\n", i32Values[0]); // EGL surface bits support eglGetConfigAttrib(m_EGLDisplay, m_EGLConfig, EGL_SURFACE_TYPE , &i32Values[0]); m_pShell->PVRShellOutputDebug(" Surface type: %s%s%s\n", i32Values[0] & EGL_WINDOW_BIT ? "WINDOW " : "", i32Values[1] & EGL_PBUFFER_BIT ? "PBUFFER " : "", i32Values[2] & EGL_PIXMAP_BIT ? "PIXMAP " : ""); // EGL renderable type #ifdef EGL_VERSION_1_2 eglGetConfigAttrib(m_EGLDisplay, m_EGLConfig, EGL_RENDERABLE_TYPE , &i32Values[0]); m_pShell->PVRShellOutputDebug(" Renderable type: %s%s%s%s\n", i32Values[0] & EGL_OPENVG_BIT ? "OPENVG " : "", i32Values[0] & EGL_OPENGL_ES_BIT ? "OPENGL_ES " : "", #ifdef EGL_OPENGL_BIT i32Values[0] & EGL_OPENGL_BIT ? "OPENGL " : #endif "", i32Values[0] & EGL_OPENGL_ES2_BIT ? "OPENGL_ES2 " : ""); #endif eglGetConfigAttrib(m_EGLDisplay, m_EGLConfig, EGL_SAMPLE_BUFFERS , &i32Values[0]); eglGetConfigAttrib(m_EGLDisplay, m_EGLConfig, EGL_SAMPLES , &i32Values[1]); m_pShell->PVRShellOutputDebug(" Sample buffer No.: %i\n", i32Values[0]); m_pShell->PVRShellOutputDebug(" Samples per pixel: %i\n", i32Values[1]); } } /*!*********************************************************************** @Function ApiReleaseAPI @description Releases all resources allocated by the API. *************************************************************************/ void PVRShellInit::ApiReleaseAPI() { eglSwapBuffers(m_EGLDisplay, m_EGLWindow); eglMakeCurrent(m_EGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglDestroyContext(m_EGLDisplay, m_EGLContext); eglDestroySurface(m_EGLDisplay, m_EGLWindow); eglTerminate(m_EGLDisplay); } /******************************************************************************* * Function Name : SelectEGLConfiguration * Inputs : pData * Returns : EGLConfig * Description : Find the config to use for EGL initialisation *******************************************************************************/ EGLConfig PVRShellInitAPI::SelectEGLConfiguration(const PVRShellData * const pData) { EGLint num_config; EGLint conflist[32]; EGLConfig conf = (EGLConfig) 0; int i = 0; // Specific config ID requested? if (m_iRequestedConfig > 0) { conflist[i++] = EGL_CONFIG_ID; conflist[i++] = m_iRequestedConfig; conflist[i++] = EGL_NONE; if(!eglChooseConfig(m_EGLDisplay, conflist, &conf, 1, &num_config) || num_config != 1) { return 0; } return conf; } // Select default configuration #if defined(ANDROID) if(pData->nColorBPP == 32) { conflist[i++] = EGL_RED_SIZE; conflist[i++] = 8; conflist[i++] = EGL_GREEN_SIZE; conflist[i++] = 8; conflist[i++] = EGL_BLUE_SIZE; conflist[i++] = 8; conflist[i++] = EGL_ALPHA_SIZE; conflist[i++] = 8; } else { conflist[i++] = EGL_RED_SIZE; conflist[i++] = 5; conflist[i++] = EGL_GREEN_SIZE; conflist[i++] = 6; conflist[i++] = EGL_BLUE_SIZE; conflist[i++] = 5; conflist[i++] = EGL_ALPHA_SIZE; conflist[i++] = 0; } #else conflist[i++] = EGL_BUFFER_SIZE; conflist[i++] = pData->nColorBPP; #endif if(pData->bNeedZbuffer || pData->nDepthBPP > 0) { conflist[i++] = EGL_DEPTH_SIZE; conflist[i++] = (pData->nDepthBPP > 0) ? pData->nDepthBPP : 16; } if(pData->bNeedStencilBuffer) { conflist[i++] = EGL_STENCIL_SIZE; conflist[i++] = 8; } conflist[i++] = EGL_SURFACE_TYPE; conflist[i] = EGL_WINDOW_BIT; if(pData->bNeedPbuffer) { conflist[i] |= EGL_PBUFFER_BIT; } if(pData->bNeedPixmap) { conflist[i] |= EGL_PIXMAP_BIT; } ++i; #if defined(BUILD_OGL) conflist[i++] = EGL_RENDERABLE_TYPE; conflist[i++] = EGL_OPENGL_BIT; #elif defined(EGL_VERSION_1_3) && defined(GL_ES_VERSION_2_0) conflist[i++] = EGL_RENDERABLE_TYPE; conflist[i++] = EGL_OPENGL_ES2_BIT; #endif // Append number of number of samples depending on AA samples value set if(pData->nAASamples > 0) { conflist[i++] = EGL_SAMPLE_BUFFERS; conflist[i++] = 1; conflist[i++] = EGL_SAMPLES; conflist[i++] = pData->nAASamples; } else { conflist[i++] = EGL_SAMPLE_BUFFERS; conflist[i++] = 0; } #if defined(EWS) || defined(__QNXNTO__) if(m_NWT != NULL) { EGLint r,g,b,a, value; EGLint i32Total_num_configs, j; EGLConfig *pConfigs; // Some platforms require an egl config to have the same pixel format as the native window because // pixel format conversion is prohibited. #if defined(EWS) int format = EWS_PIXEL_FORMAT_RGB_565; r = 5; g = 6; b = 5; a = 0; #else r = g = b = a = 8; #endif conflist[i++] = EGL_RED_SIZE; conflist[i++] = r; conflist[i++] = EGL_GREEN_SIZE; conflist[i++] = g; conflist[i++] = EGL_BLUE_SIZE; conflist[i++] = b; conflist[i++] = EGL_ALPHA_SIZE; conflist[i++] = a; // Terminate the list with EGL_NONE conflist[i++] = EGL_NONE; // Find out how many configs there are in total that match our criteria if(!eglChooseConfig(m_EGLDisplay, conflist, NULL, 0, &i32Total_num_configs) || i32Total_num_configs == 0) return 0; // Allocate an array large enough to store all the possible configs that may be returned pConfigs = new EGLConfig[i32Total_num_configs]; if(!pConfigs) return 0; // Get all the configs that match our criteria if(!eglChooseConfig(m_EGLDisplay, conflist, pConfigs, i32Total_num_configs, &num_config)) { delete[] pConfigs; return 0; } // Go through the returned configs and try and find a suitable match for(j = 0; j < num_config; ++j) { #if defined(__QNXNTO__) if((eglGetConfigAttrib(m_EGLDisplay, pConfigs[j], EGL_RED_SIZE, &value) && value == r) && (eglGetConfigAttrib(m_EGLDisplay, pConfigs[j], EGL_GREEN_SIZE, &value) && value == g) && (eglGetConfigAttrib(m_EGLDisplay, pConfigs[j], EGL_BLUE_SIZE, &value) && value == b) && (eglGetConfigAttrib(m_EGLDisplay, pConfigs[j], EGL_ALPHA_SIZE, &value) && value == a)) { conf = pConfigs[j]; break; } #else #if defined (EWS) eglGetConfigAttrib(m_EGLDisplay, pConfigs[j], EGL_NATIVE_VISUAL_ID, &value); if (value == format) { conf = pConfigs[j]; break; } #endif #endif } // Tidy up delete[] pConfigs; } else #endif { // Terminate the list with EGL_NONE conflist[i++] = EGL_NONE; // Return null config if config is not found if(!eglChooseConfig(m_EGLDisplay, conflist, &conf, 1, &num_config) || num_config != 1) { return 0; } } // Return config index return conf; } /******************************************************************************* * Function Name : StringFrom_eglGetError * Returns : A string * Description : Returns a string representation of an egl error *******************************************************************************/ const char *PVRShellInitAPI::StringFrom_eglGetError() const { EGLint nErr = eglGetError(); switch(nErr) { case EGL_SUCCESS: return "EGL_SUCCESS"; case EGL_BAD_DISPLAY: return "EGL_BAD_DISPLAY"; case EGL_NOT_INITIALIZED: return "EGL_NOT_INITIALIZED"; case EGL_BAD_ACCESS: return "EGL_BAD_ACCESS"; case EGL_BAD_ALLOC: return "EGL_BAD_ALLOC"; case EGL_BAD_ATTRIBUTE: return "EGL_BAD_ATTRIBUTE"; case EGL_BAD_CONFIG: return "EGL_BAD_CONFIG"; case EGL_BAD_CONTEXT: return "EGL_BAD_CONTEXT"; case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE"; case EGL_BAD_MATCH: return "EGL_BAD_MATCH"; case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP"; case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW"; case EGL_BAD_PARAMETER: return "EGL_BAD_PARAMETER"; case EGL_BAD_SURFACE: return "EGL_BAD_SURFACE"; default: return "unknown"; } } /*!*********************************************************************** @Function ApiScreenCaptureBuffer @Input Width Width of the region to capture @Input Height Height of the region to capture @Input pBuf A buffer to put the screen capture into @description API-specific function to store the current content of the FrameBuffer into the memory allocated by the user. *************************************************************************/ bool PVRShellInit::ApiScreenCaptureBuffer(int Width,int Height,unsigned char *pBuf) { unsigned char *pLines2; int i, j; bool bRet = true; /* Allocate memory for line */ pLines2 = (unsigned char *)calloc(4 * Width * Height, sizeof(unsigned char)); if (!pLines2) return false; while (glGetError()); /* Read line from frame buffer */ glReadPixels(0, 0, Width, Height, GL_RGBA, GL_UNSIGNED_BYTE, pLines2); if(glGetError()) { bRet = false; } else { /* Convert RGB to BGR in line */ for (j = 0, i = 0; j < 4 * Width * Height; j += 4, i += 3) { pBuf[i] = pLines2[j+2]; pBuf[i+1] = pLines2[j+1]; pBuf[i+2] = pLines2[j]; } } free(pLines2); return bRet; } /*!*********************************************************************** @Function ApiRenderComplete @description Perform API operations required after a frame has finished (e.g., flipping). *************************************************************************/ void PVRShellInit::ApiRenderComplete() { #if defined(BUILD_OGLES) || defined(BUILD_OGLES2) || defined(BUILD_OGLES3) //Discard the framebuffer if set. #if !defined(BUILD_OGLES3) if (glDiscardFramebufferEXT) #endif { const GLint numAttachments=3; GLenum attachments[numAttachments]; GLint currentAttachment=0; if (m_pShell->PVRShellGet(prefDiscardColor)) { attachments[currentAttachment] = GL_COLOR_EXT; currentAttachment++; } if (m_pShell->PVRShellGet(prefDiscardDepth)) { attachments[currentAttachment] = GL_DEPTH_EXT; currentAttachment++; } if (m_pShell->PVRShellGet(prefDiscardStencil)) { attachments[currentAttachment] = GL_STENCIL_EXT; currentAttachment++; } //Assuming some attachments have been chosen, discard/invalidate them. if (currentAttachment!=0) { #if defined(BUILD_OGLES) glDiscardFramebufferEXT(GL_FRAMEBUFFER_OES, currentAttachment, attachments); #elif defined(BUILD_OGLES2) glDiscardFramebufferEXT(GL_FRAMEBUFFER, currentAttachment, attachments); #elif defined(BUILD_OGLES3) glInvalidateFramebuffer(GL_FRAMEBUFFER, currentAttachment, attachments); #endif } } #endif bool bRes; if(m_pShell->m_pShellData->bNeedPixmap) { /* "Clients rendering to single buffered surfaces (e.g. pixmap surfaces) should call eglWaitGL before accessing the native pixmap from the client." */ eglWaitGL(); // Pixmap support: Copy the rendered pixmap to the display if(m_pShell->m_pShellData->bNeedPixmapDisableCopy) { bRes = true; } else { bRes = OsPixmapCopy(); } } else { if(m_pShell->m_pShellData->bNoShellSwapBuffer) return; bRes = (eglSwapBuffers (m_EGLDisplay, m_EGLWindow) == EGL_TRUE); } if(!bRes) { // check for context loss #ifdef EGL_VERSION_1_3 if(eglGetError() == EGL_CONTEXT_LOST) #else if((eglGetError() == EGL_CONTEXT_LOST_IMG) && m_bPowerManagementSupported) #endif { m_pShell->ReleaseView(); OsDoReleaseAPI(); if(ApiInitAPI()) { m_pShell->InitView(); } } else { if(m_pShell->m_pShellData->bNeedPixmap) m_pShell->PVRShellOutputDebug("failed to copy pixmap\n"); else m_pShell->PVRShellOutputDebug("eglSwapBuffers failed\n"); } } } /*!*********************************************************************** @Function ApiSet @Input prefName Name of value to set @Modified i32Value Value to set it to @description Set parameters which are specific to the API. *************************************************************************/ bool PVRShellInit::ApiSet(const prefNameIntEnum prefName, const int i32Value) { switch(prefName) { #ifdef EGL_VERSION_1_1 case prefSwapInterval: m_pShell->m_pShellData->nSwapInterval = i32Value; return true; #endif #if defined(BUILD_OGLES) || defined(BUILD_OGLES2) || defined(BUILD_OGLES3) case prefPriority: m_pShell->m_pShellData->nPriority = i32Value; return true; #endif case prefRequestedConfig: m_iRequestedConfig = (EGLint) i32Value; return true; default: return false; } } /*!*********************************************************************** @Function ApiGet @Input prefName Name of value to get @Modified pn A pointer set to the value asked for @description Get parameters which are specific to the API. *************************************************************************/ bool PVRShellInit::ApiGet(const prefNameIntEnum prefName, int *pn) { switch(prefName) { case prefEGLMajorVersion: *pn = (int) m_MajorVersion; return true; case prefEGLMinorVersion: *pn = (int) m_MinorVersion; return true; case prefRequestedConfig: *pn = (int) m_iRequestedConfig; return true; case prefConfig: *pn = (int) m_iConfig; return true; default: return false; } } /*!*********************************************************************** @Function ApiGet @Input prefName Name of value to get @Modified pp A pointer set to the value asked for @description Get parameters which are specific to the API. *************************************************************************/ bool PVRShellInit::ApiGet(const prefNamePtrEnum prefName, void **pp) { switch(prefName) { case prefEGLDisplay: *pp = (void*)m_EGLDisplay; return true; case prefEGLSurface: *pp = (void*)m_EGLWindow; return true; default: return false; } } /**************************************************************************** ** Local code ****************************************************************************/ // The recommended technique for querying OpenGL extensions; // adapted from http://opengl.org/resources/features/OGLextensions/ static bool PVRShellIsExtensionSupported(EGLDisplay dpy, const char *extension) { // The recommended technique for querying EGL extensions matches OpenGLES; // from http://opengl.org/resources/features/OGLextensions/ const char *extensions = NULL; const char *start; char *terminator; /* Extension names should not have spaces. */ char* where = (char *) strchr(extension, ' '); if (where || *extension == '\0') return 0; extensions = eglQueryString(dpy, EGL_EXTENSIONS); if(!extensions) return false; /* It takes a bit of care to be fool-proof about parsing the OpenGL extensions string. Don't be fooled by sub-strings, etc. */ start = extensions; for (;;) { where = (char *) strstr((const char *) start, extension); if (!where) break; terminator = where + strlen(extension); if (where == start || *(where - 1) == ' ') if (*terminator == ' ' || *terminator == '\0') return true; start = terminator; } return false; } /// @endcond /***************************************************************************** End of file (PVRShellAPI.cpp) *****************************************************************************/