/****************************************************************************** | |
@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 <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <stdarg.h> | |
#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; i<numExtensions; ++i) | |
{ | |
m_pShell->PVRShellOutputDebug((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) | |
*****************************************************************************/ | |