|         |      1 // Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). | 
|         |      2 // All rights reserved. | 
|         |      3 // This component and the accompanying materials are made available | 
|         |      4 // under the terms of "Eclipse Public License v1.0" | 
|         |      5 // which accompanies this distribution, and is available | 
|         |      6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". | 
|         |      7 // | 
|         |      8 // Initial Contributors: | 
|         |      9 // Nokia Corporation - initial contribution. | 
|         |     10 // | 
|         |     11 // Contributors: | 
|         |     12 // | 
|         |     13 // Description: | 
|         |     14 // Reference EGL implementation to support EGL sync objects and OpenWF extensions | 
|         |     15  | 
|         |     16 #include "eglprivate.h" | 
|         |     17  | 
|         |     18 const TInt KEglMajorVersion = 1; | 
|         |     19 const TInt KEglMinorVersion = 4; | 
|         |     20  | 
|         |     21 #define KEglClientApis  "" | 
|         |     22 #define KEglVendor      "Nokia" | 
|         |     23 #define KEglVersion     "1.4 Reference EGL" | 
|         |     24 #define KEglExtensions  "EGL_KHR_reusable_sync" /* additonal extensions should be added beginning with a space */ \ | 
|         |     25                         " EGL_NOK__private__signal_sync" | 
|         |     26  | 
|         |     27 // Helper macros for repetitive task | 
|         |     28 // | 
|         |     29 #define CHECK_FOR_NULL_DISPLAY(handle, retval) \ | 
|         |     30     if (handle == EGL_NO_DISPLAY) \ | 
|         |     31         { \ | 
|         |     32         SetError(EGL_BAD_DISPLAY); \ | 
|         |     33         return retval; \ | 
|         |     34         } | 
|         |     35  | 
|         |     36 #define CHECK_FOR_NULL_SYNCOBJ(handle, retval) \ | 
|         |     37     if (handle == EGL_NO_SYNC_KHR) \ | 
|         |     38         { \ | 
|         |     39         SetError(EGL_BAD_PARAMETER); \ | 
|         |     40         return retval; \ | 
|         |     41         } | 
|         |     42  | 
|         |     43 #define GET_DISPLAY_RETURN_IF_ERR(drv, display, handle, retval) \ | 
|         |     44     CEglDisplay* display = iDriver.FindDisplay(handle); \ | 
|         |     45     if (!display) \ | 
|         |     46         { \ | 
|         |     47         drv.Unlock(); \ | 
|         |     48         SetError(EGL_BAD_DISPLAY); \ | 
|         |     49         return retval; \ | 
|         |     50         } \ | 
|         |     51     if (!display->IsInitialized()) \ | 
|         |     52         { \ | 
|         |     53         drv.Unlock(); \ | 
|         |     54         SetError(EGL_NOT_INITIALIZED); \ | 
|         |     55         return retval; \ | 
|         |     56         } | 
|         |     57  | 
|         |     58 #define GET_SYNCOBJ_RETURN_IF_ERR(drv, display, sync, handle, retval) \ | 
|         |     59     CEglSync* sync = display->FindSyncObj(handle); \ | 
|         |     60     if (!sync) \ | 
|         |     61         { \ | 
|         |     62         drv.Unlock(); \ | 
|         |     63         SetError(EGL_BAD_PARAMETER); \ | 
|         |     64         return retval; \ | 
|         |     65         } \ | 
|         |     66     if (sync->IsDestroyed()) /* sync obj has been marked as destroyed */ \ | 
|         |     67         { \ | 
|         |     68         drv.Unlock(); \ | 
|         |     69         SetError(EGL_BAD_PARAMETER); \ | 
|         |     70         return retval; \ | 
|         |     71         } | 
|         |     72                                                                  | 
|         |     73 CEglThreadSession::CEglThreadSession(CEglDriver& aDriver): | 
|         |     74 	iDriver(aDriver), | 
|         |     75 	iError(EGL_SUCCESS) | 
|         |     76 	{ | 
|         |     77 	} | 
|         |     78  | 
|         |     79 CEglThreadSession::~CEglThreadSession() | 
|         |     80 	{ | 
|         |     81 	CEglDriver::Close(); | 
|         |     82 	} | 
|         |     83  | 
|         |     84 CEglThreadSession* CEglThreadSession::Static() | 
|         |     85 	{ | 
|         |     86 	CEglThreadSession* es = reinterpret_cast<CEglThreadSession*>(Dll::Tls()); | 
|         |     87 	if (es) | 
|         |     88 		{ | 
|         |     89 		return es; | 
|         |     90 		} | 
|         |     91  | 
|         |     92 	const TInt err = CEglDriver::Open(); | 
|         |     93 	if (err != KErrNone) | 
|         |     94 		{ | 
|         |     95 		return NULL; | 
|         |     96 		} | 
|         |     97  | 
|         |     98 	// CEglDriver is reference counted. As we successfuly open the driver, pls.iDriver will be non-null | 
|         |     99 	// and it should be safe to cache the pointer inside CEglThreadSession | 
|         |    100 	CEglDriver* drv = CEglDriver::GetDriver(); | 
|         |    101 	__ASSERT_DEBUG(drv, User::Panic(KEglPanicCategory, EEglPanicDriverNull)); | 
|         |    102  | 
|         |    103 	// create session object on default thread's heap | 
|         |    104 	es = new CEglThreadSession(*drv); | 
|         |    105 	if (!es || Dll::SetTls(es)!= KErrNone) | 
|         |    106 		{ | 
|         |    107 		delete es; | 
|         |    108 		return NULL; | 
|         |    109 		} | 
|         |    110 	 | 
|         |    111 	return es; | 
|         |    112 	} | 
|         |    113  | 
|         |    114 void CEglThreadSession::SetError(EGLint aError) | 
|         |    115 	{ | 
|         |    116 	// EGL spec section 3.1, GetError will return the status of the most recent EGL function call | 
|         |    117 	// so we will always override the error status | 
|         |    118 	iError = aError; | 
|         |    119 	} | 
|         |    120  | 
|         |    121 EGLint CEglThreadSession::EglGetError() | 
|         |    122 	{ | 
|         |    123 	// eglGetError always succeed so it will set error state to EGL_SUCCESS | 
|         |    124 	const EGLint lastError = iError; | 
|         |    125 	iError = EGL_SUCCESS; | 
|         |    126 	return lastError; | 
|         |    127 	} | 
|         |    128  | 
|         |    129 EGLDisplay CEglThreadSession::EglGetDisplay(NativeDisplayType aDisplayId) | 
|         |    130     { | 
|         |    131     // EGL spec section 3.2: we do not need to raise EGL error when GetDisplay fails | 
|         |    132     SetError(EGL_SUCCESS); | 
|         |    133  | 
|         |    134     if (aDisplayId != EGL_DEFAULT_DISPLAY) | 
|         |    135         { | 
|         |    136         return EGL_NO_DISPLAY; | 
|         |    137         } | 
|         |    138  | 
|         |    139     // default display is created when driver is initialised the first time and will | 
|         |    140     // be destroyed when all threads within process have called eglReleaseThread | 
|         |    141  | 
|         |    142     return KEglDefaultDisplayHandle; | 
|         |    143     } | 
|         |    144  | 
|         |    145 EGLBoolean CEglThreadSession::EglInitialize(EGLDisplay aDisplay, EGLint* aMajor, EGLint* aMinor) | 
|         |    146     { | 
|         |    147     SetError(EGL_SUCCESS); | 
|         |    148      | 
|         |    149     CHECK_FOR_NULL_DISPLAY(aDisplay, EGL_FALSE) | 
|         |    150  | 
|         |    151     iDriver.Lock(); | 
|         |    152     CEglDisplay* display = iDriver.FindDisplay(aDisplay); | 
|         |    153     if (!display) | 
|         |    154         { | 
|         |    155         iDriver.Unlock(); | 
|         |    156         SetError(EGL_BAD_DISPLAY); | 
|         |    157         return EGL_FALSE; | 
|         |    158         } | 
|         |    159  | 
|         |    160     const TInt err = display->Initialize(); | 
|         |    161     iDriver.Unlock(); | 
|         |    162      | 
|         |    163     if (err != KErrNone) | 
|         |    164         { | 
|         |    165         SetError(EGL_NOT_INITIALIZED); | 
|         |    166         return EGL_FALSE; | 
|         |    167         } | 
|         |    168  | 
|         |    169     if (aMajor) | 
|         |    170         { | 
|         |    171         *aMajor = KEglMajorVersion; | 
|         |    172         } | 
|         |    173     if (aMinor) | 
|         |    174         { | 
|         |    175         *aMinor = KEglMinorVersion; | 
|         |    176         } | 
|         |    177  | 
|         |    178     return EGL_TRUE; | 
|         |    179     } | 
|         |    180  | 
|         |    181 EGLBoolean CEglThreadSession::EglTerminate(EGLDisplay aDisplay) | 
|         |    182     { | 
|         |    183     SetError(EGL_SUCCESS); | 
|         |    184      | 
|         |    185     CHECK_FOR_NULL_DISPLAY(aDisplay, EGL_FALSE) | 
|         |    186  | 
|         |    187     iDriver.Lock(); | 
|         |    188     CEglDisplay* display = iDriver.FindDisplay(aDisplay); | 
|         |    189     if (!display) | 
|         |    190         { | 
|         |    191         iDriver.Unlock(); | 
|         |    192         SetError(EGL_BAD_DISPLAY); | 
|         |    193         return EGL_FALSE; | 
|         |    194         } | 
|         |    195  | 
|         |    196     display->Terminate(); | 
|         |    197     iDriver.Unlock(); | 
|         |    198      | 
|         |    199     return EGL_TRUE; | 
|         |    200     } | 
|         |    201  | 
|         |    202 TFuncPtrEglProc CEglThreadSession::EglGetProcAddress(const char* aName) | 
|         |    203     { | 
|         |    204     SetError(EGL_SUCCESS); | 
|         |    205          | 
|         |    206     if(!aName) | 
|         |    207         { | 
|         |    208         return NULL; | 
|         |    209         } | 
|         |    210      | 
|         |    211     // EGL spec does not mention about raising error if requested function not found | 
|         |    212     // This implementation does not set error and leave thread state unmodified | 
|         |    213     return iDriver.GetProcAddress(aName); | 
|         |    214     } | 
|         |    215  | 
|         |    216 const char* CEglThreadSession::EglQueryString(EGLDisplay aDisplay, EGLint aName) | 
|         |    217     { | 
|         |    218     SetError(EGL_SUCCESS); | 
|         |    219      | 
|         |    220     const char* str = NULL; | 
|         |    221  | 
|         |    222     CHECK_FOR_NULL_DISPLAY(aDisplay, str) | 
|         |    223  | 
|         |    224     iDriver.Lock(); | 
|         |    225     GET_DISPLAY_RETURN_IF_ERR(iDriver, display, aDisplay, str) | 
|         |    226     iDriver.Unlock(); | 
|         |    227  | 
|         |    228     switch (aName) | 
|         |    229         { | 
|         |    230         case EGL_CLIENT_APIS: | 
|         |    231             str = KEglClientApis; | 
|         |    232             break; | 
|         |    233         case EGL_EXTENSIONS: | 
|         |    234             str = KEglExtensions; | 
|         |    235             break; | 
|         |    236         case EGL_VENDOR: | 
|         |    237             str = KEglVendor; | 
|         |    238             break; | 
|         |    239         case EGL_VERSION: | 
|         |    240             str = KEglVersion; | 
|         |    241             break; | 
|         |    242         default: | 
|         |    243             SetError(EGL_BAD_PARAMETER); | 
|         |    244             break; | 
|         |    245         } | 
|         |    246  | 
|         |    247     return str; | 
|         |    248     } | 
|         |    249  | 
|         |    250 EGLSyncKHR CEglThreadSession::EglCreateSyncKhr(EGLDisplay aDisplay, EGLenum aType, const EGLint *aAttribList) | 
|         |    251     { | 
|         |    252     SetError(EGL_SUCCESS); | 
|         |    253      | 
|         |    254     CHECK_FOR_NULL_DISPLAY(aDisplay, EGL_NO_SYNC_KHR) | 
|         |    255  | 
|         |    256     if (aType != EGL_SYNC_REUSABLE_KHR || (aAttribList && *aAttribList != EGL_NONE)) | 
|         |    257         { | 
|         |    258         SetError(EGL_BAD_ATTRIBUTE); | 
|         |    259         return EGL_NO_SYNC_KHR; | 
|         |    260         } | 
|         |    261      | 
|         |    262     iDriver.Lock(); | 
|         |    263     GET_DISPLAY_RETURN_IF_ERR(iDriver, display, aDisplay, EGL_NO_SYNC_KHR) | 
|         |    264      | 
|         |    265     CEglSync* syncObj = display->CreateSyncObj(); | 
|         |    266     iDriver.Unlock(); | 
|         |    267      | 
|         |    268     if (!syncObj) | 
|         |    269         { | 
|         |    270         SetError(EGL_BAD_ALLOC); | 
|         |    271         return EGL_NO_SYNC_KHR; | 
|         |    272         } | 
|         |    273  | 
|         |    274     return reinterpret_cast<EGLSyncKHR>(syncObj); | 
|         |    275     } | 
|         |    276  | 
|         |    277 EGLBoolean CEglThreadSession::EglDestroySyncKhr(EGLDisplay aDisplay, EGLSyncKHR aSync) | 
|         |    278     { | 
|         |    279     SetError(EGL_SUCCESS); | 
|         |    280      | 
|         |    281     CHECK_FOR_NULL_DISPLAY(aDisplay, EGL_FALSE) | 
|         |    282     CHECK_FOR_NULL_SYNCOBJ(aSync, EGL_FALSE) | 
|         |    283  | 
|         |    284     iDriver.Lock(); | 
|         |    285     GET_DISPLAY_RETURN_IF_ERR(iDriver, display, aDisplay, EGL_FALSE) | 
|         |    286      | 
|         |    287     const TInt err = display->DestroySyncObj(aSync); | 
|         |    288     iDriver.Unlock(); | 
|         |    289  | 
|         |    290     if (err != KErrNone) | 
|         |    291         { | 
|         |    292         SetError(EGL_BAD_PARAMETER); | 
|         |    293         return EGL_FALSE; | 
|         |    294         } | 
|         |    295  | 
|         |    296     return EGL_TRUE; | 
|         |    297     } | 
|         |    298  | 
|         |    299 EGLint CEglThreadSession::EglClientWaitSyncKhr(EGLDisplay aDisplay, EGLSyncKHR aSync, EGLint aFlags, EGLTimeKHR aTimeout) | 
|         |    300     { | 
|         |    301     SetError(EGL_SUCCESS); | 
|         |    302      | 
|         |    303     CHECK_FOR_NULL_DISPLAY(aDisplay, EGL_FALSE) | 
|         |    304     CHECK_FOR_NULL_SYNCOBJ(aSync, EGL_FALSE) | 
|         |    305      | 
|         |    306     const EGLint supportedFlags = EGL_SYNC_FLUSH_COMMANDS_BIT_KHR; | 
|         |    307     if (aFlags & ~supportedFlags) | 
|         |    308         { | 
|         |    309         SetError(EGL_BAD_PARAMETER); | 
|         |    310         return EGL_FALSE; | 
|         |    311         } | 
|         |    312      | 
|         |    313     iDriver.Lock(); | 
|         |    314     GET_DISPLAY_RETURN_IF_ERR(iDriver, display, aDisplay, EGL_FALSE) | 
|         |    315     GET_SYNCOBJ_RETURN_IF_ERR(iDriver, display, syncObj, aSync, EGL_FALSE) | 
|         |    316  | 
|         |    317     // increment refcount to mark this sync obj in use and prevent it from being destroyed when other thread calls eglDestroySyncKHR or eglTerminate | 
|         |    318     syncObj->Open(); | 
|         |    319      | 
|         |    320     // release display lock as we're going to wait on sync object after this point, not releasing display lock at this  | 
|         |    321     // point will cause deadlock | 
|         |    322     iDriver.Unlock(); | 
|         |    323  | 
|         |    324     // sync obj refcount has been incremented so it won't get destroyed even if other thread call eglDestroySyncKHR or eglTerminate | 
|         |    325     // at this point | 
|         |    326  | 
|         |    327     // we do not support client apis, so flushing flags will be ignored in this implementation | 
|         |    328     EGLint err = syncObj->Wait(aTimeout); | 
|         |    329  | 
|         |    330     // decrement refcount | 
|         |    331     // sync obj will be destroyted if refcount is 0 e.g. other thread issues eglDestroySyncKHR or eglTerminate while this thread | 
|         |    332     // is waiting on it | 
|         |    333     iDriver.Lock(); | 
|         |    334     syncObj->Close(); | 
|         |    335     iDriver.Unlock(); | 
|         |    336  | 
|         |    337     // we do not check error here as it is passed back to caller | 
|         |    338  | 
|         |    339     return err; | 
|         |    340     } | 
|         |    341  | 
|         |    342 EGLBoolean CEglThreadSession::EglSignalSyncKhr(EGLDisplay aDisplay, EGLSyncKHR aSync, EGLenum aMode) | 
|         |    343     { | 
|         |    344     const EGLint err = EglSignalSyncInternal(aDisplay, aSync, aMode); | 
|         |    345     SetError(err); | 
|         |    346     return err == EGL_SUCCESS; | 
|         |    347     } | 
|         |    348  | 
|         |    349 EGLint CEglThreadSession::EglSignalSyncInternal(EGLDisplay aDisplay, EGLSyncKHR aSync, EGLenum aMode) | 
|         |    350     { | 
|         |    351     if (aDisplay == EGL_NO_DISPLAY) | 
|         |    352         { | 
|         |    353         return EGL_BAD_DISPLAY; | 
|         |    354         } | 
|         |    355     if (aSync == EGL_NO_SYNC_KHR) | 
|         |    356         { | 
|         |    357         return EGL_BAD_PARAMETER; | 
|         |    358         } | 
|         |    359     if (aMode != EGL_SIGNALED_KHR && aMode != EGL_UNSIGNALED_KHR) | 
|         |    360         { | 
|         |    361         return EGL_BAD_PARAMETER; | 
|         |    362         } | 
|         |    363  | 
|         |    364     iDriver.Lock(); | 
|         |    365  | 
|         |    366     CEglDisplay* display = iDriver.FindDisplay(aDisplay); | 
|         |    367     if (!display) | 
|         |    368         { | 
|         |    369         iDriver.Unlock(); | 
|         |    370         return EGL_BAD_DISPLAY; | 
|         |    371         } | 
|         |    372     if (!display->IsInitialized()) | 
|         |    373         { | 
|         |    374         iDriver.Unlock(); | 
|         |    375         return EGL_NOT_INITIALIZED; | 
|         |    376         } | 
|         |    377  | 
|         |    378     CEglSync* syncObj = display->FindSyncObj(aSync); | 
|         |    379     if (!syncObj) | 
|         |    380         { | 
|         |    381         iDriver.Unlock(); | 
|         |    382         return EGL_BAD_PARAMETER; | 
|         |    383         } | 
|         |    384     if (syncObj->Type() != EGL_SYNC_REUSABLE_KHR) | 
|         |    385         { | 
|         |    386         iDriver.Unlock(); | 
|         |    387         return EGL_BAD_MATCH; | 
|         |    388         } | 
|         |    389     if (syncObj->IsDestroyed()) /* sync obj has been marked as destroyed */ | 
|         |    390         { | 
|         |    391         iDriver.Unlock(); | 
|         |    392         return EGL_BAD_PARAMETER; | 
|         |    393         } | 
|         |    394      | 
|         |    395     syncObj->Signal(aMode); | 
|         |    396     iDriver.Unlock(); | 
|         |    397      | 
|         |    398     return EGL_SUCCESS; | 
|         |    399     } | 
|         |    400  | 
|         |    401 EGLBoolean CEglThreadSession::EglGetSyncAttribKhr(EGLDisplay aDisplay, EGLSyncKHR aSync, EGLint aAttribute, EGLint *aValue) | 
|         |    402     { | 
|         |    403     SetError(EGL_SUCCESS); | 
|         |    404      | 
|         |    405     CHECK_FOR_NULL_DISPLAY(aDisplay, EGL_FALSE) | 
|         |    406     CHECK_FOR_NULL_SYNCOBJ(aSync, EGL_FALSE) | 
|         |    407      | 
|         |    408     if (aAttribute != EGL_SYNC_TYPE_KHR && aAttribute != EGL_SYNC_STATUS_KHR) | 
|         |    409         { | 
|         |    410         SetError(EGL_BAD_ATTRIBUTE); | 
|         |    411         return EGL_FALSE; | 
|         |    412         } | 
|         |    413  | 
|         |    414     if (!aValue) | 
|         |    415         { | 
|         |    416         SetError(EGL_BAD_PARAMETER); | 
|         |    417         return EGL_FALSE; | 
|         |    418         } | 
|         |    419  | 
|         |    420     iDriver.Lock(); | 
|         |    421  | 
|         |    422     GET_DISPLAY_RETURN_IF_ERR(iDriver, display, aDisplay, EGL_FALSE) | 
|         |    423     GET_SYNCOBJ_RETURN_IF_ERR(iDriver, display, syncObj, aSync, EGL_FALSE) | 
|         |    424  | 
|         |    425     if (syncObj->Type() != EGL_SYNC_REUSABLE_KHR) | 
|         |    426         { | 
|         |    427         iDriver.Unlock(); | 
|         |    428         SetError(EGL_BAD_MATCH); | 
|         |    429         return EGL_FALSE; | 
|         |    430         } | 
|         |    431      | 
|         |    432     switch (aAttribute) | 
|         |    433         { | 
|         |    434         case EGL_SYNC_TYPE_KHR: | 
|         |    435             *aValue = syncObj->Type(); | 
|         |    436             break; | 
|         |    437              | 
|         |    438         case EGL_SYNC_STATUS_KHR: | 
|         |    439             *aValue = syncObj->Status(); | 
|         |    440             break; | 
|         |    441         } | 
|         |    442  | 
|         |    443     iDriver.Unlock(); | 
|         |    444      | 
|         |    445     return EGL_TRUE; | 
|         |    446     } | 
|         |    447  | 
|         |    448 #ifdef _DEBUG | 
|         |    449 void CEglThreadSession::EglHeapMarkStart() | 
|         |    450     { | 
|         |    451     iDriver.Lock(); | 
|         |    452     iDriver.Heap().__DbgMarkStart(); | 
|         |    453     iDriver.Unlock(); | 
|         |    454     } | 
|         |    455  | 
|         |    456 EGLint CEglThreadSession::EglHeapMarkEnd(EGLint aCount) | 
|         |    457     { | 
|         |    458     iDriver.Lock(); | 
|         |    459     const TInt cell = iDriver.Heap().__DbgMarkEnd(aCount); | 
|         |    460     iDriver.Unlock(); | 
|         |    461      | 
|         |    462     return cell; | 
|         |    463     } | 
|         |    464  | 
|         |    465 void CEglThreadSession::EglHeapSetBurstAllocFail(EGLenum aType, EGLint aRate, EGLint aBurst) | 
|         |    466     { | 
|         |    467     iDriver.Lock(); | 
|         |    468     iDriver.Heap().__DbgSetBurstAllocFail(static_cast<RAllocator::TAllocFail>(aType), aRate, aBurst); | 
|         |    469     iDriver.Unlock(); | 
|         |    470     } | 
|         |    471  | 
|         |    472 #endif //_DEBUG |