/******************************************************************************
@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)
*****************************************************************************/