egl/eglrefimpl/src/session.cpp
author Faisal Memon <faisal.memon@nokia.com>
Fri, 25 Jun 2010 17:49:58 +0100
branchEGL_MERGE
changeset 105 158b2308cc08
parent 75 b3f964e007c8
child 118 6aeef2faff80
permissions -rw-r--r--
Fix def files so that the implementation agnostic interface definition has no non-standards defined entry points, and change the eglrefimpl specific implementation to place its private entry points high up in the ordinal order space in the implementation region, not the standards based entrypoints region.

// Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
// Reference EGL implementation to support EGL sync objects and OpenWF extensions
#include <e32debug.h>
#include "eglprivate.h"

const TInt KEglMajorVersion = 1;
const TInt KEglMinorVersion = 4;

#define KEglClientApis  ""
#define KEglVendor      "Nokia"
#define KEglVersion     "1.4 Reference EGL"
#define KEglExtensions  "EGL_KHR_reusable_sync" /* additonal extensions should be added beginning with a space */ \
                        " EGL_NOK__private__signal_sync"

// Helper macros for repetitive task
//
#define CHECK_FOR_NULL_DISPLAY(handle, retval) \
    if (handle == EGL_NO_DISPLAY) \
        { \
        SetError(EGL_BAD_DISPLAY); \
        return retval; \
        }

#define CHECK_FOR_NULL_SYNCOBJ(handle, retval) \
    if (handle == EGL_NO_SYNC_KHR) \
        { \
        SetError(EGL_BAD_PARAMETER); \
        return retval; \
        }

#define GET_DISPLAY_RETURN_IF_ERR(drv, display, handle, retval) \
    CEglDisplay* display = iDriver.FindDisplay(handle); \
    if (!display) \
        { \
        drv.Unlock(); \
        SetError(EGL_BAD_DISPLAY); \
        return retval; \
        } \
    if (!display->IsInitialized()) \
        { \
        drv.Unlock(); \
        SetError(EGL_NOT_INITIALIZED); \
        return retval; \
        }

#define GET_SYNCOBJ_RETURN_IF_ERR(drv, display, sync, handle, retval) \
    CEglSync* sync = display->FindSyncObj(handle); \
    if (!sync) \
        { \
        drv.Unlock(); \
        SetError(EGL_BAD_PARAMETER); \
        return retval; \
        } \
    if (sync->IsDestroyed()) /* sync obj has been marked as destroyed */ \
        { \
        drv.Unlock(); \
        SetError(EGL_BAD_PARAMETER); \
        return retval; \
        }
                                                                
CEglThreadSession::CEglThreadSession(CEglDriver& aDriver):
	iDriver(aDriver),
	iError(EGL_SUCCESS),
	iEgl(NULL)
	{
	Dll::SetTls( NULL ); 
	}

CEglThreadSession::~CEglThreadSession()
	{
	delete iEgl;
	CEglDriver::Close();
	}

CEglThreadSession* CEglThreadSession::Static()
	{
	CEglThreadSession* es = reinterpret_cast<CEglThreadSession*>(Dll::Tls());
	
	if (es)
		{
		return es;
		}

	const TInt err = CEglDriver::Open();
	if (err != KErrNone)
		{
		return NULL;
		}

	// CEglDriver is reference counted. As we successfuly open the driver, pls.iDriver will be non-null
	// and it should be safe to cache the pointer inside CEglThreadSession
	CEglDriver* drv = CEglDriver::GetDriver();
	__ASSERT_DEBUG(drv, User::Panic(KEglPanicCategory, EEglPanicDriverNull));

	// create session object on default thread's heap
	es = new CEglThreadSession(*drv);
	if (!es || Dll::SetTls(es)!= KErrNone)
		{
		delete es;
		return NULL;
		}
	
	return es;
	}

void CEglThreadSession::SetError(EGLint aError)
	{
	// EGL spec section 3.1, GetError will return the status of the most recent EGL function call
	// so we will always override the error status
	iError = aError;
	}

EGLint CEglThreadSession::EglGetError()
	{
	// eglGetError always succeed so it will set error state to EGL_SUCCESS
	const EGLint lastError = iError;
	iError = EGL_SUCCESS;
	return lastError;
	}

EGLDisplay CEglThreadSession::EglGetDisplay(NativeDisplayType aDisplayId)
    {
    // EGL spec section 3.2: we do not need to raise EGL error when GetDisplay fails
    SetError(EGL_SUCCESS);

    if (aDisplayId != EGL_DEFAULT_DISPLAY)
        {
        return EGL_NO_DISPLAY;
        }

    // default display is created when driver is initialised the first time and will
    // be destroyed when all threads within process have called eglReleaseThread

    return KEglDefaultDisplayHandle;
    }
void CEglThreadSession::SetEgl(EGL* aEgl)
	{
	iEgl = aEgl;
	}
EGL* CEglThreadSession::getEgl()
	{
	return iEgl;
	}
EGLBoolean CEglThreadSession::EglInitialize(EGLDisplay aDisplay, EGLint* aMajor, EGLint* aMinor)
    {
    SetError(EGL_SUCCESS);
    
    CHECK_FOR_NULL_DISPLAY(aDisplay, EGL_FALSE)

    iDriver.Lock();
    CEglDisplay* display = iDriver.FindDisplay(aDisplay);
    if (!display)
        {
        iDriver.Unlock();
        SetError(EGL_BAD_DISPLAY);
        return EGL_FALSE;
        }

    const TInt err = display->Initialize();
    iDriver.Unlock();
    
    if (err != KErrNone)
        {
        SetError(EGL_NOT_INITIALIZED);
        return EGL_FALSE;
        }
    
    EGL* pEgl = NULL;
    
    try
    {
		pEgl = new EGL();
		iEgl = pEgl;
    }
    catch(std::bad_alloc)
    {
    	SetError(EGL_BAD_ALLOC);
    	return EGL_FALSE;
    }
    
    RIEGLDisplay* eglDispaly = iEgl->getDisplay(aDisplay);
    if(eglDispaly)
    	return EGL_TRUE;
   
    //create the current display
  	RIEGLDisplay* newDisplay = NULL;
	try
	{
		newDisplay = new RIEGLDisplay(aDisplay); //throws bad_alloc
		iEgl->addDisplay(newDisplay);	//throws bad_alloc
		eglDispaly = newDisplay;
		RI_ASSERT(eglDispaly);
	}
	catch(std::bad_alloc)
	{
		RI_DELETE(iEgl);
		iEgl = NULL;
		RI_DELETE(newDisplay);
    	SetError(EGL_BAD_DISPLAY);
    	return EGL_FALSE;
	}
    
    if (aMajor)	
        {
        *aMajor = KEglMajorVersion;
        }
    if (aMinor)
        {
        *aMinor = KEglMinorVersion;
        }

    return EGL_TRUE;
    }

EGLBoolean CEglThreadSession::EglTerminate(EGLDisplay aDisplay)
    {
    SetError(EGL_SUCCESS);
    
    CHECK_FOR_NULL_DISPLAY(aDisplay, EGL_FALSE)

    iDriver.Lock();
    CEglDisplay* display = iDriver.FindDisplay(aDisplay);
    if (!display)
        {
        iDriver.Unlock();
        SetError(EGL_BAD_DISPLAY);
        return EGL_FALSE;
        }

    display->Terminate();
    iDriver.Unlock();
    
    return EGL_TRUE;
    }

TFuncPtrEglProc CEglThreadSession::EglGetProcAddress(const char* aName)
    {
    SetError(EGL_SUCCESS);
        
    if(!aName)
        {
        return NULL;
        }
    
    // EGL spec does not mention about raising error if requested function not found
    // This implementation does not set error and leave thread state unmodified
    return iDriver.GetProcAddress(aName);
    }

const char* CEglThreadSession::EglQueryString(EGLDisplay aDisplay, EGLint aName)
    {
    SetError(EGL_SUCCESS);
    
    const char* str = NULL;

    CHECK_FOR_NULL_DISPLAY(aDisplay, str)

    iDriver.Lock();
    GET_DISPLAY_RETURN_IF_ERR(iDriver, display, aDisplay, str)
    iDriver.Unlock();

    switch (aName)
        {
        case EGL_CLIENT_APIS:
            str = KEglClientApis;
            break;
        case EGL_EXTENSIONS:
            str = KEglExtensions;
            break;
        case EGL_VENDOR:
            str = KEglVendor;
            break;
        case EGL_VERSION:
            str = KEglVersion;
            break;
        default:
            SetError(EGL_BAD_PARAMETER);
            break;
        }

    return str;
    }
EGLBoolean CEglThreadSession::EglGetConfigs(EGLDisplay dpy, EGLConfig *configs,
		                                    EGLint config_size, EGLint *num_config)
	{
	return do_eglGetConfigs(dpy, configs,config_size, num_config);
	}
EGLBoolean CEglThreadSession::EglChooseConfig(EGLDisplay dpy,const EGLint *attrib_list, EGLConfig *configs,
											  EGLint config_size,EGLint *num_config)
	{
	return do_eglChooseConfig(dpy, attrib_list,configs, config_size,num_config);
	}
EGLBoolean CEglThreadSession::EglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,EGLint attribute, 
		                                         EGLint *value)
	{
	return do_eglGetConfigAttrib(dpy, config,attribute, value);
	} 
EGLSurface CEglThreadSession::EglCreateWindowSurface(EGLDisplay dpy,EGLConfig config, 
		                                             EGLNativeWindowType win, const EGLint *attrib_list)
	{
	return do_eglCreateWindowSurface(dpy, config,win,attrib_list);
	}
EGLSurface CEglThreadSession::EglCreatePbufferSurface(EGLDisplay dpy,EGLConfig config, 
		                                              const EGLint *attrib_list)
	{
	return do_eglCreatePbufferSurface(dpy, config,attrib_list);
	}
EGLSurface CEglThreadSession::EglCreatePixmapSurface(EGLDisplay dpy,EGLConfig config, 
		                                             EGLNativePixmapType pixmap, const EGLint *attrib_list)
	{
	return do_eglCreatePixmapSurface(dpy, config,pixmap,attrib_list);
	}
EGLBoolean CEglThreadSession::EglDestroySurface(EGLDisplay dpy, EGLSurface surface)
	{
	return do_eglDestroySurface(dpy, surface);
	}
EGLBoolean CEglThreadSession::EglQuerySurface(EGLDisplay dpy, EGLSurface surface,EGLint attribute,
		                                      EGLint *value)
	{
	return do_eglQuerySurface(dpy, surface,attribute, value);
	}
EGLBoolean CEglThreadSession::EglBindAPI(EGLenum api)
	{
	return do_eglBindAPI(api);
	}
EGLenum CEglThreadSession::EglQueryAPI(void)
	{
	return do_eglQueryAPI();
	}
EGLBoolean CEglThreadSession::EglWaitClient()
	{
	return do_eglWaitClient();
	}
EGLSurface CEglThreadSession::EglCreatePbufferFromClientBuffer(EGLDisplay dpy,EGLenum buftype,EGLClientBuffer buffer, 
		                                                       EGLConfig config,const EGLint *attrib_list)
	{
	return do_eglCreatePbufferFromClientBuffer(dpy, buftype, buffer,config, attrib_list);
	}
EGLBoolean CEglThreadSession::EglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface,
		                                       EGLint attribute, EGLint value)
	{
	return do_eglSurfaceAttrib(dpy, surface,attribute, value);
	}
EGLBoolean CEglThreadSession::EglBindTexImage(EGLDisplay dpy,EGLSurface surface, EGLint buffer)
	{
	return do_eglBindTexImage(dpy, surface, buffer);
	}
EGLBoolean CEglThreadSession::EglReleaseTexImage(EGLDisplay dpy,EGLSurface surface, EGLint buffer)
	{
	return do_eglReleaseTexImage(dpy, surface, buffer);
	}
EGLBoolean CEglThreadSession::EglSwapInterval(EGLDisplay dpy, EGLint interval)
	{
	return do_eglSwapInterval(dpy, interval);
	}
EGLContext CEglThreadSession::EglCreateContext(EGLDisplay dpy, EGLConfig config,EGLContext share_context,
		                                       const EGLint *attrib_list)
	{
	return do_eglCreateContext(dpy, config,share_context,attrib_list);
	}
EGLBoolean CEglThreadSession::EglDestroyContext(EGLDisplay dpy, EGLContext ctx)
	{
	return do_eglDestroyContext(dpy, ctx);
	}
EGLBoolean CEglThreadSession::EglMakeCurrent(EGLDisplay dpy, EGLSurface draw,EGLSurface read, EGLContext ctx)
	{
	return do_eglMakeCurrent(dpy, draw,read, ctx);
	}
EGLContext CEglThreadSession::EglGetCurrentContext()
	{
	return do_eglGetCurrentContext();
	}
EGLSurface CEglThreadSession::EglGetCurrentSurface(EGLint readdraw)
	{
	return do_eglGetCurrentSurface(readdraw);
	}
EGLDisplay CEglThreadSession::EglGetCurrentDisplay()
	{
	return do_eglGetCurrentDisplay();
	}
EGLBoolean CEglThreadSession::EglQueryContext(EGLDisplay dpy, EGLContext ctx,
											  EGLint attribute, EGLint* value)
	{
	return do_eglQueryContext(dpy, ctx,attribute, value);
	}
EGLBoolean CEglThreadSession::EglWaitGL()
	{
	return do_eglWaitGL();
	}
EGLBoolean CEglThreadSession::EglWaitNative(EGLint engine)
	{
	return do_eglWaitNative(engine);
	}
EGLBoolean CEglThreadSession::EglSwapBuffers(EGLDisplay dpy, EGLSurface surface)
	{
	return do_eglSwapBuffers(dpy, surface);
	}
EGLBoolean CEglThreadSession::EglCopyBuffers(EGLDisplay dpy, EGLSurface surface,EGLNativePixmapType target)
	{
	return do_eglCopyBuffers(dpy, surface,target);
	}

EGLSyncKHR CEglThreadSession::EglCreateSyncKhr(EGLDisplay aDisplay, EGLenum aType, const EGLint *aAttribList)
    {
    SetError(EGL_SUCCESS);
    
    CHECK_FOR_NULL_DISPLAY(aDisplay, EGL_NO_SYNC_KHR)

    if (aType != EGL_SYNC_REUSABLE_KHR || (aAttribList && *aAttribList != EGL_NONE))
        {
        SetError(EGL_BAD_ATTRIBUTE);
        return EGL_NO_SYNC_KHR;
        }
    
    iDriver.Lock();
    GET_DISPLAY_RETURN_IF_ERR(iDriver, display, aDisplay, EGL_NO_SYNC_KHR)
    
    CEglSync* syncObj = display->CreateSyncObj();
    iDriver.Unlock();
    
    if (!syncObj)
        {
        SetError(EGL_BAD_ALLOC);
        return EGL_NO_SYNC_KHR;
        }

    return reinterpret_cast<EGLSyncKHR>(syncObj);
    }

EGLBoolean CEglThreadSession::EglDestroySyncKhr(EGLDisplay aDisplay, EGLSyncKHR aSync)
    {
    SetError(EGL_SUCCESS);
    
    CHECK_FOR_NULL_DISPLAY(aDisplay, EGL_FALSE)
    CHECK_FOR_NULL_SYNCOBJ(aSync, EGL_FALSE)

    iDriver.Lock();
    GET_DISPLAY_RETURN_IF_ERR(iDriver, display, aDisplay, EGL_FALSE)
    
    const TInt err = display->DestroySyncObj(aSync);
    iDriver.Unlock();

    if (err != KErrNone)
        {
        SetError(EGL_BAD_PARAMETER);
        return EGL_FALSE;
        }

    return EGL_TRUE;
    }

EGLint CEglThreadSession::EglClientWaitSyncKhr(EGLDisplay aDisplay, EGLSyncKHR aSync, EGLint aFlags, EGLTimeKHR aTimeout)
    {
    SetError(EGL_SUCCESS);
    
    CHECK_FOR_NULL_DISPLAY(aDisplay, EGL_FALSE)
    CHECK_FOR_NULL_SYNCOBJ(aSync, EGL_FALSE)
    
    const EGLint supportedFlags = EGL_SYNC_FLUSH_COMMANDS_BIT_KHR;
    if (aFlags & ~supportedFlags)
        {
        SetError(EGL_BAD_PARAMETER);
        return EGL_FALSE;
        }
    
    iDriver.Lock();
    GET_DISPLAY_RETURN_IF_ERR(iDriver, display, aDisplay, EGL_FALSE)
    GET_SYNCOBJ_RETURN_IF_ERR(iDriver, display, syncObj, aSync, EGL_FALSE)

    // increment refcount to mark this sync obj in use and prevent it from being destroyed when other thread calls eglDestroySyncKHR or eglTerminate
    syncObj->Open();
    
    // release display lock as we're going to wait on sync object after this point, not releasing display lock at this 
    // point will cause deadlock
    iDriver.Unlock();

    // sync obj refcount has been incremented so it won't get destroyed even if other thread call eglDestroySyncKHR or eglTerminate
    // at this point

    // we do not support client apis, so flushing flags will be ignored in this implementation
    EGLint err = syncObj->Wait(aTimeout);

    // decrement refcount
    // sync obj will be destroyted if refcount is 0 e.g. other thread issues eglDestroySyncKHR or eglTerminate while this thread
    // is waiting on it
    iDriver.Lock();
    syncObj->Close();
    iDriver.Unlock();

    // we do not check error here as it is passed back to caller

    return err;
    }

EGLBoolean CEglThreadSession::EglSignalSyncKhr(EGLDisplay aDisplay, EGLSyncKHR aSync, EGLenum aMode)
    {
    const EGLint err = EglSignalSyncInternal(aDisplay, aSync, aMode);
    SetError(err);
    return err == EGL_SUCCESS;
    }

EGLint CEglThreadSession::EglSignalSyncInternal(EGLDisplay aDisplay, EGLSyncKHR aSync, EGLenum aMode)
    {
    if (aDisplay == EGL_NO_DISPLAY)
        {
        return EGL_BAD_DISPLAY;
        }
    if (aSync == EGL_NO_SYNC_KHR)
        {
        return EGL_BAD_PARAMETER;
        }
    if (aMode != EGL_SIGNALED_KHR && aMode != EGL_UNSIGNALED_KHR)
        {
        return EGL_BAD_PARAMETER;
        }

    iDriver.Lock();

    CEglDisplay* display = iDriver.FindDisplay(aDisplay);
    if (!display)
        {
        iDriver.Unlock();
        return EGL_BAD_DISPLAY;
        }
    if (!display->IsInitialized())
        {
        iDriver.Unlock();
        return EGL_NOT_INITIALIZED;
        }

    CEglSync* syncObj = display->FindSyncObj(aSync);
    if (!syncObj)
        {
        iDriver.Unlock();
        return EGL_BAD_PARAMETER;
        }
    if (syncObj->Type() != EGL_SYNC_REUSABLE_KHR)
        {
        iDriver.Unlock();
        return EGL_BAD_MATCH;
        }
    if (syncObj->IsDestroyed()) /* sync obj has been marked as destroyed */
        {
        iDriver.Unlock();
        return EGL_BAD_PARAMETER;
        }
    
    syncObj->Signal(aMode);
    iDriver.Unlock();
    
    return EGL_SUCCESS;
    }

EGLBoolean CEglThreadSession::EglGetSyncAttribKhr(EGLDisplay aDisplay, EGLSyncKHR aSync, EGLint aAttribute, EGLint *aValue)
    {
    SetError(EGL_SUCCESS);
    
    CHECK_FOR_NULL_DISPLAY(aDisplay, EGL_FALSE)
    CHECK_FOR_NULL_SYNCOBJ(aSync, EGL_FALSE)
    
    if (aAttribute != EGL_SYNC_TYPE_KHR && aAttribute != EGL_SYNC_STATUS_KHR)
        {
        SetError(EGL_BAD_ATTRIBUTE);
        return EGL_FALSE;
        }

    if (!aValue)
        {
        SetError(EGL_BAD_PARAMETER);
        return EGL_FALSE;
        }

    iDriver.Lock();

    GET_DISPLAY_RETURN_IF_ERR(iDriver, display, aDisplay, EGL_FALSE)
    GET_SYNCOBJ_RETURN_IF_ERR(iDriver, display, syncObj, aSync, EGL_FALSE)

    if (syncObj->Type() != EGL_SYNC_REUSABLE_KHR)
        {
        iDriver.Unlock();
        SetError(EGL_BAD_MATCH);
        return EGL_FALSE;
        }
    
    switch (aAttribute)
        {
        case EGL_SYNC_TYPE_KHR:
            *aValue = syncObj->Type();
            break;
            
        case EGL_SYNC_STATUS_KHR:
            *aValue = syncObj->Status();
            break;
        }

    iDriver.Unlock();
    
    return EGL_TRUE;
    }

#ifdef _DEBUG
void CEglThreadSession::EglHeapMarkStart()
    {
    iDriver.Lock();
    iDriver.Heap().__DbgMarkStart();
    iDriver.Unlock();
    }

EGLint CEglThreadSession::EglHeapMarkEnd(EGLint aCount)
    {
    iDriver.Lock();
    const TInt cell = iDriver.Heap().__DbgMarkEnd(aCount);
    iDriver.Unlock();
    
    return cell;
    }

void CEglThreadSession::EglHeapSetBurstAllocFail(EGLenum aType, EGLint aRate, EGLint aBurst)
    {
    iDriver.Lock();
    iDriver.Heap().__DbgSetBurstAllocFail(static_cast<RAllocator::TAllocFail>(aType), aRate, aBurst);
    iDriver.Unlock();
    }

#endif //_DEBUG