/* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and /or associated documentation files
* (the "Materials "), to deal in the Materials without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Materials,
* and to permit persons to whom the Materials are furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Materials.
*
* THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR
* THE USE OR OTHER DEALINGS IN THE MATERIALS.
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:
*
*/
#include <string.h>
#include <algorithm>
#include <EGL/egl.h>
#include "eglDefinitions.h"
#include "eglInternal.h"
#include "EGLState.h"
#include "EGLProcess.h"
#include "EGLDisplay.h"
#include "EGLThread.h"
#include "EGLContext.h"
#include "EGLConfig.h"
#include "EGLWindowSurface.h"
#include "EGLPbufferSurface.h"
#include "ColorDescriptor.h"
#include "SurfaceDescriptor.h"
#include "EGLExtension.h"
#include "EGLOs.h"
#if defined(_WIN32)
#include <windows.h>
#else
// \todo other platforms
#endif
#if defined(_WIN32) && !defined(EGLI_USE_PLATSIM_EXTENSIONS)
static DWORD g_tlsIndex = TLS_OUT_OF_INDEXES;
#endif
static CEGLState* g_eglState = NULL;
static bool g_lockInitialized = false;
EGLI_LOCK g_eglLock;
CEGLState* getState()
{
#if defined(EGLI_USE_PLATSIM_EXTENSIONS)
if( !g_eglState )
{
g_eglState = EGLI_NEW CEGLState();
if( !g_eglState )
{
return NULL;
}
if( !(g_eglState->Initialize()) )
{
delete g_eglState;
g_eglState = NULL;
return NULL;
}
g_eglState->AddRef();
}
return g_eglState;
#elif defined(_WIN32)
CEGLOs::GetLock( &g_eglLock );
if( !g_eglState )
{
g_eglState = EGLI_NEW CEGLState();
if( !g_eglState )
{
CEGLOs::ReleaseLock( &g_eglLock );
return NULL;
}
if( !(g_eglState->Initialize()) )
{
delete g_eglState;
g_eglState = NULL;
CEGLOs::ReleaseLock( &g_eglLock );
return NULL;
}
}
EGLI_ASSERT( g_tlsIndex != TLS_OUT_OF_INDEXES );
if( g_tlsIndex == TLS_OUT_OF_INDEXES )
{
CEGLOs::ReleaseLock( &g_eglLock );
return NULL;
}
CEGLThread* thread = (CEGLThread*)TlsGetValue( g_tlsIndex );
if( g_eglState && !thread )
{
// \todo Remove CEGLProcess when platsim extensions are not needed any more
thread = g_eglState->GetCurrentProcess()->AddThread( GetCurrentThreadId(), true, g_eglState->SupportedApis() );
if( !thread )
{
CEGLOs::ReleaseLock( &g_eglLock );
return NULL;
}
if( !(TlsSetValue( g_tlsIndex, (void *)thread )) )
{
CEGLOs::ReleaseLock( &g_eglLock );
return NULL;
}
g_eglState->AddRef();
}
CEGLOs::ReleaseLock( &g_eglLock );
return g_eglState;
#else // Linux
// \todo
return NULL;
#endif
}
static void releaseState()
{
#if defined(EGLI_USE_PLATSIM_EXTENSIONS)
if( g_eglState )
{
if( g_eglState->RemoveRef() )
{
delete g_eglState;
g_eglState = NULL;
}
}
#elif defined(_WIN32)
CEGLOs::GetLock( &g_eglLock );
if( g_eglState )
{
g_eglState->GetCurrentProcess()->RemoveThread( GetCurrentThreadId() );
EGLI_ASSERT( g_tlsIndex != TLS_OUT_OF_INDEXES );
if( g_tlsIndex != TLS_OUT_OF_INDEXES )
{
TlsSetValue( g_tlsIndex, 0 );
}
}
if( g_eglState && g_eglState->RemoveRef() )
{
delete g_eglState;
g_eglState = NULL;
}
CEGLOs::ReleaseLock( &g_eglLock );
#else // Linux
// \todo
EGLI_ASSERT( false );
#endif
}
/*static*/ CEGLThread* getThread()
{
#if defined(EGLI_USE_PLATSIM_EXTENSIONS)
CEGLState* state = getState();
CEGLProcess* process = state->GetCurrentProcess();
if( process )
{
return process->CurrentThread();
}
return NULL;
#elif defined(_WIN32)
EGLI_ASSERT( g_tlsIndex != TLS_OUT_OF_INDEXES );
if( g_tlsIndex == TLS_OUT_OF_INDEXES )
return NULL;
CEGLThread* thread = (CEGLThread*)TlsGetValue( g_tlsIndex );
if( !thread && GetLastError() == ERROR_SUCCESS )
{
// TlsGetValue() succeeded but didn't have thread => create one now
CEGLState* state = getState();
if( state )
{
thread = (CEGLThread*)TlsGetValue( g_tlsIndex );
}
}
return thread;
#else // Linux
// \todo
EGLI_ASSERT( false );
#endif
}
void setEGLError( EGLint error )
{
CEGLThread* thread = getThread();
if( thread )
{
thread->SetError( error );
}
}
#define EGLI_GET_DISPLAY_RET(id,ret)\
CEGLDisplay* display = state->GetDisplay( id );\
if( !display )\
{\
EGLI_LEAVE_RET( ret, EGL_BAD_DISPLAY );\
}\
EGLI_ASSERT( display->ProcessId() == process->Id() );\
if( !(display->IsInitialized()) )\
{\
EGLI_LEAVE_RET( ret, EGL_NOT_INITIALIZED );\
}
#ifdef __cplusplus
extern "C" {
#endif
/*When there is no status to return (in other words, when eglGetError is called
as the first EGL call in a thread, or immediately after calling eglReleaseThread),
EGL_SUCCESS will be returned.*/
EGLAPI EGLint EGLAPIENTRY eglGetError(void)
{
EGLint err = EGL_SUCCESS;
CEGLThread* thread = getThread();
if( thread )
{
err = thread->Error();
thread->SetError( EGL_SUCCESS );
}
else
{
err = EGL_BAD_ALLOC;
}
return err;
}
EGLAPI EGLDisplay EGLAPIENTRY eglGetDisplay(EGLNativeDisplayType display_id)
{
EGLI_ENTER_RET( EGL_NO_DISPLAY );
if( display_id == EGL_DEFAULT_DISPLAY )
{
display_id = (EGLNativeDisplayType)state->DefaultDisplay();
}
CEGLDisplay* display = state->GetDisplayByNativeType( (EGLINativeDisplayType)display_id, process->Id() );
if( !display )
{
if( !(CEGLOs::IsValidNativeDisplay( (EGLINativeDisplayType)display_id )) )
{
EGLI_LEAVE_RET( EGL_NO_DISPLAY, EGL_BAD_PARAMETER );
}
display = state->AddDisplay( (EGLINativeDisplayType)display_id, process->Id() );
if( !display )
{
EGLI_LEAVE_RET( EGL_NO_DISPLAY, EGL_BAD_ALLOC );
}
display->AddRef();
}
EGLI_LEAVE_RET( (EGLDisplay)display, EGL_SUCCESS );
}
EGLAPI EGLBoolean EGLAPIENTRY eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
{
EGLI_ENTER_RET( EGL_FALSE );
CEGLDisplay* display = state->GetDisplay( dpy );
if( !display )
{
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_DISPLAY );
}
if( !(display->IsInitialized()) && !(display->Initialize()) )
{
EGLI_LEAVE_RET( EGL_FALSE, EGL_NOT_INITIALIZED );
}
if( major ) *major = 1;
if( minor ) *minor = 4;
EGLI_LEAVE_RET( EGL_TRUE, EGL_SUCCESS );
}
EGLAPI EGLBoolean EGLAPIENTRY eglTerminate(EGLDisplay dpy)
{
EGLI_ENTER_RET( EGL_FALSE );
CEGLDisplay* display = state->GetDisplay( dpy );
#if defined(EGLI_USE_PLATSIM_EXTENSIONS)
if( display && display->ProcessId() != process->Id() )
{
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_DISPLAY );
}
#endif
if( !display )
{
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_DISPLAY );
}
if( !(display->IsInitialized()) )
{
EGLI_LEAVE_RET( EGL_TRUE, EGL_SUCCESS );
}
display->RemoveRef();
if( display->TerminateDisplay() )
{
state->RemoveDisplay( display );
}
EGLI_LEAVE_RET( EGL_TRUE, EGL_SUCCESS );
}
/*
eglQueryString returns a pointer to a static, zero-terminated string describing
some aspect of the EGL implementation running on the specified display. name
may be one of EGL_CLIENT_APIS, EGL_EXTENSIONS, EGL_VENDOR, or EGL_-
VERSION.
The EGL_CLIENT_APIS string describes which client rendering APIs are
supported. It is zero-terminated and contains a space-separated list of API
names, which must include at least one of ‘‘OpenGL’’, ‘‘OpenGL_ES’’ or
‘‘OpenVG’’.
The EGL_EXTENSIONS string describes which EGL extensions are supported
by the EGL implementation running on the specified display. The string is zeroterminated
and contains a space-separated list of extension names; extension names
themselves do not contain spaces. If there are no extensions to EGL, then the empty
string is returned.
The format and contents of the EGL_VENDOR string is implementation dependent.
The format of the EGL_VERSION string is:
<major version.minor version><space><vendor specific info>
*/
EGLAPI const char * EGLAPIENTRY eglQueryString(EGLDisplay dpy, EGLint name)
{
EGLI_ENTER_RET( NULL );
EGLI_GET_DISPLAY_RET( dpy, NULL );
const char* ret = NULL;
switch(name)
{
case EGL_CLIENT_APIS:
{
switch( state->SupportedApis() )
{
case EGL_OPENVG_BIT | EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT:
{
ret = "OpenVG OpenGL_ES OpenGL_ES2";
break;
}
case EGL_OPENVG_BIT | EGL_OPENGL_ES_BIT:
{
ret = "OpenVG OpenGL_ES";
break;
}
case EGL_OPENVG_BIT | EGL_OPENGL_ES2_BIT:
{
ret = "OpenVG OpenGL_ES2";
break;
}
case EGL_OPENVG_BIT:
{
ret = "OpenVG";
break;
}
case EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT:
{
ret = "OpenGL_ES OpenGL_ES2";
break;
}
case EGL_OPENGL_ES_BIT:
{
ret = "OpenGL_ES";
break;
}
case EGL_OPENGL_ES2_BIT:
{
ret = "OpenGL_ES2";
break;
}
default:
{
ret = "";
break;
}
}
break;
}
case EGL_EXTENSIONS:
{
// TODO
ret = "EGL_KHR_image_base";
break;
}
case EGL_VENDOR:
{
ret = "Nokia";
break;
}
case EGL_VERSION:
{
ret ="1.4 PlatSim";
break;
}
default:
{
EGLI_LEAVE_RET( NULL, EGL_BAD_PARAMETER );
break;
}
}
EGLI_LEAVE_RET( ret, EGL_SUCCESS );
}
EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigs(EGLDisplay dpy, EGLConfig *configs,
EGLint config_size, EGLint *num_config)
{
EGLI_ENTER_RET( EGL_FALSE );
if( !num_config )
{
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_PARAMETER );
}
EGLI_GET_DISPLAY_RET( dpy, EGL_FALSE );
EGLint configCount = state->ConfigCount();
if( !configs )
{
*num_config = configCount;
EGLI_LEAVE_RET( EGL_TRUE, EGL_SUCCESS );
}
*num_config = EGLI_MIN( configCount, config_size );
state->FillConfigs( configs, *num_config );
EGLI_LEAVE_RET( EGL_TRUE, EGL_SUCCESS );
}
EGLAPI EGLBoolean EGLAPIENTRY eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list,
EGLConfig *configs, EGLint config_size,
EGLint *num_config)
{
EGLI_ENTER_RET( EGL_FALSE );
EGLI_GET_DISPLAY_RET( dpy, EGL_FALSE );
CColorDescriptor* colorDesc = EGLI_NEW CColorDescriptor( 0, 0, 0, 0, true, 0, false, 0, 0 );
if( !colorDesc )
{
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_ALLOC );
}
colorDesc->SetAttribute( EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER );
CEGLConfig* filter = EGLI_NEW CEGLConfig(
*colorDesc,
EGL_DONT_CARE,
EGL_DONT_CARE,
EGL_DONT_CARE,
EGL_DONT_CARE,
0, 0, 0,
EGL_DONT_CARE,
EGL_DONT_CARE,
EGL_DONT_CARE,
EGL_DONT_CARE,
EGL_OPENGL_ES_BIT,
0, 0, 0,
EGL_WINDOW_BIT,
NULL ); // transparent color
delete colorDesc;
colorDesc = NULL;
if( !filter )
{
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_ALLOC );
}
EGLint configId = 0;
EGLint matchPixmap = EGL_NONE;
if( attrib_list && attrib_list[0] != EGL_NONE )
{
for( EGLint i=0; attrib_list[i] != EGL_NONE && configId == 0; i+=2 )
{
switch( attrib_list[i] )
{
case EGL_NATIVE_VISUAL_ID:
case EGL_MAX_PBUFFER_HEIGHT:
case EGL_MAX_PBUFFER_PIXELS:
case EGL_MAX_PBUFFER_WIDTH:
{
// IGNORED
break;
}
case EGL_CONFIG_ID:
{
configId = attrib_list[i+1];
break;
}
case EGL_MATCH_NATIVE_PIXMAP:
{
matchPixmap = attrib_list[i+1];
break;
}
default:
{
if( !(filter->SetAttribute(attrib_list[i], attrib_list[i+1])) )
{
delete filter;
filter = NULL;
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_ATTRIBUTE );
}
}
}
}
}
if( configId > 0 )
{
CEGLConfig* config = state->FindConfigById( configId );
if( !config )
{
delete filter;
filter = NULL;
// TODO: is this correct error code?
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_ALLOC );
}
*num_config = 1;
configs[0] = (EGLConfig)config;
delete filter;
filter = NULL;
EGLI_LEAVE_RET( EGL_TRUE, EGL_SUCCESS );
}
if( matchPixmap != EGL_NONE )
{
// eglChooseConfig – only pbuffer supported, so no need for EGL_MATCH_NATIVE_PIXMAP
}
*num_config = state->MatchConfigs( filter, configs, config_size );
delete filter;
filter = NULL;
EGLI_LEAVE_RET( EGL_TRUE, EGL_SUCCESS );
}
EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigAttrib(EGLDisplay dpy, EGLConfig configId,
EGLint attribute, EGLint *value)
{
EGLI_ENTER_RET( EGL_FALSE );
EGLI_GET_DISPLAY_RET( dpy, EGL_FALSE );
if( !value )
{
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_PARAMETER );
}
CEGLConfig* config = state->GetConfig( configId );
if( !config )
{
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_CONFIG );
}
EGLint val = config->GetAttribute( attribute );
if( val == EGL_BAD_ATTRIBUTE )
{
EGLI_LEAVE_RET( EGL_FALSE, val );
}
*value = val;
EGLI_LEAVE_RET( EGL_TRUE, EGL_SUCCESS );
}
EGLAPI EGLSurface EGLAPIENTRY eglCreateWindowSurface(EGLDisplay dpy, EGLConfig configId,
EGLNativeWindowType win,
const EGLint *attrib_list)
{
EGLI_ENTER_RET( EGL_NO_SURFACE );
EGLI_GET_DISPLAY_RET ( dpy, EGL_NO_SURFACE );
// \todo eglCreateWindowSurface – EGL_BAD_MATCH raised (as no window-supporting configs)
CEGLConfig* config = state->GetConfig( configId );
if( !config )
{
EGLI_LEAVE_RET( EGL_NO_SURFACE, EGL_BAD_CONFIG );
}
EGLint surfaceType = config->GetAttribute( EGL_SURFACE_TYPE );
if( !(surfaceType & EGL_WINDOW_BIT) )
{
EGLI_LEAVE_RET( EGL_NO_SURFACE, EGL_BAD_MATCH );
}
CEGLSurface* surface = display->GetSurfaceByNativeType( (EGLINativeWindowType)win );
if( surface && surface->Config() == config )
{
EGLI_LEAVE_RET( EGL_NO_SURFACE, EGL_BAD_ALLOC );
}
EGLint renderBuffer = EGL_BACK_BUFFER;
EGLint colorSpace = EGL_VG_COLORSPACE_sRGB;
EGLint alphaFormat = EGL_VG_ALPHA_FORMAT_NONPRE;
EGLint renderableType = config->GetAttribute( EGL_RENDERABLE_TYPE );
if( attrib_list && attrib_list[0] != EGL_NONE )
{
for( int i=0; attrib_list[i] != EGL_NONE; i+=2 )
{
switch( attrib_list[i] )
{
case EGL_RENDER_BUFFER:
renderBuffer = attrib_list[i+1];
break;
case EGL_VG_COLORSPACE:
if( !(renderableType & EGL_OPENVG_BIT) )
{
EGLI_LEAVE_RET( EGL_NO_SURFACE, EGL_BAD_ATTRIBUTE );
}
colorSpace = attrib_list[i+1];
break;
case EGL_VG_ALPHA_FORMAT:
if( !(renderableType & EGL_OPENVG_BIT) )
{
EGLI_LEAVE_RET( EGL_NO_SURFACE, EGL_BAD_ATTRIBUTE );
}
alphaFormat = attrib_list[i+1];
break;
default:
EGLI_LEAVE_RET( EGL_NO_SURFACE, EGL_BAD_ATTRIBUTE );
}
}
}
if( !(surfaceType & colorSpace) || !(surfaceType & alphaFormat) )
{
EGLI_LEAVE_RET( EGL_NO_SURFACE, EGL_BAD_MATCH );
}
if( !CEGLOs::IsValidNativeWindow( win ) )
{
EGLI_LEAVE_RET( EGL_NO_SURFACE, EGL_BAD_NATIVE_WINDOW );
}
EGLIOsWindowContext* osContext = CEGLOs::CreateOSWindowContext( win, *config );
if( !osContext )
{
EGLI_LEAVE_RET( EGL_NO_SURFACE, EGL_BAD_ALLOC );
}
surface = EGLI_NEW CEGLWindowSurface( config, colorSpace, alphaFormat, renderBuffer, osContext );
if( !surface )
{
CEGLOs::DestroyOSWindowContext( osContext );
EGLI_LEAVE_RET( EGL_NO_SURFACE, EGL_BAD_ALLOC );
}
// \note AddSurface() will destroy the object if it fails to take ownership
surface = display->AddSurface( surface );
if( !surface )
{
EGLI_LEAVE_RET( EGL_NO_SURFACE, EGL_BAD_ALLOC );
}
#if !defined(EGLI_USE_PLATSIM_EXTENSIONS)
int width = 0;
int height = 0;
if( !CEGLOs::GetNativeWindowSize( win, width, height ) ||
!(surface->Resize( width, height )) )
{
// \note RemoveSurface() will destroy the object
display->RemoveSurface( surface );
// \todo Is this correct error?
EGLI_LEAVE_RET( EGL_NO_SURFACE, EGL_BAD_ALLOC );
}
if( (state->SupportedApis() & EGL_OPENVG_BIT) && (renderableType & EGL_OPENVG_BIT) )
{
SurfaceDescriptor* surfaceDesc = surface->Descriptor();
if( !(state->VGInterface()->CreateSurface( surfaceDesc, surface->VGBuffers(), NULL )) )
{
// \note RemoveSurface() will destroy the object
display->RemoveSurface( surface );
EGLI_LEAVE_RET( EGL_NO_SURFACE, EGL_BAD_ALLOC );
}
}
#endif // EGLI_USE_PLATSIM_EXTENSIONS
surface->AddRef();
EGLI_LEAVE_RET( (EGLSurface)surface, EGL_SUCCESS );
}
EGLAPI EGLSurface EGLAPIENTRY eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig configId,
const EGLint *attrib_list)
{
// \todo combine with eglCreatePbufferFromClientBuffer()
EGLI_ENTER_RET( EGL_NO_SURFACE );
EGLI_GET_DISPLAY_RET( dpy, EGL_NO_SURFACE );
CEGLConfig* config = state->GetConfig( configId );
if( !config )
{
EGLI_LEAVE_RET( EGL_NO_SURFACE, EGL_BAD_CONFIG );
}
if( !(config->GetAttribute( EGL_SURFACE_TYPE ) & EGL_PBUFFER_BIT) )
{
EGLI_LEAVE_RET( EGL_NO_SURFACE, EGL_BAD_MATCH );
}
EGLint width = 0;
EGLint height = 0;
EGLint textureFormat = EGL_NO_TEXTURE;
EGLint textureTarget = EGL_NO_TEXTURE;
EGLint mipmapTexture = EGL_FALSE;
EGLint largestPbuffer = EGL_FALSE;
EGLint colorSpace = EGL_VG_COLORSPACE_sRGB;
EGLint alphaFormat = EGL_VG_ALPHA_FORMAT_NONPRE;
EGLint renderableType = config->GetAttribute( EGL_RENDERABLE_TYPE );
if( attrib_list && attrib_list[0] != EGL_NONE )
{
for( int i=0; attrib_list[i] != EGL_NONE; i+=2 )
{
EGLint value = attrib_list[i+1];
switch( attrib_list[i] )
{
case EGL_WIDTH:
{
if( value < 0 )
{
EGLI_LEAVE_RET( EGL_NO_SURFACE, EGL_BAD_PARAMETER );
}
width = value;
break;
}
case EGL_HEIGHT:
{
if( value < 0 )
{
EGLI_LEAVE_RET( EGL_NO_SURFACE, EGL_BAD_PARAMETER );
}
height = value;
break;
}
case EGL_LARGEST_PBUFFER:
{
largestPbuffer = value;
break;
}
case EGL_TEXTURE_FORMAT:
{
if( !(renderableType & EGL_OPENGL_ES_BIT) &&
!(renderableType & EGL_OPENGL_ES2_BIT) ||
(value != EGL_TEXTURE_RGB &&
value != EGL_TEXTURE_RGBA &&
value != EGL_NO_TEXTURE) )
{
EGLI_LEAVE_RET( EGL_NO_SURFACE, EGL_BAD_ATTRIBUTE );
}
textureFormat = value;
break;
}
case EGL_TEXTURE_TARGET:
{
if( !(renderableType & EGL_OPENGL_ES_BIT) &&
!(renderableType & EGL_OPENGL_ES2_BIT) ||
(value != EGL_TEXTURE_2D &&
value != EGL_NO_TEXTURE) )
{
EGLI_LEAVE_RET( EGL_NO_SURFACE, EGL_BAD_ATTRIBUTE );
}
textureTarget = value;
break;
}
case EGL_MIPMAP_TEXTURE:
{
if( !(renderableType & EGL_OPENGL_ES_BIT) ||
!(renderableType & EGL_OPENGL_ES2_BIT) )
{
EGLI_LEAVE_RET( EGL_NO_SURFACE, EGL_BAD_ATTRIBUTE );
}
mipmapTexture = value;
break;
}
case EGL_VG_COLORSPACE:
{
if( !(renderableType & EGL_OPENVG_BIT) ||
(value != EGL_VG_COLORSPACE_sRGB &&
value != EGL_VG_COLORSPACE_LINEAR) )
{
EGLI_LEAVE_RET( EGL_NO_SURFACE, EGL_BAD_ATTRIBUTE );
}
colorSpace = value;
break;
}
case EGL_VG_ALPHA_FORMAT:
{
if( !(renderableType & EGL_OPENVG_BIT) ||
(value != EGL_VG_ALPHA_FORMAT_PRE &&
value != EGL_VG_ALPHA_FORMAT_NONPRE) )
{
EGLI_LEAVE_RET( EGL_NO_SURFACE, EGL_BAD_ATTRIBUTE );
}
alphaFormat = value;
break;
}
default:
EGLI_LEAVE_RET( EGL_NO_SURFACE, EGL_BAD_ATTRIBUTE );
}
}
}
if( (textureFormat == EGL_NO_TEXTURE && textureTarget != EGL_NO_TEXTURE) ||
(textureFormat != EGL_NO_TEXTURE && textureTarget == EGL_NO_TEXTURE) )
{
EGLI_LEAVE_RET( EGL_NO_SURFACE, EGL_BAD_MATCH );
}
CEGLPbufferSurface* surface = EGLI_NEW CEGLPbufferSurface( colorSpace, alphaFormat,
EGL_BACK_BUFFER, config, largestPbuffer, textureFormat, textureTarget, mipmapTexture );
// \note AddSurface() will destroy the object if it fails to take ownership
surface = (CEGLPbufferSurface*)display->AddSurface( surface );
if( !surface )
{
EGLI_LEAVE_RET( EGL_NO_SURFACE, EGL_BAD_ALLOC );
}
if( !(surface->Resize(width, height)) )
{
display->RemoveSurface( surface );
EGLI_LEAVE_RET( EGL_NO_SURFACE, EGL_BAD_ALLOC );
}
// \todo refactor all this surface creation stuff
if( (renderableType & EGL_OPENVG_BIT) && (state->SupportedApis() & EGL_OPENVG_BIT) )
{
// \todo Delay surface creation until needed.
// \todo largest Pbuffer
if( !(state->VGInterface()->CreateSurface( surface->Descriptor(), surface->VGBuffers(), NULL )) )
{
// \note RemoveSurface() will destroy the object
display->RemoveSurface( surface );
EGLI_LEAVE_RET( EGL_NO_SURFACE, EGL_BAD_ALLOC );
}
}
if( renderableType & EGL_OPENGL_ES_BIT && (state->SupportedApis() & EGL_OPENGL_ES_BIT) )
{
struct EGLINativePbufferContainer* nativePbuffer = CEGLOs::CreateNativePbuffer( display->NativeType(),
*config, width, height, largestPbuffer, textureFormat, textureTarget );
if( !nativePbuffer )
{
if( surface->VGClientSurface() )
{
state->VGInterface()->ReleaseSurface( surface->VGClientSurface() );
}
// \note RemoveSurface() will destroy the object
display->RemoveSurface( surface );
EGLI_LEAVE_RET( EGL_NO_SURFACE, EGL_BAD_ALLOC );
}
surface->SetNativePbufferContainer( nativePbuffer );
}
if( renderableType & EGL_OPENGL_ES2_BIT && (state->SupportedApis() & EGL_OPENGL_ES2_BIT) )
{
struct EGLINativePbufferContainer* nativePbuffer = CEGLOs::CreateNativePbuffer( display->NativeType(),
*config, width, height, largestPbuffer, textureFormat, textureTarget );
if( !nativePbuffer )
{
if( surface->VGClientSurface() )
{
state->VGInterface()->ReleaseSurface( surface->VGClientSurface() );
}
// \note RemoveSurface() will destroy the object
display->RemoveSurface( surface );
EGLI_LEAVE_RET( EGL_NO_SURFACE, EGL_BAD_ALLOC );
}
surface->SetNativePbufferContainer( nativePbuffer );
}
surface->AddRef();
EGLI_LEAVE_RET( (EGLSurface)surface, EGL_SUCCESS );
}
EGLAPI EGLSurface EGLAPIENTRY eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config,
EGLNativePixmapType pixmap,
const EGLint *attrib_list)
{
EGLI_ENTER_RET( EGL_NO_SURFACE );
// eglCreatePixmapSurface – EGL_BAD_MATCH raised (as no pixmap-supporting configs)
EGLI_LEAVE_RET( EGL_NO_SURFACE, EGL_BAD_MATCH );
}
EGLAPI EGLBoolean EGLAPIENTRY eglDestroySurface(EGLDisplay dpy, EGLSurface surfaceId)
{
EGLI_ENTER_RET( EGL_FALSE );
EGLI_GET_DISPLAY_RET( dpy, EGL_FALSE );
CEGLSurface* surface = display->GetSurface( surfaceId );
if( !surface )
{
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_SURFACE );
}
// \note EGLI_ENTER_RET macro will fail if thread allocation didn't succeed
CEGLThread* thread = getThread();
surface->Lock();
//TODO: client apis
if( surface->RemoveRef() )
{
if( surface->VGClientSurface() )
{
if( !(state->VGInterface()->ReleaseSurface(surface->VGClientSurface())) )
{
// need to add reference because surface is still alive
surface->AddRef();
surface->Unlock();
// \todo error code?
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_ACCESS );
}
}
// \note RemoveSurface() will destroy the object
display->RemoveSurface( surface );
surface = NULL;
}
else
{
surface->Terminate();
}
if( surface ) surface->Unlock();
EGLI_LEAVE_RET( EGL_TRUE, EGL_SUCCESS );
}
EGLAPI EGLBoolean EGLAPIENTRY eglQuerySurface(EGLDisplay dpy, EGLSurface surfaceId,
EGLint attribute, EGLint *value)
{
EGLI_ENTER_RET( EGL_FALSE );
if( !value )
{
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_PARAMETER );
}
EGLI_GET_DISPLAY_RET( dpy, EGL_FALSE );
CEGLSurface* surface = display->GetSurface( surfaceId );
if( !surface )
{
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_SURFACE );
}
surface->Lock();
EGLint ret = EGL_BAD_ATTRIBUTE;
switch( attribute )
{
case EGL_VG_ALPHA_FORMAT:
{
ret = surface->AlphaFormat();
break;
}
case EGL_VG_COLORSPACE:
{
ret = surface->ColorSpace();
break;
}
case EGL_CONFIG_ID:
{
ret = surface->Config()->Id();
break;
}
case EGL_HEIGHT:
{
ret = surface->Height();
break;
}
case EGL_WIDTH:
{
ret = surface->Width();
break;
}
case EGL_HORIZONTAL_RESOLUTION:
{
if( surface->Type() == CEGLSurface::WINDOW_SURFACE )
{
//TODO
EGLI_ASSERT( false );
}
else
{
ret = EGL_UNKNOWN;
}
break;
}
case EGL_VERTICAL_RESOLUTION:
{
if( surface->Type() == CEGLSurface::WINDOW_SURFACE )
{
//TODO
EGLI_ASSERT( false );
}
else
{
ret = EGL_UNKNOWN;
}
break;
}
case EGL_PIXEL_ASPECT_RATIO:
{
if( surface->Type() == CEGLSurface::WINDOW_SURFACE )
{
//TODO
EGLI_ASSERT( false );
}
else
{
ret = EGL_UNKNOWN;
}
break;
}
case EGL_LARGEST_PBUFFER:
{
if( surface->Type() == CEGLSurface::PBUFFER_SURFACE )
{
ret = ((CEGLPbufferSurface*)surface)->IsLargestPbuffer();
}
break;
}
case EGL_MIPMAP_TEXTURE:
{
if( surface->Type() == CEGLSurface::PBUFFER_SURFACE )
{
ret = ((CEGLPbufferSurface*)surface)->MipmapTexture();
}
break;
}
case EGL_MIPMAP_LEVEL:
{
if( surface->Type() == CEGLSurface::PBUFFER_SURFACE )
{
ret = surface->MipmapLevel();
}
break;
}
case EGL_MULTISAMPLE_RESOLVE:
{
ret = surface->MultisampleResolve();
break;
}
case EGL_RENDER_BUFFER:
{
ret = surface->RenderBuffer();
break;
}
case EGL_SWAP_BEHAVIOR:
{
ret = surface->SwapBehavior();
break;
}
case EGL_TEXTURE_FORMAT:
{
if( surface->Type() == CEGLSurface::PBUFFER_SURFACE )
{
ret = ((CEGLPbufferSurface*)surface)->TextureFormat();
}
break;
}
case EGL_TEXTURE_TARGET:
{
if( surface->Type() == CEGLSurface::PBUFFER_SURFACE )
{
ret = ((CEGLPbufferSurface*)surface)->TextureTarget();
}
break;
}
default:
{
surface->Unlock();
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_ATTRIBUTE );
}
}
*value = ret;
surface->Unlock();
EGLI_LEAVE_RET( EGL_TRUE, EGL_SUCCESS );
}
EGLAPI EGLBoolean EGLAPIENTRY eglBindAPI(EGLenum api)
{
CEGLThread* thread = getThread();
EGLI_ASSERT( thread != NULL );
if( thread && thread->IsSupportedApi( api ) )
{
thread->SetApi( api );
thread->SetError( EGL_SUCCESS );
return EGL_TRUE;
}
else if( thread )
{
thread->SetError( EGL_BAD_PARAMETER );
}
return EGL_FALSE;
}
EGLAPI EGLenum EGLAPIENTRY eglQueryAPI(void)
{
CEGLThread* thread = getThread();
EGLI_ASSERT( thread != NULL );
EGLenum api = EGL_NONE;
if( thread )
{
api = thread->CurrentApi();
thread->SetError( EGL_SUCCESS );
}
return api;
}
EGLAPI EGLBoolean EGLAPIENTRY eglWaitClient(void)
{
EGLI_ENTER_RET( EGL_FALSE );
// Macro above fails if thread is not available.
CEGLThread* thread = getThread();
switch( thread->CurrentApi() )
{
case EGL_OPENVG_API:
{
if( !(thread->CurrentVGSurface()) )
{
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_CURRENT_SURFACE );
}
if( !(thread->CurrentVGContext()) )
{
EGLI_LEAVE_RET( EGL_TRUE, EGL_SUCCESS );
}
if( !(state->VGInterface()) )
{
// \todo error code?
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_ACCESS );
}
state->VGInterface()->Finish();
break;
}
case EGL_OPENGL_ES_API:
{
CEGLSurface* read = NULL;
CEGLSurface* draw = NULL;
thread->CurrentGLESSurfaces( &read, &draw );
if( !read || !draw )
{
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_CURRENT_SURFACE );
}
if( !(thread->CurrentGLESContext()) )
{
EGLI_LEAVE_RET( EGL_TRUE, EGL_SUCCESS );
}
state->GLESInterface( thread->CurrentGLESContext()->ClientVersion() )->Finish();
break;
}
}
EGLI_LEAVE_RET( EGL_TRUE, EGL_SUCCESS );
}
EGLAPI EGLBoolean EGLAPIENTRY eglReleaseThread(void)
{
#if !defined(EGLI_USE_PLATSIM_EXTENSIONS)
#if defined(_WIN32)
EGLI_ASSERT( g_tlsIndex != TLS_OUT_OF_INDEXES );
if( TlsGetValue( g_tlsIndex ) == NULL )
{
// Already released or first call => success
return EGL_TRUE;
}
#else // Linux
// \todo
EGLI_ASSERT( false );
#endif
#else
EGLI_ENTER_RET( EGL_FALSE );
#endif //EGLI_USE_PLATSIM_EXTENSIONS
CEGLThread* thread = getThread();
EGLenum api = thread->CurrentApi();
if( thread->CurrentVGContext() )
{
const CEGLDisplay* display = thread->CurrentVGContext()->Display();
EGLI_ASSERT( display );
thread->SetApi( EGL_OPENVG_API );
eglMakeCurrent( (EGLDisplay)display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
}
if( thread->CurrentGLESContext() )
{
const CEGLDisplay* display = thread->CurrentGLESContext()->Display();
EGLI_ASSERT( display );
thread->SetApi( EGL_OPENGL_ES_API );
eglMakeCurrent( (EGLDisplay)display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
}
thread->SetApi( api );
#if defined(EGLI_USE_PLATSIM_EXTENSIONS)
process->RemoveThread( thread->Id() );
if( process->ThreadCount() == 0 )
{
// All threads destroyed from process => it's not a process any more
state->RemoveProcess( process->Id() );
process = NULL;
}
#else
releaseState();
#endif
return EGL_TRUE;
}
EGLAPI EGLSurface EGLAPIENTRY eglCreatePbufferFromClientBuffer(
EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
EGLConfig configId, const EGLint *attrib_list)
{
// \todo combine with eglCreatePbufferSurface()
EGLI_ENTER_RET( EGL_NO_SURFACE );
EGLI_GET_DISPLAY_RET( dpy, EGL_NO_SURFACE );
// EGLI_ENTER_RET macro above will fail if thread is not available
CEGLThread* thread = getThread();
switch( buftype )
{
case EGL_OPENVG_IMAGE:
{
if( !(thread->CurrentVGContext()) )
{
EGLI_LEAVE_RET( EGL_NO_SURFACE, EGL_BAD_ACCESS );
}
break;
}
default:
EGLI_LEAVE_RET( EGL_NO_SURFACE, EGL_BAD_PARAMETER );
}
CEGLConfig* config = state->GetConfig( configId );
if( !config )
{
EGLI_LEAVE_RET( EGL_NO_SURFACE, EGL_BAD_CONFIG );
}
if( !(state->VGInterface()) )
{
EGLI_LEAVE_RET( EGL_NO_SURFACE, EGL_BAD_ALLOC );
}
CColorDescriptor colorDescriptor;
int width = 0;
int height = 0;
if( !(state->VGInterface()->IsValidImage(buffer, &colorDescriptor, &width, &height)) )
{
EGLI_LEAVE_RET( EGL_NO_SURFACE, EGL_BAD_PARAMETER );
}
if( display->FindSurfaceByClientBuffer( buffer ) != NULL ||
state->VGInterface()->IsImageInUse( buffer ) )
{
EGLI_LEAVE_RET( EGL_NO_SURFACE, EGL_BAD_ACCESS );
}
if( !(colorDescriptor.MatchBitDepth(*(config->GetDescriptor()))) )
{
EGLI_LEAVE_RET( EGL_NO_SURFACE, EGL_BAD_MATCH );
}
EGLint textureFormat = EGL_NO_TEXTURE;
EGLint textureTarget = EGL_NO_TEXTURE;
EGLint mipmapTexture = EGL_FALSE;
EGLint largestPbuffer = EGL_FALSE;
EGLint colorSpace = colorDescriptor.isNonlinear() ? EGL_VG_COLORSPACE_sRGB : EGL_VG_COLORSPACE_LINEAR;
EGLint alphaFormat = colorDescriptor.isPremultiplied() ? EGL_VG_ALPHA_FORMAT_PRE : EGL_VG_ALPHA_FORMAT_NONPRE;
EGLint renderableType = config->GetAttribute( EGL_RENDERABLE_TYPE );
if( attrib_list && attrib_list[0] != EGL_NONE )
{
for( int i=0; attrib_list[i] != EGL_NONE; i+=2 )
{
EGLint value = attrib_list[i+1];
switch( attrib_list[i] )
{
case EGL_TEXTURE_FORMAT:
{
if( !(renderableType & EGL_OPENGL_ES_BIT) &&
!(renderableType & EGL_OPENGL_ES2_BIT) ||
(value != EGL_TEXTURE_RGB &&
value != EGL_TEXTURE_RGBA &&
value != EGL_NO_TEXTURE) )
{
EGLI_LEAVE_RET( EGL_NO_SURFACE, EGL_BAD_ATTRIBUTE );
}
textureFormat = value;
break;
}
case EGL_TEXTURE_TARGET:
{
if( !(renderableType & EGL_OPENGL_ES_BIT) &&
!(renderableType & EGL_OPENGL_ES2_BIT) ||
(value != EGL_TEXTURE_2D &&
value != EGL_NO_TEXTURE) )
{
EGLI_LEAVE_RET( EGL_NO_SURFACE, EGL_BAD_ATTRIBUTE );
}
textureTarget = value;
break;
}
case EGL_MIPMAP_TEXTURE:
{
if( !(renderableType & EGL_OPENGL_ES_BIT) ||
!(renderableType & EGL_OPENGL_ES2_BIT) )
{
EGLI_LEAVE_RET( EGL_NO_SURFACE, EGL_BAD_ATTRIBUTE );
}
mipmapTexture = value;
break;
}
default:
EGLI_LEAVE_RET( EGL_NO_SURFACE, EGL_BAD_ATTRIBUTE );
}
}
}
if( (textureFormat == EGL_NO_TEXTURE && textureTarget != EGL_NO_TEXTURE) ||
(textureFormat != EGL_NO_TEXTURE && textureTarget == EGL_NO_TEXTURE) )
{
EGLI_LEAVE_RET( EGL_NO_SURFACE, EGL_BAD_MATCH );
}
CEGLPbufferSurface* surface = EGLI_NEW CEGLPbufferSurface( colorSpace, alphaFormat,
EGL_BACK_BUFFER, config, largestPbuffer, textureFormat, textureTarget, mipmapTexture, buffer );
if( !surface )
{
EGLI_LEAVE_RET( EGL_NO_SURFACE, EGL_BAD_ALLOC );
}
// \note AddSurface() will destroy the object if it fails to take ownership
surface = (CEGLPbufferSurface*)display->AddSurface( surface );
if( !surface )
{
EGLI_LEAVE_RET( EGL_NO_SURFACE, EGL_BAD_ALLOC );
}
if( !(surface->Resize(width, height)) )
{
display->RemoveSurface( surface );
EGLI_LEAVE_RET( EGL_NO_SURFACE, EGL_BAD_ALLOC );
}
if( !(state->VGInterface()->CreateSurface(surface->Descriptor(), surface->VGBuffers(), buffer)) )
{
// \note RemoveSurface() will destroy the object
display->RemoveSurface( surface );
EGLI_LEAVE_RET( EGL_NO_SURFACE, EGL_BAD_ALLOC );
}
surface->AddRef();
EGLI_LEAVE_RET( surface, EGL_SUCCESS );
}
EGLAPI EGLBoolean EGLAPIENTRY eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surfaceId,
EGLint attribute, EGLint value)
{
EGLI_ENTER_RET( EGL_FALSE );
EGLI_GET_DISPLAY_RET( dpy, EGL_FALSE );
CEGLSurface* surface = display->GetSurface( surfaceId );
if( !surface )
{
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_SURFACE );
}
surface->Lock();
switch( attribute )
{
case EGL_MIPMAP_LEVEL:
{
if( !(surface->Config()->GetAttribute( EGL_RENDERABLE_TYPE ) & EGL_OPENGL_ES_BIT ))
{
surface->Unlock();
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_PARAMETER );
}
break;
}
case EGL_MULTISAMPLE_RESOLVE:
{
bool hasBoxBit = !!(surface->Config()->GetAttribute( EGL_SURFACE_TYPE ) & EGL_MULTISAMPLE_RESOLVE_BOX_BIT );
if( value != EGL_MULTISAMPLE_RESOLVE_BOX ||
value != EGL_MULTISAMPLE_RESOLVE_DEFAULT )
{
surface->Unlock();
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_ATTRIBUTE );
}
else if( value == EGL_MULTISAMPLE_RESOLVE_BOX && !hasBoxBit )
{
surface->Unlock();
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_MATCH );
}
break;
}
case EGL_SWAP_BEHAVIOR:
{
bool hasPreservedBit = !!(surface->Config()->GetAttribute( EGL_SURFACE_TYPE ) & EGL_SWAP_BEHAVIOR_PRESERVED_BIT );
if( value != EGL_BUFFER_PRESERVED ||
value != EGL_BUFFER_DESTROYED )
{
surface->Unlock();
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_ATTRIBUTE );
}
else if( value == EGL_BUFFER_PRESERVED && !hasPreservedBit )
{
surface->Unlock();
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_MATCH );
}
break;
}
default:
{
surface->Unlock();
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_ATTRIBUTE );
}
}
surface->SetAttribute( attribute, value );
surface->Unlock();
EGLI_LEAVE_RET( EGL_TRUE, EGL_SUCCESS );
}
EGLAPI EGLBoolean EGLAPIENTRY eglBindTexImage(EGLDisplay dpy, EGLSurface surfaceId, EGLint buffer)
{
EGLI_ENTER_RET( EGL_FALSE );
EGLI_GET_DISPLAY_RET( dpy, EGL_FALSE );
// EGLI_ENTER_RET macro above will fail if thread is not available
CEGLThread* thread = getThread();
CEGLSurface* surface = display->GetSurface( surfaceId );
if( !surface )
{
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_SURFACE );
}
if( buffer != EGL_BACK_BUFFER )
{
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_PARAMETER );
}
if( thread->CurrentGLESContext() == NULL)
{
EGLI_LEAVE_RET( EGL_TRUE, EGL_SUCCESS );
}
if( surface->IsLocked() )
{
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_ACCESS );
}
surface->Lock();
CEGLSurface* glesReadSurface;
thread->CurrentGLESSurfaces( &glesReadSurface, NULL );
state->SyncSurface( EGL_OPENVG_API, 0, surface, glesReadSurface );
EGLint renderableType = surface->Config()->GetAttribute( EGL_RENDERABLE_TYPE );
if( (!(renderableType & EGL_OPENGL_ES_BIT) && !(renderableType & EGL_OPENGL_ES2_BIT)) ||
surface->Type() != CEGLSurface::PBUFFER_SURFACE ||
(surface->Config()->GetAttribute( EGL_BIND_TO_TEXTURE_RGB ) == EGL_FALSE &&
surface->Config()->GetAttribute( EGL_BIND_TO_TEXTURE_RGBA ) == EGL_FALSE ) )
{
surface->Unlock();
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_SURFACE );
}
if( ((CEGLPbufferSurface*)surface)->TextureFormat() == EGL_NO_TEXTURE )
{
surface->Unlock();
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_MATCH );
}
bool mipmapTexture = !!((CEGLPbufferSurface*)surface)->MipmapTexture();
IEGLtoGLESInterface* iFace = state->GLESInterface( thread->CurrentGLESContext()->ClientVersion() );
if( surface->BoundContext() == thread->CurrentGLESContext() )
{
iFace->Flush();
}
else
{
// \todo Wait for all issued client API commands drawing to the surface to complete.
}
int level = surface->Attribute( EGL_MIPMAP_LEVEL );
int textureName = iFace->BindTexImage( surface, level, mipmapTexture, surface->Descriptor(), surface->VGColorBuffer());
EGLITextureBinding& binding = surface->TextureBinding();
binding.name = textureName;
binding.level = level;
binding.clientVersion = thread->CurrentGLESContext()->ClientVersion();
binding.context = eglGetCurrentContext();
EGLI_LEAVE_RET( EGL_TRUE, EGL_SUCCESS );
}
EGLAPI EGLBoolean EGLAPIENTRY eglReleaseTexImage(EGLDisplay dpy, EGLSurface surfaceId, EGLint buffer)
{
EGLI_ENTER_RET( EGL_FALSE );
EGLI_GET_DISPLAY_RET( dpy, EGL_FALSE );
// EGLI_ENTER_RET macro above will fail if thread is not available
CEGLThread* thread = getThread();
if( buffer != EGL_BACK_BUFFER )
{
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_PARAMETER );
}
CEGLSurface* surface = display->GetSurface( surfaceId );
// \todo errors etc.
if( !surface || (surface && surface->Type() != CEGLSurface::PBUFFER_SURFACE) )
{
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_SURFACE );
}
if( ((CEGLPbufferSurface*)surface)->TextureFormat() == EGL_NO_TEXTURE )
{
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_MATCH );
}
EGLITextureBinding& binding = surface->TextureBinding();
if( display->GetContext( binding.context ))
{
EGLenum origAPI = eglQueryAPI();
EGLSurface origReadSurface, origDrawSurface;
EGLContext origContext;
bool switchAPI = origAPI == EGL_OPENGL_ES_API;
bool switchContext = binding.context != thread->CurrentGLESContext();
if( switchAPI )
{
eglBindAPI( EGL_OPENGL_ES_API );
}
if( switchContext )
{
// Switch to the context where the texture lives.
origReadSurface = eglGetCurrentSurface(EGL_READ);
origDrawSurface = eglGetCurrentSurface(EGL_DRAW);
origContext = eglGetCurrentContext();
eglMakeCurrent( display, surfaceId, surfaceId, binding.context );
}
state->GLESInterface(binding.clientVersion)->ReleaseTexImage( binding.name, binding.level );
if( switchContext )
{
// Switch back to the original context.
eglMakeCurrent( display, origDrawSurface, origReadSurface, origContext );
}
if( switchAPI )
{
eglBindAPI( origAPI );
}
}
else
{
// The context has been destroyed. Ignore the call.
}
binding.name = 0;
surface->Unlock();
EGLI_LEAVE_RET( EGL_TRUE, EGL_SUCCESS );
}
EGLAPI EGLBoolean EGLAPIENTRY eglSwapInterval(EGLDisplay dpy, EGLint interval)
{
EGLI_ENTER_RET( EGL_FALSE );
EGLI_GET_DISPLAY_RET( dpy, EGL_FALSE );
CEGLThread* thread = process->CurrentThread();
EGLI_ASSERT( thread != NULL );
if( !(thread->CurrentVGContext()) )
{
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_CONTEXT );
}
if( !(thread->CurrentVGSurface()) )
{
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_SURFACE );
}
// eglSwapInterval – hardcode EGL_MAX_SWAP_INTERVAL and EGL_MIN_SWAP_INTERVAL to 1, so nothing here
if( thread->CurrentVGSurface()->Type() == CEGLSurface::WINDOW_SURFACE )
{
((CEGLWindowSurface*)thread->CurrentVGSurface())->SetSwapInterval( /*interval*/ 1 );
}
EGLI_LEAVE_RET( EGL_TRUE, EGL_SUCCESS );
}
EGLAPI EGLContext EGLAPIENTRY eglCreateContext(EGLDisplay dpy, EGLConfig configId,
EGLContext share_context,
const EGLint *attrib_list)
{
EGLI_ENTER_RET( EGL_NO_CONTEXT );
EGLI_GET_DISPLAY_RET( dpy, EGL_NO_CONTEXT );
CEGLConfig* config = state->GetConfig( configId );
if( !config )
{
EGLI_LEAVE_RET( EGL_NO_CONTEXT, EGL_BAD_CONFIG );
}
CEGLThread* thread = process->CurrentThread();
EGLI_ASSERT( thread != NULL );
EGLenum currentApi = thread->CurrentApi();
if( currentApi == EGL_NONE )
{
EGLI_LEAVE_RET( EGL_NO_CONTEXT, EGL_BAD_MATCH );
}
CEGLContext* shareContext = NULL;
if( share_context != EGL_NO_CONTEXT )
{
shareContext = display->GetContext( share_context );
if( !shareContext || (shareContext && process->Id() != shareContext->ProcessId()) )
{
EGLI_LEAVE_RET( EGL_NO_CONTEXT, EGL_BAD_MATCH );
}
if( currentApi != shareContext->ClientApi() )
{
EGLI_LEAVE_RET( EGL_NO_CONTEXT, EGL_BAD_CONTEXT );
}
}
EGLint renderableType = config->GetAttribute( EGL_RENDERABLE_TYPE );
EGLint clientVersion = 1;
if( attrib_list && attrib_list[0] != EGL_NONE )
{
switch( attrib_list[0] )
{
case EGL_CONTEXT_CLIENT_VERSION:
{
if( currentApi != EGL_OPENGL_ES_API )
{
EGLI_LEAVE_RET( EGL_NO_CONTEXT, EGL_BAD_ATTRIBUTE );
}
if( attrib_list[1] == 1 ) //GLES 1.1
{
if( !(renderableType & EGL_OPENGL_ES_BIT) )
{
EGLI_LEAVE_RET( EGL_NO_CONTEXT, EGL_BAD_CONFIG );
}
clientVersion = 1;
}
else if( attrib_list[1] == 2 ) //GLES 2.0
{
if( !(renderableType & EGL_OPENGL_ES2_BIT) )
{
EGLI_LEAVE_RET( EGL_NO_CONTEXT, EGL_BAD_CONFIG );
}
clientVersion = 2;
}
else
{
EGLI_LEAVE_RET( EGL_NO_CONTEXT, EGL_BAD_ATTRIBUTE );
}
break;
}
default:
{
EGLI_LEAVE_RET( EGL_NO_CONTEXT, EGL_BAD_ATTRIBUTE );
break;
}
}
}
void* clientContext = NULL;
CEGLContext* context = NULL;
switch( currentApi )
{
case EGL_OPENVG_API:
{
EGLI_ASSERT( state->VGInterface() != NULL );
clientContext = state->VGInterface()->CreateContext(
shareContext != NULL ? shareContext->ClientContext() : shareContext );
if( clientContext )
{
context = EGLI_NEW CEGLContext( process->Id(), display, config, currentApi, clientVersion, clientContext );
// \note AddContext() will destroy the object if it fails to take ownership
context = display->AddContext( context );
if( !context )
{
state->VGInterface()->ReleaseContext( clientContext );
EGLI_LEAVE_RET( EGL_NO_CONTEXT, EGL_BAD_ALLOC );
}
}
break;
}
case EGL_OPENGL_ES_API:
{
EGLINativeContextType nativeShareContext = shareContext != NULL ? shareContext->NativeContext() : NULL;
EGLINativeContextType nativeContext = CEGLOs::CreateNativeContext( *config, display->NativeType(), nativeShareContext );
if( !nativeContext )
{
EGLI_LEAVE_RET( EGL_NO_CONTEXT, EGL_BAD_ALLOC );
}
IEGLtoGLESInterface* iFace = state->GLESInterface( clientVersion );
EGLI_ASSERT( iFace != NULL );
clientContext = state->GLESInterface( clientVersion )->CreateContext( nativeContext );
if( clientContext )
{
context = EGLI_NEW CEGLContext( process->Id(), display, config, currentApi, clientVersion, clientContext );
if( context )
// \note AddContext() will destroy the object if it fails to take ownership
context = display->AddContext( context );
if( !context )
{
iFace->ReleaseContext( clientContext );
CEGLOs::DestroyNativeContext( nativeContext );
EGLI_LEAVE_RET( EGL_NO_CONTEXT, EGL_BAD_ALLOC );
}
context->SetNativeContext( nativeContext );
}
else
{
CEGLOs::DestroyNativeContext( nativeContext );
EGLI_LEAVE_RET( EGL_NO_CONTEXT, EGL_BAD_ALLOC );
}
break;
}
case EGL_NONE:
{
EGLI_LEAVE_RET( EGL_NO_CONTEXT, EGL_BAD_MATCH );
break;
}
}
if( context )
{
context->AddRef();
}
else
{
EGLI_LEAVE_RET( EGL_NO_CONTEXT, EGL_BAD_ALLOC );
}
EGLI_LEAVE_RET( (EGLContext)context, EGL_SUCCESS );
}
EGLAPI EGLBoolean EGLAPIENTRY eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
{
EGLI_ENTER_RET( EGL_FALSE );
EGLI_GET_DISPLAY_RET( dpy, EGL_FALSE );
CEGLThread* thread = process->CurrentThread();
EGLI_ASSERT( thread != NULL );
CEGLContext* context = display->GetContext( ctx );
if( !context )
{
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_CONTEXT );
}
EGLenum clientApi = context->ClientApi();
switch( clientApi )
{
case EGL_OPENVG_API:
{
if( context->RemoveRef() )
{
state->VGInterface()->ReleaseContext(context->ClientContext());
// \note RemoveContext() will destroy the object
display->RemoveContext( context );
}
else
{
context->Terminate();
}
break;
}
case EGL_OPENGL_ES_API:
{
if( context->RemoveRef() )
{
if( !(state->GLESInterface( context->ClientVersion() )->ReleaseContext( context->ClientContext() )) )
{
// \todo Handle errors!
EGLI_ASSERT( false );
}
if( context->NativeContext() && !(CEGLOs::DestroyNativeContext(context->NativeContext())) )
{
// \todo Handle errors!
EGLI_ASSERT( false );
}
// \note RemoveContext() will destroy the object
display->RemoveContext( context );
}
else
{
context->Terminate();
}
break;
}
}
EGLI_LEAVE_RET( EGL_TRUE, EGL_SUCCESS );
}
EGLAPI EGLBoolean EGLAPIENTRY eglMakeCurrent(EGLDisplay dpy, EGLSurface draw,
EGLSurface read, EGLContext ctx)
{
EGLI_ENTER_RET( EGL_FALSE );
EGLI_GET_DISPLAY_RET( dpy, EGL_FALSE );
CEGLThread* thread = process->CurrentThread();
EGLI_ASSERT( thread );
bool releaseCurrent = ( draw == EGL_NO_SURFACE && read == EGL_NO_SURFACE && ctx == EGL_NO_CONTEXT );
if( (ctx == EGL_NO_CONTEXT && draw != EGL_NO_SURFACE && read != EGL_NO_SURFACE) ||
((draw == EGL_NO_SURFACE || read == EGL_NO_SURFACE) && ctx != EGL_NO_CONTEXT) )
{
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_MATCH );
}
CEGLContext* context = display->GetContext( ctx );
if( (!releaseCurrent && !context ) || (context && context->ProcessId() != process->Id()) )
{
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_CONTEXT );
}
EGLenum currentApi = thread->CurrentApi();
CEGLContext* currentContext = NULL;
CEGLSurface* currentDrawSurface = NULL;
CEGLSurface* currentReadSurface = NULL;
CEGLSurface* drawSurface = NULL;
CEGLSurface* readSurface = NULL;
if( !releaseCurrent )
{
if( context && context->ClientApi() == EGL_OPENVG_API && ( draw != read ) )
{
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_MATCH );
}
drawSurface = display->GetSurface( draw );
readSurface = display->GetSurface( read );
if( !drawSurface || !readSurface )
{
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_SURFACE );
}
if( !(context->Config()->IsCompatible( *(drawSurface->Config()), context->ClientApi())) ||
!(context->Config()->IsCompatible( *(readSurface->Config()), context->ClientApi())) )
{
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_MATCH );
}
if( (context->Thread() && context->Thread() != thread) ||
(drawSurface->BoundContext() && drawSurface->BoundContext()->Thread() != thread) ||
(readSurface->BoundContext() && readSurface->BoundContext()->Thread() != thread) )
{
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_ACCESS );
}
if( drawSurface->Type() == CEGLSurface::WINDOW_SURFACE &&
!(CEGLOs::IsValidNativeWindow(((CEGLWindowSurface*)drawSurface)->NativeType())) )
{
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_NATIVE_WINDOW );
}
if( readSurface != drawSurface && readSurface->Type() == CEGLSurface::WINDOW_SURFACE &&
!(CEGLOs::IsValidNativeWindow(((CEGLWindowSurface*)readSurface)->NativeType())) )
{
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_NATIVE_WINDOW );
}
// TODO: If binding ctx would exceed the number of current contexts of that client
// API type supported by the implementation, an EGL_BAD_ACCESS error is
// generated.
// TODO: If either draw or read are pbuffers created with eglCreatePbufferFromClientBuffer,
// and the underlying bound client API buffers are in use by the
// client API that created them, an EGL_BAD_ACCESS error is generated
// TODO: If draw and read cannot fit into graphics memory simultaneously, an EGL_BAD_MATCH error is generated.
// TODO: If the previous context of the calling thread has unflushed commands, and
// the previous surface is no longer valid, an EGL_BAD_CURRENT_SURFACE
// error is generated.
// TODO: If the ancillary buffers for draw and read cannot be allocated, an EGL_BAD_ALLOC error is generated.
// TODO: If a power management event has occurred, an EGL_CONTEXT_LOST error is generated.
// TODO: flush context
switch( context->ClientApi() )
{
case EGL_OPENVG_API:
{
state->VGInterface()->Flush();
currentContext = thread->SwitchVGContext( context );
currentDrawSurface = thread->SwitchVGSurface( drawSurface );
drawSurface->BindToContext( context );
if( !(state->VGInterface()->SetCurrentSurface(context->ClientContext(), drawSurface->VGClientSurface())) )
{
// Restore previous context/surface
thread->SwitchVGContext( currentContext );
thread->SwitchVGSurface( currentDrawSurface );
// \todo error code?
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_ACCESS );
}
// \todo track changes through locking
drawSurface->SetVGDirty( true );
break;
}
case EGL_OPENGL_ES_API:
{
if( thread->CurrentGLESContext() )
{
state->GLESInterface(context->ClientVersion())->Flush();
}
currentContext = thread->SwitchGLESContext( context );
thread->SwitchGLESSurfaces( drawSurface, readSurface, currentReadSurface, currentDrawSurface );
drawSurface->BindToContext( context );
if( drawSurface != readSurface )
{
readSurface->BindToContext( context );
}
EGLINativeContextType nativeContext = (EGLINativeContextType)state->GLESInterface(context->ClientVersion())->GetNativeContext( context->ClientContext() );
if( !(context->NativeGLFunctions()) )
{
EGLINativeGLFunctions* nativeFuncs = EGLI_NEW EGLINativeGLFunctions;
if( !nativeFuncs )
{
// Restore previous context/surface
thread->SwitchGLESContext( currentContext );
thread->SwitchGLESSurfaces( currentReadSurface, currentDrawSurface, readSurface, drawSurface );
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_ALLOC );
}
memset( nativeFuncs, 0, sizeof(EGLINativeGLFunctions) );
if( !(CEGLOs::InitializeNativeGLFunctions(nativeFuncs, display->NativeType(), nativeContext)) )
{
// Restore previous context/surface
thread->SwitchGLESContext( currentContext );
thread->SwitchGLESSurfaces( currentReadSurface, currentDrawSurface, readSurface, drawSurface );
delete nativeFuncs;
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_ALLOC );
}
context->SetNativeGLFucntions( nativeFuncs );
}
EGLINativeDisplayType drawDC = NULL;
EGLINativeDisplayType readDC = NULL;
if( drawSurface->Type() == CEGLSurface::PBUFFER_SURFACE )
{
drawDC = ((CEGLPbufferSurface*)drawSurface)->NativeDisplay();
}
else if( drawSurface->Type() == CEGLSurface::WINDOW_SURFACE )
{
drawDC = ((CEGLWindowSurface*)drawSurface)->OsContext()->glesDisplay;
}
if( readSurface == drawSurface )
{
readDC = drawDC;
}
else if( readSurface->Type() == CEGLSurface::PBUFFER_SURFACE )
{
readDC = ((CEGLPbufferSurface*)readSurface)->NativeDisplay();
}
else if( readSurface->Type() == CEGLSurface::WINDOW_SURFACE )
{
readDC = ((CEGLWindowSurface*)readSurface)->OsContext()->glesDisplay;
}
if( !(CEGLOs::MakeNativeContextCurrent(context->NativeGLFunctions(), drawDC, readDC, context->NativeContext())) )
{
// Restore previous context/surface. CEGLOs::MakeNativeContextCurrent() will restore previous
// native context/surface on failure
thread->SwitchGLESContext( currentContext );
thread->SwitchGLESSurfaces( currentReadSurface, currentDrawSurface, readSurface, drawSurface );
// \todo error code?
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_ACCESS );
}
break;
}
default:
{
EGLI_ASSERT( false );
break;
}
}
}
else
{
switch( currentApi )
{
case EGL_OPENVG_API:
{
state->VGInterface()->Flush();
if( thread->CurrentGLESContext() )
{
// Sync surface before releasing the VG context because there
// might not be a VG context if GLES locks the surface later.
CEGLSurface* glesReadSurface;
thread->CurrentGLESSurfaces( &glesReadSurface, NULL );
state->SyncSurface( EGL_OPENGL_API, thread->CurrentGLESContext()->ClientVersion(), thread->CurrentVGSurface(), glesReadSurface );
}
currentContext = thread->SwitchVGContext( NULL );
currentDrawSurface = thread->SwitchVGSurface( NULL );
break;
}
case EGL_OPENGL_ES_API:
{
if( thread->CurrentGLESContext() )
{
state->GLESInterface(thread->CurrentGLESContext()->ClientVersion())->Flush();
}
if( thread->CurrentVGContext() )
{
// Sync surface before releasing the GLES context because there
// might not be a GLES context if VG locks the surface later.
CEGLSurface* glesReadSurface;
CEGLSurface* glesDrawSurface;
thread->CurrentGLESSurfaces( &glesReadSurface, &glesDrawSurface );
state->SyncSurface( EGL_OPENVG_API, 0, glesReadSurface, glesReadSurface );
if( glesDrawSurface != glesReadSurface )
{
state->SyncSurface( EGL_OPENVG_API, 0, glesDrawSurface, NULL );
}
}
currentContext = thread->SwitchGLESContext( NULL );
thread->SwitchGLESSurfaces( NULL, NULL, currentReadSurface, currentDrawSurface );
break;
}
}
}
if( currentDrawSurface && currentDrawSurface != drawSurface )
{
currentDrawSurface->BindToContext( NULL );
if( currentDrawSurface->RemoveRef() )
{
if( currentDrawSurface->VGClientSurface() )
{
if( !(state->VGInterface()->ReleaseSurface(currentDrawSurface->VGClientSurface())) )
{
// \todo error code?
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_ACCESS );
}
}
if( currentDrawSurface->Type() == CEGLSurface::PBUFFER_SURFACE )
{
//((CEGLPbufferSurface*)currentDrawSurface)->SetNativePbufferContainer( NULL );
//EGLI_ASSERT( false );
}
// \note RemoveSurface() will destroy the object
display->RemoveSurface( currentDrawSurface );
}
if( currentReadSurface == currentDrawSurface )
{
currentReadSurface = NULL;
}
currentDrawSurface = NULL;
}
if( currentReadSurface && currentReadSurface != readSurface )
{
currentReadSurface->BindToContext( NULL );
if( currentReadSurface->RemoveRef() )
{
if( currentReadSurface->VGClientSurface() )
{
if( !(state->VGInterface()->ReleaseSurface(currentReadSurface->VGClientSurface())) )
{
// \todo error code?
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_ACCESS );
}
}
if( currentReadSurface->Type() == CEGLSurface::PBUFFER_SURFACE )
{
// \todo
((CEGLPbufferSurface*)currentReadSurface)->SetNativePbufferContainer( NULL );
}
// \note RemoveSurface() will destroy the object
display->RemoveSurface( currentReadSurface );
}
}
if( currentContext && currentContext != context )
{
currentContext->SetThread( NULL );
if( currentContext->RemoveRef() )
{
if( currentContext->ClientContext() )
{
if( currentContext->ClientApi() == EGL_OPENVG_API )
{
bool success = state->VGInterface()->ReleaseContext( currentContext->ClientContext() );
EGLI_ASSERT( success );
}
if( currentContext->ClientApi() == EGL_OPENGL_ES_API )
{
bool success = state->GLESInterface(currentContext->ClientVersion())->ReleaseContext(currentContext->ClientContext());
EGLI_ASSERT( success );
}
}
if( currentContext->NativeContext() )
{
if( !(CEGLOs::DestroyNativeContext(currentContext->NativeContext())) )
{
// \todo Handle errors!
EGLI_ASSERT( false );
}
}
// \note RemoveContext() will destroy the object
display->RemoveContext( currentContext );
currentContext = NULL;
}
}
if( context && currentContext != context )
{
context->AddRef();
}
if( drawSurface && currentDrawSurface != drawSurface )
{
drawSurface->AddRef();
}
if( readSurface && readSurface != drawSurface && readSurface != currentReadSurface )
{
readSurface->AddRef();
}
EGLI_LEAVE_RET( EGL_TRUE, EGL_SUCCESS );
}
EGLAPI EGLContext EGLAPIENTRY eglGetCurrentContext(void)
{
EGLI_ENTER_RET( EGL_NO_CONTEXT );
CEGLThread* thread = process->CurrentThread();
EGLI_ASSERT( thread != NULL );
EGLContext ret = EGL_NO_CONTEXT;
switch( thread->CurrentApi() )
{
case EGL_OPENVG_API:
{
if( thread->CurrentVGContext() )
{
ret = thread->CurrentVGContext();
}
break;
}
case EGL_OPENGL_ES_API:
{
if( thread->CurrentGLESContext() )
{
ret = thread->CurrentGLESContext();
}
break;
}
}
EGLI_LEAVE_RET( ret, EGL_SUCCESS );
}
EGLAPI EGLSurface EGLAPIENTRY eglGetCurrentSurface(EGLint readdraw)
{
EGLI_ENTER_RET( EGL_NO_SURFACE );
if( readdraw != EGL_READ && readdraw != EGL_DRAW )
{
EGLI_LEAVE_RET( EGL_NO_SURFACE, EGL_BAD_PARAMETER );
}
CEGLThread* thread = process->CurrentThread();
EGLI_ASSERT( thread != NULL );
EGLSurface ret = EGL_NO_SURFACE;
EGLenum currentApi = thread->CurrentApi();
switch( currentApi )
{
case EGL_OPENVG_API:
{
CEGLContext* context = thread->CurrentVGContext();
if( context )
{
ret = thread->CurrentVGSurface();
}
break;
}
case EGL_OPENGL_ES_API:
{
CEGLSurface* read = NULL;
CEGLSurface* draw = NULL;
thread->CurrentGLESSurfaces( &read, &draw );
switch( readdraw )
{
case EGL_READ:
{
ret = (EGLSurface)read;
break;
}
case EGL_DRAW:
{
ret = (EGLSurface)draw;
break;
}
}
break;
}
default:
{
EGLI_ASSERT( false );
}
}
EGLI_LEAVE_RET( ret, EGL_SUCCESS );
}
EGLAPI EGLDisplay EGLAPIENTRY eglGetCurrentDisplay(void)
{
EGLI_ENTER_RET( EGL_NO_DISPLAY );
CEGLThread* thread = process->CurrentThread();
EGLI_ASSERT( thread );
EGLenum currentApi = thread->CurrentApi();
EGLDisplay ret = EGL_NO_DISPLAY;
switch( currentApi )
{
case EGL_OPENVG_API:
{
if( thread->CurrentVGContext() )
{
ret = (EGLDisplay)thread->CurrentVGContext()->Display();
}
break;
}
case EGL_OPENGL_ES_API:
{
if( thread->CurrentGLESContext() )
{
ret = (EGLDisplay)thread->CurrentGLESContext()->Display();
}
break;
}
default:
EGLI_ASSERT( false );
}
EGLI_LEAVE_RET( ret, EGL_SUCCESS );
}
EGLAPI EGLBoolean EGLAPIENTRY eglQueryContext(EGLDisplay dpy, EGLContext ctx,
EGLint attribute, EGLint *value)
{
EGLI_ENTER_RET( EGL_FALSE );
EGLI_GET_DISPLAY_RET( dpy, EGL_FALSE )
if( !value )
{
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_PARAMETER );
}
CEGLContext* context = display->GetContext( ctx );
if( !context )
{
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_CONTEXT );
}
switch( attribute )
{
case EGL_CONFIG_ID:
{
*value = ((CEGLConfig*)context->Config())->GetAttribute( EGL_CONFIG_ID );
break;
}
case EGL_CONTEXT_CLIENT_TYPE:
{
*value = context->ClientApi();
break;
}
case EGL_CONTEXT_CLIENT_VERSION:
{
*value = context->ClientVersion();
break;
}
case EGL_RENDER_BUFFER:
{
CEGLSurface* surface = NULL;
CEGLThread* thread = process->CurrentThread();
EGLI_ASSERT( thread != NULL );
if( thread->CurrentVGContext() == context )
{
surface = thread->CurrentVGSurface();
}
else if( thread->CurrentGLESContext() == context )
{
thread->CurrentGLESSurfaces( NULL, &surface );
}
else
{
surface = process->FindBoundSurface( context, false );
}
if( surface )
{
*value = surface->RenderBuffer();
}
else
{
*value = EGL_NONE;
}
break;
}
default:
{
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_ATTRIBUTE );
}
}
EGLI_LEAVE_RET( EGL_TRUE, EGL_SUCCESS );
}
EGLAPI EGLBoolean EGLAPIENTRY eglWaitGL(void)
{
EGLI_ENTER_RET( EGL_FALSE );
// EGLI_ENTER_RET macro above will fail if thread is not available
CEGLThread* thread = getThread();
EGLBoolean ret = EGL_TRUE;
EGLenum api = eglQueryAPI();
if( eglBindAPI( EGL_OPENGL_ES_API ) )
{
ret = eglWaitClient();
if( thread->IsSupportedApi(api) )
{
eglBindAPI( api );
}
}
EGLI_LEAVE_RET( ret, thread->Error() );
}
EGLAPI EGLBoolean EGLAPIENTRY eglWaitNative(EGLint engine)
{
EGLI_ENTER_RET( EGL_FALSE );
// eglWaitNative – no-op, as no such thing as native rendering to pbuffers
EGLI_LEAVE_RET( EGL_TRUE, EGL_SUCCESS );
}
EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffers(EGLDisplay dpy, EGLSurface surfaceId)
{
// \todo eglSwapBuffers – all surfaces are single-buffered pbuffers, so this just needs to do a flush in the current client API
EGLI_ENTER_RET( EGL_FALSE );
EGLI_GET_DISPLAY_RET( dpy, EGL_FALSE );
// EGLI_ENTER_RET macro above will fail if thread is not available
CEGLThread* thread = getThread();
CEGLSurface* surface = display->GetSurface( surfaceId );
if( !surface )
{
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_SURFACE );
}
EGLenum currentApi = thread->CurrentApi();
switch( currentApi )
{
case EGL_OPENVG_API:
{
if( thread->CurrentVGContext() != surface->BoundContext() )
{
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_SURFACE );
}
break;
}
case EGL_OPENGL_ES_API:
{
if( thread->CurrentGLESContext() != surface->BoundContext() )
{
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_SURFACE );
}
// \todo other GLES stuff?
}
}
if( surface->Type() != CEGLSurface::WINDOW_SURFACE || surface->RenderBuffer() == EGL_SINGLE_BUFFER )
{
EGLI_LEAVE_RET( EGL_TRUE, EGL_SUCCESS );
}
if( !(CEGLOs::IsValidNativeWindow(((CEGLWindowSurface*)surface)->NativeType())) )
{
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_NATIVE_WINDOW );
}
#if !defined(EGLI_USE_PLATSIM_EXTENSIONS)
int w, h;
if( !(CEGLOs::GetNativeWindowSize(((CEGLWindowSurface*)surface)->NativeType(), w, h)) )
{
// \todo Error code?
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_SURFACE );
}
#else
int w = surface->Width();
int h = surface->Height();
#endif
if( surface->Width() != w || surface->Height() != h )
{
if( !(surface->Resize(w, h)) )
{
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_ALLOC );
}
if( w <= 0 || h <= 0 )
{
// invisible window => do nothing
EGLI_LEAVE_RET( EGL_TRUE, EGL_SUCCESS );
}
if( surface->VGClientSurface() && state->VGInterface() )
{
if( !(state->VGInterface()->ResizeSurface(thread->CurrentVGContext()->ClientContext(),
surface->VGClientSurface(), w, h, surface->VGBuffers())) )
{
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_ALLOC );
}
}
}
EGLint stride = surface->Stride();
void* buf = ((CEGLWindowSurface*)surface)->CurrentBuffer();
#if defined(EGLI_USE_PLATSIM_EXTENSIONS)
buf = (void*)((char*)buf + ((surface->Height() - 1) * stride));
#else
switch( currentApi )
{
case EGL_OPENVG_API:
{
state->VGInterface()->CopyBuffers( buf, surface->Stride(), surface->VGClientSurface() );
break;
}
case EGL_OPENGL_ES_API:
{
if( surface->BoundContext() && !(state->GLESInterface(surface->BoundContext()->ClientVersion())) )
{
// \todo error code?
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_ACCESS );
}
}
}
#endif
CEGLOs::BlitToOSWindow( currentApi, display, ((CEGLWindowSurface*)surface)->OsContext(), buf, surface->Width(), surface->Height(), stride );
EGLI_LEAVE_RET( EGL_TRUE, EGL_SUCCESS );
}
EGLAPI EGLBoolean EGLAPIENTRY eglCopyBuffers(EGLDisplay dpy, EGLSurface surface,
EGLNativePixmapType target)
{
EGLI_ENTER_RET( EGL_FALSE );
// eglCopyBuffers always raises EGL_BAD_NATIVE_PIXMAP error (as no native pixmaps supported)
EGLI_LEAVE_RET( EGL_FALSE, EGL_BAD_NATIVE_PIXMAP );
}
/* Now, define eglGetProcAddress using the generic function ptr. type */
EGLAPI __eglMustCastToProperFunctionPointerType EGLAPIENTRY
eglGetProcAddress(const char *procname)
{
EGLI_ENTER_RET( NULL );
// \todo EGL
__eglMustCastToProperFunctionPointerType ret = NULL;
if( strncmp( procname, "vg", 2 ) == 0 )
{
ret = state->VGInterface()->GetVGProcAddress( procname );
}
else if( strncmp( procname, "egl", 3 ) == 0 )
{
ret = (__eglMustCastToProperFunctionPointerType)CEGLExtension::eglGetProcAddress( procname );
}
else if( strncmp( procname, "gl", 2 ) == 0 )
{
ret = state->GLESInterface(2)->GetGLProcAddress( procname );
if( ret == NULL )
{
// Not found in GLES2, try GLES1.
ret = state->GLESInterface(1)->GetGLProcAddress( procname );
}
}
else
{
// return just NULL pointer...
}
EGLI_LEAVE_RET( ret, EGL_SUCCESS );
}
#if defined(EGLI_USE_PLATSIM_EXTENSIONS)
// non-standard platsim functions
EGLAPI void EGLAPIENTRY eglPlatsimSetProcessInformation( EGLint processId, EGLint threadId )
{
EGLI_ENTER_RET(EGLI_NO_RET);
if( process && process->Id() != processId )
{
process = state->GetProcess( processId );
}
if( !process )
{
process = state->AddProcess( processId, true );
EGLI_ASSERT( process != NULL );
CEGLThread* thread = process->AddThread( threadId, true, state->SupportedApis() );
EGLI_ASSERT( thread != NULL );
}
else if( !(process->HasThread( threadId )) )
{
CEGLThread* thread = process->AddThread( threadId, true, state->SupportedApis() );
EGLI_ASSERT( thread != NULL );
}
else
{
state->SetCurrentProcessThread( processId, threadId );
}
EGLI_LEAVE_RET( EGLI_NO_RET, EGL_SUCCESS );
}
EGLAPI EGLint EGLAPIENTRY eglPlatsimGetError()
{
//TODO
EGLI_ENTER_RET( EGL_SUCCESS );
EGLI_ASSERT( process != NULL );
CEGLThread* thread = process->CurrentThread();
EGLI_ASSERT( thread != NULL );
EGLint err = thread->Error();
EGLI_LEAVE_RET( err, err );
}
// This is called after eglCreateWindowSurface()
EGLAPI void EGLAPIENTRY eglPlatsimSetSurfaceParams(
EGLDisplay displayId, EGLSurface surfaceId, EGLint width, EGLint height,
EGLint stride, void* buffer0, void *buffer1)
{
EGLI_ENTER_RET( EGLI_NO_RET );
CEGLDisplay* display = state->GetDisplay( displayId );
if( !display || (display && !(display->IsInitialized())) )
{
EGLI_LEAVE_RET( EGLI_NO_RET, EGL_NOT_INITIALIZED );
}
EGLI_ASSERT( display->ProcessId() == process->Id() );
CEGLSurface* surface = display->GetSurface( surfaceId );
if( !surface )
{
EGLI_LEAVE_RET( EGLI_NO_RET, EGL_BAD_SURFACE );
}
EGLI_ASSERT( surface->Type() == CEGLSurface::WINDOW_SURFACE );
if( !(surface->Resize(width, height)) )
{
EGLI_LEAVE_RET( EGLI_NO_RET, EGL_BAD_ALLOC );
}
((CEGLWindowSurface*)surface)->SetStride( stride );
((CEGLWindowSurface*)surface)->SetWindowBuffers( buffer0, buffer1 );
CEGLThread* thread = process->CurrentThread();
EGLI_ASSERT( thread != NULL );
//TODO: resizing
switch( thread->CurrentApi() )
{
case EGL_OPENVG_API:
{
if( !(surface->VGColorBuffer()) )
{
EGLI_ASSERT( state->VGInterface() != NULL );
SurfaceDescriptor* surfaceDesc = surface->Descriptor();
bool success = state->VGInterface()->CreateSurface( surfaceDesc, surface->VGBuffers(), NULL );
EGLI_ASSERT( success );
}
break;
}
case EGL_OPENGL_ES_API:
{
//TODO: GLES not implemented
//EGLI_ASSERT( false );
break;
}
default:
{
EGLI_ASSERT( false );
}
}
//TODO: what else?
EGLI_LEAVE_RET( EGLI_NO_RET, EGL_SUCCESS );
}
EGLAPI EGLNativePixmapType EGLAPIENTRY eglPlatsimGetPixmapSurfaceBitmap( EGLDisplay display, EGLSurface surface)
{
//TODO
return NULL;
}
#endif
#if defined(_WIN32)
BOOL WINAPI DllMain( HINSTANCE hinstDLL,
DWORD fdwReason,
LPVOID lpvReserved )
{
#if !defined(EGLI_USE_PLATSIM_EXTENSIONS)
switch( fdwReason )
{
case DLL_PROCESS_ATTACH:
{
g_tlsIndex = TlsAlloc();
if( g_tlsIndex == TLS_OUT_OF_INDEXES )
return FALSE;
if( !g_lockInitialized )
{
CEGLOs::InitializeLock( &g_eglLock );
g_lockInitialized = true;
}
break;
}
case DLL_THREAD_ATTACH:
{
break;
}
case DLL_THREAD_DETACH:
{
break;
}
case DLL_PROCESS_DETACH:
{
if( g_eglState )
{
EGLI_ASSERT( g_eglState->RefCount() == 0 );
delete g_eglState;
g_eglState = NULL;
}
if( g_lockInitialized )
{
CEGLOs::DestroyLock( &g_eglLock );
g_lockInitialized = false;
}
if( g_tlsIndex != TLS_OUT_OF_INDEXES )
{
TlsFree( g_tlsIndex );
}
break;
}
}
#else
switch( fdwReason )
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
{
break;
}
case DLL_PROCESS_DETACH:
{
EGLI_ASSERT( g_eglState == NULL );
break;
}
}
#endif // EGLI_USE_PLATSIM_EXTENSIONS
return TRUE;
}
#endif // _WIN32
#ifdef __cplusplus
}
#endif