sl@0: // Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // Reference EGL implementation to support EGL sync objects and OpenWF extensions sl@0: sl@0: #include "eglprivate.h" sl@0: sl@0: const TInt KEglMajorVersion = 1; sl@0: const TInt KEglMinorVersion = 4; sl@0: sl@0: #define KEglClientApis "" sl@0: #define KEglVendor "Nokia" sl@0: #define KEglVersion "1.4 Reference EGL" sl@0: #define KEglExtensions "EGL_KHR_reusable_sync" /* additonal extensions should be added beginning with a space */ \ sl@0: " EGL_NOK__private__signal_sync" sl@0: sl@0: // Helper macros for repetitive task sl@0: // sl@0: #define CHECK_FOR_NULL_DISPLAY(handle, retval) \ sl@0: if (handle == EGL_NO_DISPLAY) \ sl@0: { \ sl@0: SetError(EGL_BAD_DISPLAY); \ sl@0: return retval; \ sl@0: } sl@0: sl@0: #define CHECK_FOR_NULL_SYNCOBJ(handle, retval) \ sl@0: if (handle == EGL_NO_SYNC_KHR) \ sl@0: { \ sl@0: SetError(EGL_BAD_PARAMETER); \ sl@0: return retval; \ sl@0: } sl@0: sl@0: #define GET_DISPLAY_RETURN_IF_ERR(drv, display, handle, retval) \ sl@0: CEglDisplay* display = iDriver.FindDisplay(handle); \ sl@0: if (!display) \ sl@0: { \ sl@0: drv.Unlock(); \ sl@0: SetError(EGL_BAD_DISPLAY); \ sl@0: return retval; \ sl@0: } \ sl@0: if (!display->IsInitialized()) \ sl@0: { \ sl@0: drv.Unlock(); \ sl@0: SetError(EGL_NOT_INITIALIZED); \ sl@0: return retval; \ sl@0: } sl@0: sl@0: #define GET_SYNCOBJ_RETURN_IF_ERR(drv, display, sync, handle, retval) \ sl@0: CEglSync* sync = display->FindSyncObj(handle); \ sl@0: if (!sync) \ sl@0: { \ sl@0: drv.Unlock(); \ sl@0: SetError(EGL_BAD_PARAMETER); \ sl@0: return retval; \ sl@0: } \ sl@0: if (sync->IsDestroyed()) /* sync obj has been marked as destroyed */ \ sl@0: { \ sl@0: drv.Unlock(); \ sl@0: SetError(EGL_BAD_PARAMETER); \ sl@0: return retval; \ sl@0: } sl@0: sl@0: CEglThreadSession::CEglThreadSession(CEglDriver& aDriver): sl@0: iDriver(aDriver), sl@0: iError(EGL_SUCCESS) sl@0: { sl@0: } sl@0: sl@0: CEglThreadSession::~CEglThreadSession() sl@0: { sl@0: CEglDriver::Close(); sl@0: } sl@0: sl@0: CEglThreadSession* CEglThreadSession::Static() sl@0: { sl@0: CEglThreadSession* es = reinterpret_cast(Dll::Tls()); sl@0: if (es) sl@0: { sl@0: return es; sl@0: } sl@0: sl@0: const TInt err = CEglDriver::Open(); sl@0: if (err != KErrNone) sl@0: { sl@0: return NULL; sl@0: } sl@0: sl@0: // CEglDriver is reference counted. As we successfuly open the driver, pls.iDriver will be non-null sl@0: // and it should be safe to cache the pointer inside CEglThreadSession sl@0: CEglDriver* drv = CEglDriver::GetDriver(); sl@0: __ASSERT_DEBUG(drv, User::Panic(KEglPanicCategory, EEglPanicDriverNull)); sl@0: sl@0: // create session object on default thread's heap sl@0: es = new CEglThreadSession(*drv); sl@0: if (!es || Dll::SetTls(es)!= KErrNone) sl@0: { sl@0: delete es; sl@0: return NULL; sl@0: } sl@0: sl@0: return es; sl@0: } sl@0: sl@0: void CEglThreadSession::SetError(EGLint aError) sl@0: { sl@0: // EGL spec section 3.1, GetError will return the status of the most recent EGL function call sl@0: // so we will always override the error status sl@0: iError = aError; sl@0: } sl@0: sl@0: EGLint CEglThreadSession::EglGetError() sl@0: { sl@0: // eglGetError always succeed so it will set error state to EGL_SUCCESS sl@0: const EGLint lastError = iError; sl@0: iError = EGL_SUCCESS; sl@0: return lastError; sl@0: } sl@0: sl@0: EGLDisplay CEglThreadSession::EglGetDisplay(NativeDisplayType aDisplayId) sl@0: { sl@0: // EGL spec section 3.2: we do not need to raise EGL error when GetDisplay fails sl@0: SetError(EGL_SUCCESS); sl@0: sl@0: if (aDisplayId != EGL_DEFAULT_DISPLAY) sl@0: { sl@0: return EGL_NO_DISPLAY; sl@0: } sl@0: sl@0: // default display is created when driver is initialised the first time and will sl@0: // be destroyed when all threads within process have called eglReleaseThread sl@0: sl@0: return KEglDefaultDisplayHandle; sl@0: } sl@0: sl@0: EGLBoolean CEglThreadSession::EglInitialize(EGLDisplay aDisplay, EGLint* aMajor, EGLint* aMinor) sl@0: { sl@0: SetError(EGL_SUCCESS); sl@0: sl@0: CHECK_FOR_NULL_DISPLAY(aDisplay, EGL_FALSE) sl@0: sl@0: iDriver.Lock(); sl@0: CEglDisplay* display = iDriver.FindDisplay(aDisplay); sl@0: if (!display) sl@0: { sl@0: iDriver.Unlock(); sl@0: SetError(EGL_BAD_DISPLAY); sl@0: return EGL_FALSE; sl@0: } sl@0: sl@0: const TInt err = display->Initialize(); sl@0: iDriver.Unlock(); sl@0: sl@0: if (err != KErrNone) sl@0: { sl@0: SetError(EGL_NOT_INITIALIZED); sl@0: return EGL_FALSE; sl@0: } sl@0: sl@0: if (aMajor) sl@0: { sl@0: *aMajor = KEglMajorVersion; sl@0: } sl@0: if (aMinor) sl@0: { sl@0: *aMinor = KEglMinorVersion; sl@0: } sl@0: sl@0: return EGL_TRUE; sl@0: } sl@0: sl@0: EGLBoolean CEglThreadSession::EglTerminate(EGLDisplay aDisplay) sl@0: { sl@0: SetError(EGL_SUCCESS); sl@0: sl@0: CHECK_FOR_NULL_DISPLAY(aDisplay, EGL_FALSE) sl@0: sl@0: iDriver.Lock(); sl@0: CEglDisplay* display = iDriver.FindDisplay(aDisplay); sl@0: if (!display) sl@0: { sl@0: iDriver.Unlock(); sl@0: SetError(EGL_BAD_DISPLAY); sl@0: return EGL_FALSE; sl@0: } sl@0: sl@0: display->Terminate(); sl@0: iDriver.Unlock(); sl@0: sl@0: return EGL_TRUE; sl@0: } sl@0: sl@0: TFuncPtrEglProc CEglThreadSession::EglGetProcAddress(const char* aName) sl@0: { sl@0: SetError(EGL_SUCCESS); sl@0: sl@0: if(!aName) sl@0: { sl@0: return NULL; sl@0: } sl@0: sl@0: // EGL spec does not mention about raising error if requested function not found sl@0: // This implementation does not set error and leave thread state unmodified sl@0: return iDriver.GetProcAddress(aName); sl@0: } sl@0: sl@0: const char* CEglThreadSession::EglQueryString(EGLDisplay aDisplay, EGLint aName) sl@0: { sl@0: SetError(EGL_SUCCESS); sl@0: sl@0: const char* str = NULL; sl@0: sl@0: CHECK_FOR_NULL_DISPLAY(aDisplay, str) sl@0: sl@0: iDriver.Lock(); sl@0: GET_DISPLAY_RETURN_IF_ERR(iDriver, display, aDisplay, str) sl@0: iDriver.Unlock(); sl@0: sl@0: switch (aName) sl@0: { sl@0: case EGL_CLIENT_APIS: sl@0: str = KEglClientApis; sl@0: break; sl@0: case EGL_EXTENSIONS: sl@0: str = KEglExtensions; sl@0: break; sl@0: case EGL_VENDOR: sl@0: str = KEglVendor; sl@0: break; sl@0: case EGL_VERSION: sl@0: str = KEglVersion; sl@0: break; sl@0: default: sl@0: SetError(EGL_BAD_PARAMETER); sl@0: break; sl@0: } sl@0: sl@0: return str; sl@0: } sl@0: sl@0: EGLSyncKHR CEglThreadSession::EglCreateSyncKhr(EGLDisplay aDisplay, EGLenum aType, const EGLint *aAttribList) sl@0: { sl@0: SetError(EGL_SUCCESS); sl@0: sl@0: CHECK_FOR_NULL_DISPLAY(aDisplay, EGL_NO_SYNC_KHR) sl@0: sl@0: if (aType != EGL_SYNC_REUSABLE_KHR || (aAttribList && *aAttribList != EGL_NONE)) sl@0: { sl@0: SetError(EGL_BAD_ATTRIBUTE); sl@0: return EGL_NO_SYNC_KHR; sl@0: } sl@0: sl@0: iDriver.Lock(); sl@0: GET_DISPLAY_RETURN_IF_ERR(iDriver, display, aDisplay, EGL_NO_SYNC_KHR) sl@0: sl@0: CEglSync* syncObj = display->CreateSyncObj(); sl@0: iDriver.Unlock(); sl@0: sl@0: if (!syncObj) sl@0: { sl@0: SetError(EGL_BAD_ALLOC); sl@0: return EGL_NO_SYNC_KHR; sl@0: } sl@0: sl@0: return reinterpret_cast(syncObj); sl@0: } sl@0: sl@0: EGLBoolean CEglThreadSession::EglDestroySyncKhr(EGLDisplay aDisplay, EGLSyncKHR aSync) sl@0: { sl@0: SetError(EGL_SUCCESS); sl@0: sl@0: CHECK_FOR_NULL_DISPLAY(aDisplay, EGL_FALSE) sl@0: CHECK_FOR_NULL_SYNCOBJ(aSync, EGL_FALSE) sl@0: sl@0: iDriver.Lock(); sl@0: GET_DISPLAY_RETURN_IF_ERR(iDriver, display, aDisplay, EGL_FALSE) sl@0: sl@0: const TInt err = display->DestroySyncObj(aSync); sl@0: iDriver.Unlock(); sl@0: sl@0: if (err != KErrNone) sl@0: { sl@0: SetError(EGL_BAD_PARAMETER); sl@0: return EGL_FALSE; sl@0: } sl@0: sl@0: return EGL_TRUE; sl@0: } sl@0: sl@0: EGLint CEglThreadSession::EglClientWaitSyncKhr(EGLDisplay aDisplay, EGLSyncKHR aSync, EGLint aFlags, EGLTimeKHR aTimeout) sl@0: { sl@0: SetError(EGL_SUCCESS); sl@0: sl@0: CHECK_FOR_NULL_DISPLAY(aDisplay, EGL_FALSE) sl@0: CHECK_FOR_NULL_SYNCOBJ(aSync, EGL_FALSE) sl@0: sl@0: const EGLint supportedFlags = EGL_SYNC_FLUSH_COMMANDS_BIT_KHR; sl@0: if (aFlags & ~supportedFlags) sl@0: { sl@0: SetError(EGL_BAD_PARAMETER); sl@0: return EGL_FALSE; sl@0: } sl@0: sl@0: iDriver.Lock(); sl@0: GET_DISPLAY_RETURN_IF_ERR(iDriver, display, aDisplay, EGL_FALSE) sl@0: GET_SYNCOBJ_RETURN_IF_ERR(iDriver, display, syncObj, aSync, EGL_FALSE) sl@0: sl@0: // increment refcount to mark this sync obj in use and prevent it from being destroyed when other thread calls eglDestroySyncKHR or eglTerminate sl@0: syncObj->Open(); sl@0: sl@0: // release display lock as we're going to wait on sync object after this point, not releasing display lock at this sl@0: // point will cause deadlock sl@0: // coverity[stale] sl@0: iDriver.Unlock(); sl@0: sl@0: // sync obj refcount has been incremented so it won't get destroyed even if other thread call eglDestroySyncKHR or eglTerminate sl@0: // at this point sl@0: sl@0: // we do not support client apis, so flushing flags will be ignored in this implementation sl@0: EGLint err = syncObj->Wait(aTimeout); sl@0: sl@0: // decrement refcount sl@0: // sync obj will be destroyted if refcount is 0 e.g. other thread issues eglDestroySyncKHR or eglTerminate while this thread sl@0: // is waiting on it sl@0: iDriver.Lock(); sl@0: syncObj->Close(); sl@0: iDriver.Unlock(); sl@0: sl@0: // we do not check error here as it is passed back to caller sl@0: sl@0: return err; sl@0: } sl@0: sl@0: EGLBoolean CEglThreadSession::EglSignalSyncKhr(EGLDisplay aDisplay, EGLSyncKHR aSync, EGLenum aMode) sl@0: { sl@0: const EGLint err = EglSignalSyncInternal(aDisplay, aSync, aMode); sl@0: SetError(err); sl@0: return err == EGL_SUCCESS; sl@0: } sl@0: sl@0: EGLint CEglThreadSession::EglSignalSyncInternal(EGLDisplay aDisplay, EGLSyncKHR aSync, EGLenum aMode) sl@0: { sl@0: if (aDisplay == EGL_NO_DISPLAY) sl@0: { sl@0: return EGL_BAD_DISPLAY; sl@0: } sl@0: if (aSync == EGL_NO_SYNC_KHR) sl@0: { sl@0: return EGL_BAD_PARAMETER; sl@0: } sl@0: if (aMode != EGL_SIGNALED_KHR && aMode != EGL_UNSIGNALED_KHR) sl@0: { sl@0: return EGL_BAD_PARAMETER; sl@0: } sl@0: sl@0: iDriver.Lock(); sl@0: sl@0: CEglDisplay* display = iDriver.FindDisplay(aDisplay); sl@0: if (!display) sl@0: { sl@0: iDriver.Unlock(); sl@0: return EGL_BAD_DISPLAY; sl@0: } sl@0: if (!display->IsInitialized()) sl@0: { sl@0: iDriver.Unlock(); sl@0: return EGL_NOT_INITIALIZED; sl@0: } sl@0: sl@0: CEglSync* syncObj = display->FindSyncObj(aSync); sl@0: if (!syncObj) sl@0: { sl@0: iDriver.Unlock(); sl@0: return EGL_BAD_PARAMETER; sl@0: } sl@0: if (syncObj->Type() != EGL_SYNC_REUSABLE_KHR) sl@0: { sl@0: iDriver.Unlock(); sl@0: return EGL_BAD_MATCH; sl@0: } sl@0: if (syncObj->IsDestroyed()) /* sync obj has been marked as destroyed */ sl@0: { sl@0: iDriver.Unlock(); sl@0: return EGL_BAD_PARAMETER; sl@0: } sl@0: sl@0: syncObj->Signal(aMode); sl@0: iDriver.Unlock(); sl@0: sl@0: return EGL_SUCCESS; sl@0: } sl@0: sl@0: EGLBoolean CEglThreadSession::EglGetSyncAttribKhr(EGLDisplay aDisplay, EGLSyncKHR aSync, EGLint aAttribute, EGLint *aValue) sl@0: { sl@0: SetError(EGL_SUCCESS); sl@0: sl@0: CHECK_FOR_NULL_DISPLAY(aDisplay, EGL_FALSE) sl@0: CHECK_FOR_NULL_SYNCOBJ(aSync, EGL_FALSE) sl@0: sl@0: if (aAttribute != EGL_SYNC_TYPE_KHR && aAttribute != EGL_SYNC_STATUS_KHR) sl@0: { sl@0: SetError(EGL_BAD_ATTRIBUTE); sl@0: return EGL_FALSE; sl@0: } sl@0: sl@0: if (!aValue) sl@0: { sl@0: SetError(EGL_BAD_PARAMETER); sl@0: return EGL_FALSE; sl@0: } sl@0: sl@0: iDriver.Lock(); sl@0: sl@0: GET_DISPLAY_RETURN_IF_ERR(iDriver, display, aDisplay, EGL_FALSE) sl@0: GET_SYNCOBJ_RETURN_IF_ERR(iDriver, display, syncObj, aSync, EGL_FALSE) sl@0: sl@0: if (syncObj->Type() != EGL_SYNC_REUSABLE_KHR) sl@0: { sl@0: iDriver.Unlock(); sl@0: SetError(EGL_BAD_MATCH); sl@0: return EGL_FALSE; sl@0: } sl@0: sl@0: switch (aAttribute) sl@0: { sl@0: case EGL_SYNC_TYPE_KHR: sl@0: *aValue = syncObj->Type(); sl@0: break; sl@0: sl@0: case EGL_SYNC_STATUS_KHR: sl@0: *aValue = syncObj->Status(); sl@0: break; sl@0: } sl@0: sl@0: iDriver.Unlock(); sl@0: sl@0: return EGL_TRUE; sl@0: } sl@0: sl@0: #ifdef _DEBUG sl@0: void CEglThreadSession::EglHeapMarkStart() sl@0: { sl@0: iDriver.Lock(); sl@0: iDriver.Heap().__DbgMarkStart(); sl@0: iDriver.Unlock(); sl@0: } sl@0: sl@0: EGLint CEglThreadSession::EglHeapMarkEnd(EGLint aCount) sl@0: { sl@0: iDriver.Lock(); sl@0: const TInt cell = iDriver.Heap().__DbgMarkEnd(aCount); sl@0: iDriver.Unlock(); sl@0: sl@0: return cell; sl@0: } sl@0: sl@0: void CEglThreadSession::EglHeapSetBurstAllocFail(EGLenum aType, EGLint aRate, EGLint aBurst) sl@0: { sl@0: iDriver.Lock(); sl@0: iDriver.Heap().__DbgSetBurstAllocFail(static_cast(aType), aRate, aBurst); sl@0: iDriver.Unlock(); sl@0: } sl@0: sl@0: #endif //_DEBUG