diff -r 000000000000 -r 5d03bc08d59c egl/eglrefimpl/src/session.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/egl/eglrefimpl/src/session.cpp Tue Feb 02 01:47:50 2010 +0200 @@ -0,0 +1,472 @@ +// 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 "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) + { + } + +CEglThreadSession::~CEglThreadSession() + { + CEglDriver::Close(); + } + +CEglThreadSession* CEglThreadSession::Static() + { + CEglThreadSession* es = reinterpret_cast(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; + } + +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; + } + + 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; + } + +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(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(aType), aRate, aBurst); + iDriver.Unlock(); + } + +#endif //_DEBUG