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: CEglSync::CEglSync(CEglDisplay& aDisplay): sl@0: iDisplay(aDisplay), sl@0: iType(EGL_SYNC_REUSABLE_KHR), sl@0: iStatus(EGL_UNSIGNALED_KHR) sl@0: { sl@0: } sl@0: sl@0: CEglSync::~CEglSync() sl@0: { sl@0: iCondVar.Close(); sl@0: iMutex.Close(); sl@0: } sl@0: sl@0: TInt CEglSync::Construct() sl@0: { sl@0: TInt err = iMutex.CreateLocal(); sl@0: if (err != KErrNone) sl@0: { sl@0: return err; sl@0: } sl@0: sl@0: err = iCondVar.CreateLocal(); sl@0: if (err != KErrNone) sl@0: { sl@0: return err; sl@0: } sl@0: sl@0: err = iDisplay.RegisterSyncObj(*this); sl@0: if (err != KErrNone) sl@0: { sl@0: return err; sl@0: } sl@0: sl@0: iRefCount = 1; sl@0: return KErrNone; sl@0: } sl@0: sl@0: CEglSync* CEglSync::Create(CEglDisplay& aDisplay) sl@0: { sl@0: // sync object will be allocated in the EGL shared heap and added to sync object list sl@0: // we need to switch current heap to EGL shared heap sl@0: // sl@0: RHeap* callerHeap = User::SwitchHeap(&aDisplay.Heap()); sl@0: sl@0: CEglSync* syncObj = new CEglSync(aDisplay); sl@0: if (!syncObj) sl@0: { sl@0: User::SwitchHeap(callerHeap); sl@0: return NULL; sl@0: } sl@0: sl@0: const TInt err = syncObj->Construct(); sl@0: if (err != KErrNone) sl@0: { sl@0: delete syncObj; sl@0: User::SwitchHeap(callerHeap); sl@0: return NULL; sl@0: } sl@0: sl@0: User::SwitchHeap(callerHeap); sl@0: return syncObj; sl@0: } sl@0: sl@0: void CEglSync::Destroy() sl@0: { sl@0: // multiple calls to Destroy() is not allowed, it's either coming from eglDestroySyncKHR or eglTerminate sl@0: // sl@0: __ASSERT_DEBUG(!iIsDestroyed, User::Panic(KEglPanicCategory, EEglPanicSyncObjHasBeenDestroyed)); sl@0: sl@0: iIsDestroyed = ETrue; sl@0: sl@0: // wake up all waiting threads sl@0: iCondVar.Broadcast(); sl@0: sl@0: // always remove sync obj from hash map when it is destroyed, the actual deletion will be done from Close(), sl@0: // which can happen when eglClientWaitSyncKHR is called by user sl@0: RHeap* callerHeap = User::SwitchHeap(&iDisplay.Heap()); sl@0: iDisplay.UnregisterSyncObj(*this); sl@0: User::SwitchHeap(callerHeap); sl@0: sl@0: // decrement refcount for this sync obj, it will delete the object if refcount is zero sl@0: Close(); sl@0: } sl@0: sl@0: void CEglSync::Close() sl@0: { sl@0: if (--iRefCount == 0) sl@0: { sl@0: // we're here either from Destroy() or eglClientWaitSyncKHR sl@0: RHeap* callerHeap = User::SwitchHeap(&iDisplay.Heap()); sl@0: delete this; sl@0: User::SwitchHeap(callerHeap); sl@0: } sl@0: } sl@0: sl@0: void CEglSync::Signal(EGLenum aMode) sl@0: { sl@0: iMutex.Wait(); sl@0: if (iStatus != aMode) sl@0: { sl@0: iStatus = aMode; sl@0: if (iStatus == EGL_SIGNALED_KHR) sl@0: { sl@0: iCondVar.Broadcast(); sl@0: } sl@0: } sl@0: iMutex.Signal(); sl@0: } sl@0: sl@0: EGLint CEglSync::Wait(EGLTimeKHR aTimeOut) sl@0: { sl@0: // driver display lock is not held when we're about to enter block wait on condition variable sl@0: // we use sync object mutex to synchronise threads access from this point until end of this function sl@0: iMutex.Wait(); sl@0: EGLint errCode = EGL_CONDITION_SATISFIED_KHR; sl@0: sl@0: if (iStatus == EGL_UNSIGNALED_KHR) sl@0: { sl@0: switch(aTimeOut) sl@0: { sl@0: case EGL_FOREVER_KHR: sl@0: { sl@0: const TInt res = iCondVar.Wait(iMutex); sl@0: //we do not expect to fail here sl@0: __ASSERT_DEBUG(res == KErrNone, User::Panic(KEglPanicCategory, EEglPanicCondVarWaitFail)); sl@0: break; sl@0: } sl@0: case 0: sl@0: { sl@0: //by setting this we notify the caller that the sync object is in unsignaled state sl@0: errCode = EGL_TIMEOUT_EXPIRED_KHR; sl@0: break; sl@0: } sl@0: default: sl@0: { sl@0: // Since the supported range of timeout at function RCondVar::TimedWait(mutex, timeout) sl@0: // is 0 to KMaxTInt, looping mechanism below is used to support 64bit timeout. sl@0: // sl@0: TInt res = KErrTimedOut; sl@0: for(TInt64 timeoutMicroseconds = aTimeOut/1000; (res == KErrTimedOut) && (timeoutMicroseconds > 0); timeoutMicroseconds -= KMaxTInt) sl@0: { sl@0: res = iCondVar.TimedWait(iMutex, (timeoutMicroseconds > KMaxTInt?KMaxTInt:timeoutMicroseconds)); sl@0: //we do not expect to fail here sl@0: __ASSERT_DEBUG(res == KErrNone || res == KErrTimedOut, User::Panic(KEglPanicCategory, EEglPanicCondVarTimedWaitFail)); sl@0: } sl@0: if(res == KErrTimedOut) sl@0: { sl@0: errCode = EGL_TIMEOUT_EXPIRED_KHR; sl@0: } sl@0: break; sl@0: } sl@0: } sl@0: } sl@0: sl@0: iMutex.Signal(); sl@0: return errCode; sl@0: }