guestrendering/guestegl/src/eglcontext.cpp
author Matt Plumtree <matt.plumtree@nokia.com>
Thu, 07 Oct 2010 13:58:22 +0100
branchbug235_bringup_0
changeset 55 09263774e342
parent 13 220791dae4c4
permissions -rwxr-xr-x
Move GLES20 source into standard locations Move Khronos headers into their respective components, to be exported by each. Remove hostthreadadapter as nothing outside of the vghwapiwrapper, which now contains the code, needs it

// 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