egl/eglrefimpl/src/session.cpp
changeset 0 5d03bc08d59c
child 57 2bf8a359aa2f
child 160 969102054596
--- /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<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;
+    }
+
+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<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