guestrendering/guestegl/src/eglcontext.cpp
author Faisal Memon <faisal.memon@nokia.com>
Wed, 08 Sep 2010 15:45:18 +0100
branchbug235_bringup_0
changeset 13 220791dae4c4
permissions -rwxr-xr-x
Add TPIP free guest egl

// Copyright (c) 2010 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:
// Implementation of guest egl context

#include <e32debug.h>
#include "eglapi.h"



// factory function
CEglContext* CEglContext::Create(TEglThreadState& aThreadState, EGLDisplay aDisplay, EGLConfig aConfig, CEglContext* aShareContext, const EGLint* aAttribList)
	{
	// ToDo validate aConfig
	// ToDo validate aShareContext

	// which Khronos Graphics API is the Context for: Open GL ES, Open VG, ...
	EGLenum api = aThreadState.EglBoundApi();
	// (in case supported APIs ever change) ensure the current API is valid 
	if (api == EGL_NONE)
		{
		aThreadState.SetEglError(EGL_BAD_MATCH);
		return EGL_NO_CONTEXT;
		}

	EGLint glesClientVersion = 1;
	// validate AttribList parameter
	if ( aAttribList && (*aAttribList != EGL_NONE) )
		{
		TBool attribsOkay = EFalse;
		// As of EGL 1.4 only Open GL ES api supports any attributes for eglCreateContext
		if (api == EGL_OPENGL_ES_API)
			{
			// only supported attribute for Open GL ES is EGL_CONTEXT_CLIENT_VERSION
			if ( (aAttribList[0] == EGL_CONTEXT_CLIENT_VERSION) && (aAttribList[2] == EGL_NONE) )
				{
				glesClientVersion = aAttribList[1];
				// modify this code when GL ES 2 support is added
				if (glesClientVersion == 1)
					{
					attribsOkay = ETrue;
					}
				}
			}
		if (!attribsOkay)
			{
			aThreadState.SetEglError(EGL_BAD_PARAMETER);
			return EGL_NO_CONTEXT;
			}
		}

	// ToDo validate that aConfig supports this API (inc GL ES v2 versus v1)
	EGLContext shareContextFamily = EGL_NO_CONTEXT;
	if (aShareContext)
		{
		shareContextFamily = aShareContext->ShareContextFamily();
		}
	RHeap* threadHeap = CVghwUtils::SwitchToVghwHeap();
	CEglContext* self = new CEglContext(aDisplay, aConfig, shareContextFamily, api, glesClientVersion);
	if (self == EGL_NO_CONTEXT)
		{
		aThreadState.SetEglError(EGL_BAD_ALLOC);
		}
	else
		{
		// call Host EGL, & set iHostContext
		RemoteFunctionCallData rfcdata; EglRFC eglApiData( rfcdata );
		eglApiData.Init(EglRFC::EeglCreateContext);
		eglApiData.AppendEGLDisplay(aDisplay);
		eglApiData.AppendEGLConfig(aConfig);
		eglApiData.AppendEGLContext(aShareContext ? aShareContext->HostContext() : EGL_NO_CONTEXT);
		eglApiData.AppendEGLintVector(aAttribList, TAttribUtils::AttribListLength(aAttribList));
		self->iHostContext = aThreadState.ExecEglContextCmd(eglApiData);
		if (self->iHostContext == EGL_NO_CONTEXT)
			{ // Host EGL error
			delete self;
			self = EGL_NO_CONTEXT;
			}
		}
	CVghwUtils::SwitchFromVghwHeap(threadHeap);
	return self;
	}


CEglContext::CEglContext(EGLDisplay aDisplay, EGLConfig aConfig, EGLContext aShareContextFamily, EGLenum aRenderingApi,
			EGLint aGlesClientVersion) :
		iFirstUse(ETrue), iHostContext(EGL_NO_CONTEXT), iDisplay(aDisplay), iShareContextFamily(aShareContextFamily),
		iConfigId(aConfig), iRenderingApi(aRenderingApi), iDrawSurface(EGL_NO_SURFACE), iReadSurface(EGL_NO_SURFACE),
		iGlesClientVersion(aGlesClientVersion), iIsDestroyed(EFalse)
	{
	iCtxMutex.CreateLocal(EOwnerProcess);
	}


void CEglContext::Delete(TEglThreadState& aThreadState)
	{
	EGLPANIC_ASSERT_DEBUG(iCtxMutex.IsHeld(), EEglPanicTemp);

	// tell Host EGL to destroy the Context now
	RemoteFunctionCallData rfcdata; EglRFC eglApiData( rfcdata );
	eglApiData.Init(EglRFC::EeglDestroyContext);
	eglApiData.AppendEGLDisplay(iDisplay);
	eglApiData.AppendEGLContext(iHostContext);
	EGLBoolean hostResult = aThreadState.ExecEglBooleanCmd(eglApiData);
	EGLPANIC_ASSERT_DEBUG(hostResult,  EEglPanicTemp);

	// free
	iCtxMutex.Close();
	RHeap* threadHeap = CVghwUtils::SwitchToVghwHeap();
	delete this;
	CVghwUtils::SwitchFromVghwHeap(threadHeap);
	}


CEglContext::~CEglContext()
	{
	if (iCtxMutex.Handle())
		{
	iCtxMutex.Close();
		}
	}


EGLBoolean CEglContext::MakeCurrent(TEglThreadState& aThreadState, EGLSurface aDraw, EGLSurface aRead)
	{
	// ToDo support different number spaces for Host & Client EGL Surfaces 
	EGLBoolean hostResult = EGL_FALSE;
	EGLint error = EGL_SUCCESS;
	iCtxMutex.Wait();
	if (iIsDestroyed)
		{
		error = EGL_BAD_CONTEXT;
		}
	else
		{
		// ToDo validate aDraw & aRead are compatible with API
		RemoteFunctionCallData rfcdata; EglRFC eglApiData( rfcdata );
		eglApiData.Init( EglRFC::EeglMakeCurrent );
		eglApiData.AppendEGLDisplay(iDisplay);
		eglApiData.AppendEGLSurface(aDraw);
		eglApiData.AppendEGLSurface(aRead);
		eglApiData.AppendEGLContext(iHostContext);
		hostResult = aThreadState.ExecEglBooleanCmd(eglApiData);
		if (hostResult)
			{
			iDrawSurface = aDraw;
			iReadSurface = aRead;
			}
		}
	iCtxMutex.Signal();
	if (error != EGL_SUCCESS)
		{ // error in parameter checks 
		aThreadState.SetEglError(error);
		}
	return hostResult;
	}


TBool CEglContext::Destroy(TEglThreadState& aThreadState)
	{
	iCtxMutex.Wait();
	iIsDestroyed = ETrue;
	if ( (iDrawSurface == EGL_NO_SURFACE) && (iReadSurface == EGL_NO_SURFACE) )
		{ // Context not in use
		Delete(aThreadState);
		return ETrue;
		}
	iCtxMutex.Signal();
	return EFalse;
	}


TBool CEglContext::MakeNotCurrent(TEglThreadState& aThreadState)
	{
	iCtxMutex.Wait();
	iDrawSurface = EGL_NO_SURFACE;
	iReadSurface = EGL_NO_SURFACE;

	if (iIsDestroyed)
		{ // Destroyed & no longer in use
		Delete(aThreadState);
		return ETrue;
		}
	iCtxMutex.Signal();
	return EFalse;
	}


EGLContext CEglContext::ShareContextFamily()
	{
	EGLContext result = EGL_NO_CONTEXT;
	// ToDo review - maybe just check Mutex is held
	iCtxMutex.Wait();
	if (!iIsDestroyed)
		{
		if (iShareContextFamily)
			{
			result = iShareContextFamily;
			}
		else
			{
			result = iHostContext;
			}
		}
	iCtxMutex.Signal();
	return result;
	}

// Valid attributes are: EGL_CONFIG_ID, EGL_CONTEXT_CLIENT_TYPE, EGL_CONTEXT_CLIENT_VERSION, or EGL_RENDER_BUFFER
EGLBoolean CEglContext::QueryAttribute(TEglThreadState& aThreadState, EGLint aAttribute, EGLint* aValue)
	{
	EGLint error = EGL_SUCCESS;
	iCtxMutex.Wait();
	if (iIsDestroyed)
		{
		error = EGL_BAD_CONTEXT;
		}
	else
		{
		switch (aAttribute)
			{
			case EGL_CONFIG_ID:
				*aValue = iConfigId;
				break;
	
			case EGL_CONTEXT_CLIENT_TYPE:
				*aValue = iRenderingApi;
				break;
	
			case EGL_CONTEXT_CLIENT_VERSION:
				*aValue = iGlesClientVersion;
				break;
	
			case EGL_RENDER_BUFFER:
				if (iDrawSurface == NULL)
					{ // context is not bound to any surface
					*aValue = EGL_NONE;
					}
				else
					// ToDo check the currently bound surface type to answer this
					{
					RemoteFunctionCallData rfcdata; EglRFC eglApiData( rfcdata );
					eglApiData.Init(EglRFC::EeglQueryContext);
					eglApiData.AppendEGLDisplay(iDisplay);
					eglApiData.AppendEGLContext(iHostContext);
					eglApiData.AppendEGLint(aAttribute);
					eglApiData.AppendEGLintVector(aValue, 1, RemoteFunctionCallData::EOut);
					EGLBoolean hostResult = aThreadState.ExecEglBooleanCmd(eglApiData);
					return hostResult;
					}
				break;
	
			default:
				error = EGL_BAD_ATTRIBUTE;
				break;
			}
		// Debug compare with Host EGL result
#ifdef _DEBUG
		EGLint hostValue = 0;
		RemoteFunctionCallData rfcdata; EglRFC eglApiData( rfcdata );
		eglApiData.Init(EglRFC::EeglQueryContext);
		eglApiData.AppendEGLDisplay(iDisplay);
		eglApiData.AppendEGLContext(iHostContext);
		eglApiData.AppendEGLint(aAttribute);
		eglApiData.AppendEGLintVector(&hostValue, 1, RemoteFunctionCallData::EOut);
		EGLBoolean hostResult = aThreadState.ExecEglBooleanCmd(eglApiData);
		if (error == EGL_SUCCESS)
			{ // Host EGl result should match ours
			EGLPANIC_ASSERT(hostResult,  EEglPanicTemp);
			EGLPANIC_ASSERT(hostValue == *aValue, EEglPanicTemp);
			}
		else
			{
			EGLPANIC_ASSERT(!hostResult,  EEglPanicTemp);		
			}
#endif
		}
	aThreadState.SetEglError(error);
	iCtxMutex.Signal();
	return (error == EGL_SUCCESS);
	}

// end of file eglcontext.cpp