Add dynamic framebuffer support, and associated vghw utils needed. This code does not compile, and needs companion updates in graphics (3899db667a38) and qemu (c7e943dbf70f). Some code looks like syborg-specific so tagged with FAISALMEMON. Need to check with Jani on this. A later submission will declare when the code compiles again. bug235_bringup_0
authorFaisal Memon <faisal.memon@nokia.com>
Thu, 26 Aug 2010 19:08:32 +0100
branchbug235_bringup_0
changeset 7 ec0e558822c5
parent 5 65231b4e789a
child 8 2231338401dd
Add dynamic framebuffer support, and associated vghw utils needed. This code does not compile, and needs companion updates in graphics (3899db667a38) and qemu (c7e943dbf70f). Some code looks like syborg-specific so tagged with FAISALMEMON. Need to check with Jani on this. A later submission will declare when the code compiles again.
guestrendering/guestvideodriver/api/src/guestvideodriver.cpp
guestrendering/guestvideodriver/ldd/group/virtualvideohwdevice.mmp
guestrendering/guestvideodriver/ldd/src/reqhandlerextension.cpp
guestrendering/guestvideodriver/ldd/src/virtualvideohwchannel.cpp
guestrendering/guestvideodriver/ldd/src/virtualvideohwdevice.cpp
guestrendering/guestvideodriver/ldd/src/virtualvideohwinterface.cpp
guestrendering/vghwserialiser/inc/eglrfc.h
guestrendering/vghwserialiser/src/remotefunctioncall.cpp
guestrendering/vghwutils/eabi/vghwutilsu.def
guestrendering/vghwutils/group/bld.inf
guestrendering/vghwutils/group/vghwutils.mmp
guestrendering/vghwutils/inc/vghwutils.h
guestrendering/vghwutils/rom/vghwutils.iby
guestrendering/vghwutils/src/vghwutils.cpp
--- a/guestrendering/guestvideodriver/api/src/guestvideodriver.cpp	Thu Aug 26 13:29:31 2010 +0100
+++ b/guestrendering/guestvideodriver/api/src/guestvideodriver.cpp	Thu Aug 26 19:08:32 2010 +0100
@@ -223,6 +223,16 @@
     }
 
 // -----------------------------------------------------------------------------
+// RGuestVideDriver::MapToHWAddress
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TInt RGuestVideoDriver::GetFrameBufferBaseAddress( TUint32& aFrameBufferBaseAddress )
+    {
+    TPckg<TUint32> address( aFrameBufferBaseAddress );
+    return DoControl( GuestVideoDriver::ERequestFrameBaseAddress, (TAny*)&address );
+    }
+
+// -----------------------------------------------------------------------------
 // RGuestVideoDriver::EglGetSgHandles
 // -----------------------------------------------------------------------------
 //
--- a/guestrendering/guestvideodriver/ldd/group/virtualvideohwdevice.mmp	Thu Aug 26 13:29:31 2010 +0100
+++ b/guestrendering/guestvideodriver/ldd/group/virtualvideohwdevice.mmp	Thu Aug 26 19:08:32 2010 +0100
@@ -30,6 +30,17 @@
 OS_LAYER_ESTLIB_SYSTEMINCLUDE
 USERINCLUDE     ../inc
 USERINCLUDE     ../../commoninc
+
+
+// This is a co-dependency between adaptation layer packages.  This needs
+// to be refactored in qemu to be a OS level export
+USERINCLUDE	../../../../../qemu/baseport/syborg/specific
+
+// There is a weird depedency here to satisfy syborg to get to the flexible
+// memory model for its syborg.h header
+SYSTEMINCLUDE   /epoc32/include/platform/memmodel/epoc/multiple/arm
+SYSTEMINCLUDE   /epoc32/include/platform/memmodel/epoc/moving
+
 SYSTEMINCLUDE   /epoc32/include/drivers
 
 SOURCEPATH      ../src
--- a/guestrendering/guestvideodriver/ldd/src/reqhandlerextension.cpp	Thu Aug 26 13:29:31 2010 +0100
+++ b/guestrendering/guestvideodriver/ldd/src/reqhandlerextension.cpp	Thu Aug 26 19:08:32 2010 +0100
@@ -11,7 +11,7 @@
 // Contributors:
 //
 // Description:
-// Platsim video driver - request handler extension (a.k.a. Command Scheduler extension)
+// Guest video driver - request handler extension (a.k.a. Command Scheduler extension)
 //
 
 #include <kernel/kern_priv.h>
--- a/guestrendering/guestvideodriver/ldd/src/virtualvideohwchannel.cpp	Thu Aug 26 13:29:31 2010 +0100
+++ b/guestrendering/guestvideodriver/ldd/src/virtualvideohwchannel.cpp	Thu Aug 26 19:08:32 2010 +0100
@@ -236,6 +236,14 @@
                 }
             break;
             }
+        case ERequestFrameBaseAddress:
+            {
+            TPhysAddr physicalAddress(0);
+			physicalAddress = iHwInterface.GetFrameBase();
+            TPckgC<TPhysAddr> address(physicalAddress);
+            err = Kern::ThreadDesWrite(aUserThread, a1, address, 0, 0, aUserThread);
+            break;
+            }
 #ifdef FAISALMEMON_S4_SGIMAGE
         case ERequestSgHandles:
             {
--- a/guestrendering/guestvideodriver/ldd/src/virtualvideohwdevice.cpp	Thu Aug 26 13:29:31 2010 +0100
+++ b/guestrendering/guestvideodriver/ldd/src/virtualvideohwdevice.cpp	Thu Aug 26 19:08:32 2010 +0100
@@ -46,6 +46,8 @@
     // Just set the version.
     using namespace GuestVideoDriver;
     iVersion = TVersion( KMajorVer, KMinorVer, KBuildVer );
+	iHwInterface = new DVirtualVideoHwInterface;
+	Kern::Printf("DVirtualVideoHwDevice::DVirtualVideoHwDevice()<");
     VVHW_TRACE("DVirtualVideoHwDevice::DVirtualVideoHwDevice");
     }
 
@@ -77,7 +79,9 @@
         return err;
         }
     
-    iHwInterface = new DVirtualVideoHwInterface;
+	// We have already created this during construction
+    // iHwInterface = new DVirtualVideoHwInterface;
+
     if ( !iHwInterface )
         {
         return KErrNoMemory;
--- a/guestrendering/guestvideodriver/ldd/src/virtualvideohwinterface.cpp	Thu Aug 26 13:29:31 2010 +0100
+++ b/guestrendering/guestvideodriver/ldd/src/virtualvideohwinterface.cpp	Thu Aug 26 19:08:32 2010 +0100
@@ -21,11 +21,13 @@
 #include <graphics/guestvideodriverinterfaceconstants.h>
 #include <graphics/virtualvideohwinterface.h>
 #include <graphics/virtualvideotracing.h>
+#include "syborg.h"
 
 
 // CONSTANTS
 
 _LIT( KVirtualVideoHwInterfacePanic, "DVirtualVideoHwInterface" );
+DVirtualVideoHwInterface * DVirtualVideoHwInterface::pVVHIf = NULL;
 
 // ============================ LOCAL DATA TYPES ===============================
 
@@ -44,7 +46,9 @@
     VVI_R_INPUT_BUFFER_READ_COUNT,
     VVI_R_INPUT_BUFFER_WRITE_COUNT,
     VVI_R_INPUT_BUFFER_MAX_TAIL,
-    VVI_R_REQUEST_ID
+    VVI_R_REQUEST_ID,
+	VVI_R_SHARED_CMD_MEMORY_BASE,
+	VVI_R_SHARED_FRAMEBUFFER_MEMORY_BASE,
     };
 #define ASSERT_PANIC(c,p) __ASSERT_DEBUG(c,Kern::PanicCurrentThread(KVirtualVideoHwInterfacePanic,p));
 
@@ -67,6 +71,24 @@
     iInputParametersMemoryChunk = NULL;
     iOutputParametersMemoryChunk = NULL;
     iRegisterMemoryChunk = NULL;
+
+	DVirtualVideoHwInterface::pVVHIf = this;
+
+    Kern::Printf("DVirtualVideoHwInterface::DVirtualVideoHwInterface()>");
+	// Reserve a contiguous memory chunk for graphics usage
+	TUint32 ramSize = VVI_PARAMETERS_INPUT_MEMORY_SIZE +
+						VVI_PARAMETERS_OUTPUT_MEMORY_SIZE + 
+						VVI_FRAMEBUFFER_MEMORY_SIZE + 
+						VVI_REGISTERS_MEMORY_SIZE;
+	TInt r = Epoc::AllocPhysicalRam( ramSize, iVideoRamPhys );
+    VVHW_TRACE("DVirtualVideoHwInterface::DVirtualVideoHwInterface() AllocPhysicalRam %d", r);
+	if (r != KErrNone)
+		{
+	    NKern::ThreadLeaveCS();
+		Kern::Fault("DVirtualVideoHwInterface Allocate Ram %d",r);
+		}
+	iFrameRamPhys = iVideoRamPhys + VVI_FRAMEBUFFER_BASE_ADDRESS;
+	Kern::Printf("DVirtualVideoHwInterface::DVirtualVideoHwInterface()<");
     }
 
 
@@ -104,23 +126,36 @@
 
 TInt DVirtualVideoHwInterface::InitParametersInputMemory()
     {
-    return InitPhysicalMemory( VVI_PARAMETERS_INPUT_BASE_ADDRESS, 
+    TInt ret = InitPhysicalMemory( iVideoRamPhys + VVI_PARAMETERS_INPUT_BASE_ADDRESS, 
             VVI_PARAMETERS_INPUT_MEMORY_SIZE, iInputParametersMemoryChunk, 
             iInputParametersChunkKernelAddress );    
-    }
+    Kern::Printf("DVirtualVideoHwInterface::InitParametersInputMemory - Base phy: 0x%08x lin: 0x%08x ret: %d", 
+    		iVideoRamPhys + VVI_PARAMETERS_INPUT_BASE_ADDRESS, 
+    		iInputParametersChunkKernelAddress, ret );
+    return ret;
+	}
 
 TInt DVirtualVideoHwInterface::InitParametersOutputMemory()
     {
-    return InitPhysicalMemory( VVI_PARAMETERS_OUTPUT_BASE_ADDRESS, 
+    TInt ret = InitPhysicalMemory( iVideoRamPhys + VVI_PARAMETERS_OUTPUT_BASE_ADDRESS, 
             VVI_PARAMETERS_OUTPUT_MEMORY_SIZE, iOutputParametersMemoryChunk, 
-            iOutputParametersChunkKernelAddress );    
+            iOutputParametersChunkKernelAddress );
+    Kern::Printf("DVirtualVideoHwInterface::InitParametersOutputMemory - Base phy: 0x%08x lin: 0x%08x ret: %d", 
+    	iVideoRamPhys + VVI_PARAMETERS_OUTPUT_BASE_ADDRESS, 
+    	iOutputParametersChunkKernelAddress, ret );
+    return ret;
     }
 
 TInt DVirtualVideoHwInterface::InitRegisterMemory()
     {
-    return InitPhysicalMemory( VVI_REGISTERS_BASE_ADDRESS, 
-            VVI_REGISTERS_MEMORY_SIZE, iRegisterMemoryChunk, 
-            iRegisterChunkKernelAddress );        
+    Kern::Printf(" DVirtualVideoHwInterface::InitRegisterMemory>");
+    Kern::Printf("DVirtualVideoHwInterface::InitRegisterMemory - parameter base phy: 0x%08x", iVideoRamPhys );
+ 	SetSharedCmdMemBase( iVideoRamPhys );
+   	Kern::Printf("DVirtualVideoHwInterface::InitRegisterMemory - frame buffer phy: 0x%08x", iFrameRamPhys );
+	SetSharedFramebufferMemBase( iFrameRamPhys );
+
+    Kern::Printf(" DVirtualVideoHwInterface::InitRegisterMemory<");
+    return 0;   
     }
 
 // -----------------------------------------------------------------------------
@@ -218,6 +253,22 @@
     SetRegisterValue( ERegCommand, aCommand );
     }
 
+// DVirtualVideoHwInterface::SetSharedCmdMemBase
+// -----------------------------------------------------------------------------
+//
+void DVirtualVideoHwInterface::SetSharedCmdMemBase( TUint32 aPhysicalAddress )
+    {
+    VVHW_TRACE("DVirtualVideoHwInterface::SetSharedCmdMemBase 0x%08x", aPhysicalAddress);
+    SetRegisterValue( ERegSharedCmdMemBase, aPhysicalAddress );
+    }
+
+void DVirtualVideoHwInterface::SetSharedFramebufferMemBase( TUint32 aPhysicalAddress )
+    {
+    VVHW_TRACE("DVirtualVideoHwInterface::SetSharedFramebufferMemBase 0x%08x", aPhysicalAddress);
+    SetRegisterValue( ERegSharedFramebufferMemBase, aPhysicalAddress );
+    }
+
+
 // -----------------------------------------------------------------------------
 // DVirtualVideoHwInterface::GetRegisterValue
 // -----------------------------------------------------------------------------
@@ -226,11 +277,13 @@
     TRegister aRegister,
     TUint32& aValue )
     {
-    if ( iRegisterMemoryChunk )
+    if ( 1 /* iRegisterMemoryChunk */ ) // FAISALMEMON check this line of code with Jani.  Can we get rid of it?
         {
         TLinAddr offset = RegisterOffset( aRegister );
-        TUint32* ptr = reinterpret_cast<TUint32*>( iRegisterChunkKernelAddress + offset );
-        aValue = *ptr;
+		// FAISALMEMON check this with Jani.  Will the code still work for platsim or is this now syborg specific?
+        //TUint32* ptr = reinterpret_cast<TUint32*>( iRegisterChunkKernelAddress + offset );
+        //aValue = *ptr;
+		aValue = ReadReg( KHwGraphicsRegBase, offset );
         }
     else
         {
@@ -259,19 +312,12 @@
         }
     }
 
-// TODO FAISALMEMON This is the first portion of the port of Jani's
-// Dynamic framebuffer base address code.  Inspect this code, and also
-// put in the rest of the code.
 EXPORT_C TPhysAddr  DVirtualVideoHwInterface::GetFrameBase()
 	{
-#ifdef FAISALMEMON_DONE_DYNAMIC_FRAMEBUFFER_PORT 
 	TPhysAddr ret = 0;
 	if(DVirtualVideoHwInterface::pVVHIf != NULL)
 		{
 		ret = DVirtualVideoHwInterface::pVVHIf->iFrameRamPhys;
 		}
 	return ret;
-#else
-	return 0;
-#endif
 }
--- a/guestrendering/vghwserialiser/inc/eglrfc.h	Thu Aug 26 13:29:31 2010 +0100
+++ b/guestrendering/vghwserialiser/inc/eglrfc.h	Thu Aug 26 19:08:32 2010 +0100
@@ -89,8 +89,8 @@
         EeglWaitNative, // 30
         EeglSwapBuffers,
         EeglCopyBuffers,
-        EeglPlatsimSetSurfaceParams,
-        EeglPlatsimCopyImageData,
+        EeglSimulatorSetSurfaceParams,
+        EeglSimulatorCopyImageData,
         EeglPixmapSurfaceSizeChanged,
         EeglMakeCurrentSg, //sgImage support
         EeglCreatePixmapSurfaceSg,
--- a/guestrendering/vghwserialiser/src/remotefunctioncall.cpp	Thu Aug 26 13:29:31 2010 +0100
+++ b/guestrendering/vghwserialiser/src/remotefunctioncall.cpp	Thu Aug 26 19:08:32 2010 +0100
@@ -19,7 +19,7 @@
 #define USE_SYMBIAN_CLIENT_PANICS
 #include <e32debug.h>
 #include "serialisedapiuids.h"
-// Platsim Serialiser panic codes
+// Guest Serialiser panic codes
 typedef enum
 	{
 	ESerPanicMaxParamCountExceeded=1,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/guestrendering/vghwutils/eabi/vghwutilsu.def	Thu Aug 26 19:08:32 2010 +0100
@@ -0,0 +1,34 @@
+EXPORTS
+	_Z9VghwPanic10TVghwPanicPcS0_S0_i @ 1 NONAME
+	_ZN10CVghwUtils14MapToHWAddressEiRm @ 2 NONAME
+	_ZN10CVghwUtils20DriverExecuteCommandER22RemoteFunctionCallData @ 3 NONAME
+	_ZN10CVghwUtils11InitStaticsEv @ 4 NONAME
+	_ZN10CVghwUtils5AllocEi @ 5 NONAME
+	_ZN10CVghwUtils4FreeEPv @ 6 NONAME
+	_ZN10CVghwUtils7GetHeapEv @ 7 NONAME
+	_ZN10CVghwUtils16SwitchToVghwHeapEv @ 8 NONAME
+	_ZN10CVghwUtils18SwitchFromVghwHeapEP5RHeap @ 9 NONAME
+	Reserved10 @ 10 NONAME ABSENT
+	Reserved11 @ 11 NONAME ABSENT
+	_ZN10CVghwUtils17CreateThreadStateEv @ 12 NONAME
+	_ZN10CVghwUtils18ReleaseThreadStateEv @ 13 NONAME
+	_ZN10CVghwUtils14EglThreadStateEv @ 14 NONAME
+	_ZN10CVghwUtils9VgContextEv @ 15 NONAME
+	_ZN10CVghwUtils11GlesContextEv @ 16 NONAME
+	_ZN15TEglThreadState8EglErrorEv @ 17 NONAME
+	_ZN15TEglThreadState17ExecEglBooleanCmdER6EglRFC @ 18 NONAME
+	_ZN15TEglThreadState17ExecEglContextCmdER6EglRFC @ 19 NONAME
+	_ZN15TEglThreadState17ExecEglSurfaceCmdER6EglRFC @ 20 NONAME
+	_ZN10CVghwUtils16EglManagementApiEv @ 21 NONAME
+	_ZN10CVghwUtils15EglGetSgHandlesEyPy @ 22 NONAME
+	_ZN10CVghwUtils14DestroyStaticsEv @ 23 NONAME
+	_ZN10CVghwUtils19SetEglManagementApiEP17MEglManagementApi @ 24 NONAME
+	_ZN10CVghwUtils14SetVgApiForEglEP12MVgApiForEgl @ 25 NONAME
+	_ZN10CVghwUtils18SetGles11ApiForEglEP16MGles11ApiForEgl @ 26 NONAME
+	_ZN10CVghwUtils17SetGles2ApiForEglEP15MGles2ApiForEgl @ 27 NONAME
+	_ZN10CVghwUtils11VgApiForEglEv @ 28 NONAME
+	_ZN10CVghwUtils15Gles11ApiForEglEv @ 29 NONAME
+	_ZN10CVghwUtils14Gles2ApiForEglEv @ 30 NONAME
+
+
+
--- a/guestrendering/vghwutils/group/bld.inf	Thu Aug 26 13:29:31 2010 +0100
+++ b/guestrendering/vghwutils/group/bld.inf	Thu Aug 26 19:08:32 2010 +0100
@@ -0,0 +1,22 @@
+// 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:
+// Build file for VG Hardware Utilities
+
+PRJ_PLATFORMS
+DEFAULT -WINSCW
+
+PRJ_EXPORTS
+
+PRJ_MMPFILES
+vghwutils.mmp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/guestrendering/vghwutils/group/vghwutils.mmp	Thu Aug 26 19:08:32 2010 +0100
@@ -0,0 +1,53 @@
+// 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:
+// Project file for vghwutils
+
+TARGET		  vghwutils.dll
+TARGETTYPE	  dll
+UID			 0x1000008d 0x20026A32
+capability      CAP_GENERAL_DLL //All -Tcb
+vendorid        VID_DEFAULT //0x101FB657 //Nokia vendor id 
+
+OS_LAYER_ESTLIB_SYSTEMINCLUDE
+OS_LAYER_SYSTEMINCLUDE
+USERINCLUDE	 ../inc
+SYSTEMINCLUDE   /epoc32/include
+//systeminclude   /epoc32/include/libc	// STDLIB include files
+//systeminclude   /epoc32/include/vg	// OpenVG include files
+USERINCLUDE     ../../vghwserialiser/inc
+// userinclude     ../../platsimvideodriver/api/inc			// Local include files
+// userinclude     ../../platsimvideodriver/commoninc			// Local include files
+
+SOURCEPATH	  ../src
+
+SOURCE		  vghwutils.cpp
+
+// constructors & such for OpenVgRFC and EglRFC objects
+SOURCEPATH      ../../vghwserialiser/src
+SOURCE          eglrfc.cpp
+SOURCE          openvgrfc.cpp
+SOURCE          opengles11rfc.cpp
+
+
+//nostrictdef
+
+LIBRARY euser.lib
+LIBRARY platsimvideohwapi.lib
+LIBRARY vghwserialiser.lib
+
+#ifdef ENABLE_ABIV2_MODE
+DEBUGGABLE_UDEBONLY
+#endif
+
+EPOCALLOWDLLDATA
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/guestrendering/vghwutils/inc/vghwutils.h	Thu Aug 26 19:08:32 2010 +0100
@@ -0,0 +1,342 @@
+// 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:
+
+
+#ifndef __VGHWUTILS_H__
+#define __VGHWUTILS_H__
+
+//  Include Files
+#include <e32base.h>	// CBase
+#include <EGL/egl.h>
+#include <VG/openvg.h>
+#include <GLES/gl.h>
+#include "eglrfc.h"
+
+
+class RGuestVideoDriver;
+
+// Virtual Graphics Hardware per thread data: TEglThreadState is concrete, MVgContext & MGlesContext are per API interfaces
+class TEglThreadState;
+class MGlesContext;
+class MVgContext;
+
+// data serialisation packages
+class OpenVgRFC;
+class EglRFC;
+class RemoteFunctionCall;
+class RemoteFunctionCallData;
+
+// tracing
+#ifdef _DEBUG
+	#include <e32debug.h>
+    #define UTIL_TRACE(fmt, args...) RDebug::Printf(fmt, ##args)
+	#define VGHWPANIC_ASSERT(condition, panic) if (!(condition)) { VghwPanic(panic, #panic, #condition, __FILE__, __LINE__); }
+	#define VGHWPANIC_ASSERT_DEBUG(condition, panic) if (!(condition)) { VghwPanic(panic, #panic, #condition, __FILE__, __LINE__); }
+#else
+    #define UTIL_TRACE(fmt, args...)
+	#define VGHWPANIC_ASSERT(condition, panic) if (!(condition)) { VghwPanic(panic, NULL, NULL, NULL, __LINE__); }
+	#define VGHWPANIC_ASSERT_DEBUG(condition, panic)
+#endif
+
+
+// Simulator Virtual Graphics Hardware panic codes
+typedef enum
+	{
+	EVghwPanicNoVideoChannel = 1,
+	EVghwPanicOperationDataTooBig,
+	EVghwPanicDriverOpenError,
+	EVghwPanicVghwHeapDoesNotExist,
+	EVghwPanicInitializeFailed,
+	EVghwPanicGraphicsDriverNotOpen,
+	EVghwPanicSwitchToVghwHeapOldHeapIsVghwHeap,
+	EVghwPanicSwitchFromVghwHeapParamIsNull,
+	EVghwPanicSwitchFromVghwHeapOldHeapIsNotVghwHeap,
+	EVghwPanicSwitchFromVghwHeapParamIsVghwHeap, // 10
+	EVghwPanicGraphicsCreationLockDoesNotExist,
+	EVghwPanicExecuteCommandFailed,
+	EVghwPanicBadVgErrorValue,
+	EVghwPanicBadGlesErrorValue,
+	EVghwPanicBadEglErrorValue,
+	EVghwPanicBadEglBoundApi,
+	} TVghwPanic;
+
+// This panic function is exported to allow inline functions to use it
+IMPORT_C void VghwPanic(TVghwPanic aPanicCode, char* aPanicName, char* aCondition, char* aFile, TInt aLine);
+
+
+// Mix-in class: EGL support functions, including SgImage support, expected to be called by Open VG and Open GL ES
+class MEglManagementApi
+	{
+public:
+	virtual TBool EglImageOpenForVgImage(EGLImageKHR aImage, TSize& aSize, VGHandle& aVgHandle, TUint64& aSgImageId) = 0;
+	virtual void EglImageClose(EGLImageKHR aImage) = 0;
+	// ToDo add an API so that Open VG can query the size of the current Context's surface
+	};
+
+
+typedef void (*ExtensionProcPointer)(...);
+
+
+// Private interfaces for EGL to call into Open VG 
+class MVgApiForEgl
+	{
+public:
+	virtual ExtensionProcPointer platsimGetVgProcAddress (const char *aProcName) = 0;
+	};
+
+
+// Private interfaces for EGL to call into Open GL ES 1.1 
+class MGles11ApiForEgl
+	{
+public:
+	virtual ExtensionProcPointer platsimGetGles11ProcAddress (const char *aProcName) = 0;
+	};
+
+
+// Private interfaces for EGL to call into Open GL ES 2 
+class MGles2ApiForEgl
+	{
+public:
+	virtual ExtensionProcPointer platsimGetGles2ProcAddress (const char *aProcName) = 0;
+	};
+
+
+/*
+ VGHWUtils APIs are static for ease of use by the other Simulator Graphics DLLs.
+
+ One (singleton) instance is created as Writeable Static Data when the DLL is loaded.
+ After initialization this will hold process-wide data - e.g. a memory heap for Graphics DLLs
+ to store local Symbian client state information.
+
+ ToDo maybe make this a Symbian X class because it owns resources, but only as static data.
+ */
+NONSHARABLE_CLASS(CVghwUtils): public CBase
+    {
+	friend class TEglThreadState; // to limit visibility of DriverExecuteCommand
+public:
+	// open Driver connection, create Memory Heap, etc...
+	IMPORT_C static void InitStatics();
+	IMPORT_C static void DestroyStatics();
+
+	IMPORT_C static TInt MapToHWAddress(const TInt aChunkHandle, TUint32& aHWAddress);
+	IMPORT_C static TInt GetFrameBufferBaseAddress(TUint32& aHWAddress);
+	IMPORT_C static TInt EglGetSgHandles(const TUint64 aId, TUint64 *aSgHandles);
+
+	// VG Memory Pool APIs (One heap is created for the process, for use by all Simulator Graphics DLLs)
+	IMPORT_C static TAny* Alloc(TInt aSize); 
+	IMPORT_C static void Free(TAny* aPtr);
+	IMPORT_C static RHeap* GetHeap();
+	IMPORT_C static RHeap* SwitchToVghwHeap();
+	IMPORT_C static void SwitchFromVghwHeap(RHeap* aOldHeapPtr);
+	// handy function for Debug Asserts
+	static inline TBool UsingVghwHeap() { return &User::Heap() == GetHeap(); }
+
+	// if this thread does not have a state object try to alloc a new one
+	IMPORT_C static TEglThreadState* CreateThreadState();
+	// current state object, if any, for this thread (for EGL)
+	IMPORT_C static TEglThreadState* EglThreadState();
+	// current state object, if Open VG, for this thread (as tracked by EGL DLL)
+	IMPORT_C static MVgContext* VgContext();
+	// current state object for Open GL ES 1.1, for this thread (as tracked by EGL DLL)
+	IMPORT_C static MGlesContext* GlesContext();
+	// free current state object, if any, for this thread
+	IMPORT_C static void ReleaseThreadState();
+
+	IMPORT_C static void SetEglManagementApi(MEglManagementApi* aEglManagementApi);
+	IMPORT_C static MEglManagementApi* EglManagementApi();
+
+	// Private interfaces for EGL to call into Open GL ES and Open VG (avoids breaking DEF file compatibility) 
+	IMPORT_C static void SetVgApiForEgl(MVgApiForEgl* aVgApiForEgl);
+	IMPORT_C static MVgApiForEgl* VgApiForEgl();
+
+	IMPORT_C static void SetGles11ApiForEgl(MGles11ApiForEgl* aGles11ApiForEgl);
+	IMPORT_C static MGles11ApiForEgl* Gles11ApiForEgl();
+
+	IMPORT_C static void SetGles2ApiForEgl(MGles2ApiForEgl* aGles2ApiForEgl);
+	IMPORT_C static MGles2ApiForEgl* Gles2ApiForEgl();
+
+protected:
+	IMPORT_C static void DriverExecuteCommand(RemoteFunctionCallData& aRequestData);
+
+private:
+	inline static RGuestVideoDriver& Driver();
+
+private:
+	// everything is zeroed on construction, call Initialize() to prepare
+	volatile static TBool iInitialized;    // NB "volatile" used for thread safety in InitStaticse()
+	static TInt           iVghwInitMutex;  // required for thread safety in Initialize()
+
+	// static member objects
+	static RGuestVideoDriver*   iDriver;
+	static RHeap*               iHeap;
+	static MEglManagementApi*   iEglManagementApi;
+	static MVgApiForEgl*        iVgApiForEgl;
+	static MGles11ApiForEgl*    iGles11ApiForEgl;
+	static MGles2ApiForEgl*     iGles2ApiForEgl;
+	static TBool                iLoadedOpenVgDll;
+	static TBool                iLoadedOpenGles11Dll;
+	static TBool                iLoadedOpenGles2Dll;	
+	};
+
+
+// Basic interface for sending GL ES 1.1 commands down to Host Open GL ES implementation - can be expanded later
+class MGlesContext
+	{
+public:
+	// Execute Open GL ES 1.1 commands
+	virtual void ExecuteGlesCommand(RemoteFunctionCall& aGlesRequestData) = 0;
+	virtual void ExecuteGlesFlushCommand() = 0;
+	virtual void ExecuteGlesFinishCommand() = 0;
+	// GLES state
+	virtual void SetGlesError(GLenum aGlesErrorCode) = 0;
+	virtual GLenum GlesError() = 0;
+	// ToDo make context tracking work for VG & GL ES
+	virtual EGLContext GlesEglContext() = 0;
+	};
+
+
+// Basic interface for sending VG commands down to Host Open VG implementation - can be expanded later
+class MVgContext
+	{
+public:
+	// Execute Open VG commands
+	virtual void ExecuteVgCommand(OpenVgRFC& aVgApiData) = 0;
+	virtual void ExecuteVgFlushCommand() = 0;
+	virtual void ExecuteVgFinishCommand() = 0;
+	// VG state
+	virtual void SetVgError(VGErrorCode aVgErrorCode) = 0;
+	virtual VGErrorCode VgError() = 0;
+	virtual EGLContext VgEglContext() = 0;
+	};
+
+
+NONSHARABLE_CLASS(TEglThreadState) : public MGlesContext, public MVgContext
+	{
+	friend class CVghwUtils; // to manage creation / delete of per thread state
+public:
+	// Execute EGL commands, and analyse for success
+	IMPORT_C EGLBoolean ExecEglBooleanCmd(EglRFC& aEglApiData);
+	IMPORT_C EGLContext ExecEglContextCmd(EglRFC& aEglApiData);
+	IMPORT_C EGLSurface ExecEglSurfaceCmd(EglRFC& aEglApiData);
+	// ToDo add static export for eglTerminate
+
+	// Execute EGL commands whose return value cannot be tested for fail/success
+	inline void ExecuteEglNeverErrorCmd(EglRFC& aEglApiData);
+	// EGL thread state
+	inline void ClearEglError();
+	inline void SetEglError(EGLint aEglError);
+	IMPORT_C EGLint EglError();
+	inline void SetEglBoundApi(EGLenum aEglBoundApi);
+	inline EGLenum EglBoundApi();
+	inline EGLint PeekEglError(); // reads DLL set error code (only)
+
+	// MGlesContext: Execute Open GL ES 1.1 commands & manage Open GL ES state
+	virtual void ExecuteGlesCommand(RemoteFunctionCall& aGlesRequestData);
+	virtual void ExecuteGlesFlushCommand();
+	virtual void ExecuteGlesFinishCommand();
+	virtual void SetGlesError(GLenum aGlesErrorCode);
+	virtual GLenum GlesError();
+	virtual EGLContext GlesEglContext();
+
+	// MVgContext: Execute Open VG commands & manage Open VG state
+	virtual void ExecuteVgCommand(OpenVgRFC& aVgApiData);
+	virtual void ExecuteVgFlushCommand();
+	virtual void ExecuteVgFinishCommand();
+	virtual void SetVgError(VGErrorCode aVgErrorCode);
+	virtual VGErrorCode VgError();
+	virtual EGLContext VgEglContext();
+
+protected:
+	static TEglThreadState* New();
+	void Destroy();
+	TEglThreadState();
+	~TEglThreadState();
+
+private:
+	GLenum GetHostGlesError();
+	VGErrorCode GetHostVgError();
+
+private:
+	// EGL thread state
+	EGLint       iEglError;
+	TBool        iEglHostHasRecentError;
+	// currently bound graphics API
+	EGLenum      iEglBoundApi;
+
+	// Open VG context for thread
+	VGErrorCode  iVgError;
+	EGLContext  iVgEglContext;
+	TBool        iVgCommandsSinceGetError;
+	TBool        iVgCommandsSinceFlush;
+	TBool        iVgCommandsSinceFinish;
+
+	// Open GL ES 1.1 context for thread
+	GLenum       iGlesError;
+	EGLContext  iGlesEglContext;
+	TBool        iGlesCommandsSinceGetError;
+	TBool        iGlesCommandsSinceFlush;
+	TBool        iGlesCommandsSinceFinish;
+	};
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// TVghwThreadState inline functions
+
+void TEglThreadState::ClearEglError()
+	{
+	UTIL_TRACE("  TVghwThreadState::ClearEglError");
+	iEglError = EGL_SUCCESS;
+	iEglHostHasRecentError = EFalse;
+	}
+
+
+void TEglThreadState::SetEglError(EGLint aEglError)
+	{
+	UTIL_TRACE("  TVghwThreadState::SetEglError error=0x%x", aEglError);
+	VGHWPANIC_ASSERT_DEBUG((aEglError >= EGL_SUCCESS) && (aEglError <= 0x301F), EVghwPanicBadEglErrorValue);
+	iEglError = aEglError;
+	iEglHostHasRecentError = EFalse;
+	}
+
+
+EGLint TEglThreadState::PeekEglError() // reads DLL set error code
+	{
+	return iEglError;
+	}
+
+
+void TEglThreadState::SetEglBoundApi(EGLenum aEglBoundApi)
+	{
+	VGHWPANIC_ASSERT_DEBUG((aEglBoundApi == EGL_OPENGL_ES_API) || (aEglBoundApi == EGL_OPENVG_API), EVghwPanicBadEglBoundApi);
+	iEglBoundApi = aEglBoundApi;
+	}
+
+
+EGLenum TEglThreadState::EglBoundApi()
+	{
+	return iEglBoundApi;
+	}
+
+// Execute EGL Command simple variants
+
+void TEglThreadState::ExecuteEglNeverErrorCmd(EglRFC& aEglApiData)
+	{ // for EGL commands which cannot have a host error
+	CVghwUtils::DriverExecuteCommand(aEglApiData.Data());
+	iEglHostHasRecentError = EFalse;
+	iEglError = EGL_SUCCESS;
+	}
+
+#endif  // __VGHWUTILS_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/guestrendering/vghwutils/rom/vghwutils.iby	Thu Aug 26 19:08:32 2010 +0100
@@ -0,0 +1,24 @@
+// 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:
+
+
+#ifndef PLATSIMVGHWUTILS_IBY
+#define PLATSIMVGHWUTILS_IBY
+
+
+file=ABI_DIR\BUILD_DIR\vghwutils.dll                SHARED_LIB_DIR\vghwutils.dll
+
+#endif // PLATSIMVGHWUTILS_IBY
+
+//  End of File
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/guestrendering/vghwutils/src/vghwutils.cpp	Thu Aug 26 19:08:32 2010 +0100
@@ -0,0 +1,902 @@
+// 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:
+
+
+#include <e32atomics.h>
+#include <e32debug.h>
+
+#include <graphics/guestvideodriver.h>
+
+#include "vghwutils.h"
+#include "eglrfc.h"
+#include "openvgrfc.h"
+#include "opengles11rfc.h"
+
+#ifdef _DEBUG
+#define EGL_ERROR_PRINT(T, E)  EglErrorPrint(T, E)
+#define GLES_ERROR_PRINT(T, E) GlesErrorPrint(T, E)
+#define VG_ERROR_PRINT(T, E)   VgErrorPrint(T, E)
+static void EglErrorPrint(char* aTitle, EGLint aEglError);
+static void GlesErrorPrint(char* aTitle, GLenum aGlesError);
+static void VgErrorPrint(char* aTitle, VGErrorCode aVgError);
+#else
+#define EGL_ERROR_PRINT(T, E)
+#define GLES_ERROR_PRINT(T, E)
+#define VG_ERROR_PRINT(T, E)
+#endif
+
+
+// Min & Max sizes for creating Memory Heap for Guest Graphics DLLs
+#define KVghwHeapMin 0x1000
+#define KVghwHeapMax 0x100000
+
+
+// protection against concurrent initialisation from multiple threads
+volatile TBool       CVghwUtils::iInitialized = EFalse;
+TInt                 CVghwUtils::iVghwInitMutex = 0;
+
+// static member objects - Writeable Static Data
+RGuestVideoDriver* CVghwUtils::iDriver = NULL;
+RHeap*               CVghwUtils::iHeap = NULL;
+MEglManagementApi*   CVghwUtils::iEglManagementApi = NULL;
+MVgApiForEgl*        CVghwUtils::iVgApiForEgl = NULL;
+MGles11ApiForEgl*    CVghwUtils::iGles11ApiForEgl = NULL;
+MGles2ApiForEgl*     CVghwUtils::iGles2ApiForEgl = NULL;
+TBool                CVghwUtils::iLoadedOpenVgDll = EFalse;
+TBool                CVghwUtils::iLoadedOpenGles11Dll = EFalse;
+TBool                CVghwUtils::iLoadedOpenGles2Dll = EFalse;	
+
+
+
+_LIT(KVghwPanicCategory, "Guest VGHW");
+
+
+// NOTE: Exported because some VGHW functions are inline and could Assert & Panic from somewhere else
+EXPORT_C void VghwPanic(TVghwPanic aPanicCode, char* aPanicName, char* aCondition, char* aFile, TInt aLine)
+	{
+	if (aCondition && aFile)
+		{
+		RDebug::Printf("VghwUtils Panic %s for failed Assert (%s), at %s:%d", aPanicName, aCondition, aFile, aLine);
+		}
+	else
+		{  
+		RDebug::Printf("VghwUtils Panic %d for failed Assert (line %d)", aPanicCode, aLine);
+		}
+		
+	User::Panic(KVghwPanicCategory, aPanicCode);
+	}
+
+// inline functions
+
+RGuestVideoDriver& CVghwUtils::Driver()
+	{
+	// TODO remove this later in refactoring - Open VG & GL ES commands should not reach here before EGL has initialized the singleton
+	if (!iInitialized || !iDriver)
+		{
+		UTIL_TRACE("CVghwUtils::Driver called before EGL has initialised VghwUtils: iInitialized=%d, iDriver=0x%x", iInitialized, iDriver);
+		InitStatics();
+		}
+	VGHWPANIC_ASSERT(iInitialized && iDriver, EVghwPanicGraphicsDriverNotOpen);
+	return *iDriver;
+	}
+
+
+EXPORT_C void CVghwUtils::DestroyStatics()
+	{
+#ifdef _DEBUG
+	TUint64 processId = RProcess().Id().Id();
+	TUint64 threadId = RThread().Id().Id();
+	UTIL_TRACE("CVghwUtils::DestroyStatics iInitialized=%d, iDriver=0x%x, iHeap=0x%x, Process=0x%lx, Thread=0x%lx",
+		iInitialized, iDriver, iHeap, processId, threadId);
+#endif
+	if (iHeap)
+		{
+		if (iDriver)
+			{
+			iDriver->Flush();
+			iDriver->Close();
+			RHeap* threadHeap = SwitchToVghwHeap();
+			delete iDriver;
+			SwitchFromVghwHeap(threadHeap);
+			iDriver = NULL;
+			}
+		iHeap->Reset();
+		iHeap->Close();
+		iHeap = NULL;
+		}
+	if (iInitialized)
+		{
+		iInitialized = EFalse;
+		}
+	}
+
+
+// Ensure Graphics memory heap is created, and Open driver channel
+EXPORT_C void CVghwUtils::InitStatics()
+	{
+#ifdef _DEBUG
+	TUint64 processId = RProcess().Id().Id();
+	TUint64 threadId = RThread().Id().Id();
+	UTIL_TRACE("CVghwUtils::InitStatics start Process=0x%lx, Thread=0x%lx, iInitialized=%d",
+		processId, threadId, iInitialized);
+#endif
+	// bootstrap creation of mutexes and Graphics memory heap
+	while (!iInitialized)
+		{
+		TInt creationError = KErrNone;
+		// thread safe initialization
+		// LockedDec() returns the value prior to decrement
+		if (0 != User::LockedDec(iVghwInitMutex))
+			{
+			User::AfterHighRes(1000);     // Yield X microseconds, review length if code is changed
+			}
+		else
+			{
+			// volatile attribute forces rereading of the pointer, in case another thread has done the allocation
+			if (!iInitialized)
+				{ // loop style init exits if any stage fails, and gives per step debug logging
+				TInt step = 0;
+				do
+					{
+					switch (step)
+						{
+						case 0:
+							// guarantee that initialisation of the object is flushed before the pointer is published
+							__e32_atomic_store_rel_ptr(&iHeap, User::ChunkHeap(NULL, KVghwHeapMin, KVghwHeapMax));
+							if (!iHeap)
+								{
+								creationError = KErrNoMemory;
+								}
+							break;
+						case 1:
+							{
+							VGHWPANIC_ASSERT_DEBUG(iHeap, EVghwPanicVghwHeapDoesNotExist);
+							RHeap* threadHeap = User::SwitchHeap(iHeap); // switch to VGHW graphics Heap
+							iDriver = new RGuestVideoDriver();
+							if (!iDriver)
+								{
+								creationError = KErrNoMemory;
+								}
+							User::SwitchHeap(threadHeap); // switch back to client Heap
+							}
+							break;
+						case 2:
+							creationError = User::LoadLogicalDevice(_L("platsimvideohw"));
+							if ( (KErrNone == creationError) || (KErrAlreadyExists == creationError) )
+								{
+								creationError = iDriver->Open();
+								}
+							break;
+						default: // all initialisation steps completed
+							iInitialized = ETrue;
+						}
+					++step;
+					}
+				while (!iInitialized && !creationError);
+				UTIL_TRACE("CVghwUtils::InitStatics %s step=%d; creationError=%d, iInitialized=%d, iDriver=0x%x, iHeap=0x%x",
+						creationError ? "failed at" : "completed", step, creationError, iInitialized, iDriver, iHeap);
+				}
+			}
+		User::LockedInc(iVghwInitMutex);
+
+		VGHWPANIC_ASSERT(creationError == KErrNone, EVghwPanicInitializeFailed);
+		}
+	}
+
+
+// -----------------------------------------------------------------------------
+// 
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CVghwUtils::DriverExecuteCommand(RemoteFunctionCallData& aRequestData)
+	{
+	if (!iInitialized || !iDriver)
+		{
+		UTIL_TRACE("CVghwUtils::DriverExecuteCommand called before EGL has initialised VghwUtils: iInitialized=%d, iDriver=0x%x", iInitialized, iDriver);
+		InitStatics();
+		}
+	VGHWPANIC_ASSERT(iInitialized && iDriver, EVghwPanicGraphicsDriverNotOpen);
+	iDriver->ExecuteCommand(aRequestData);
+	}
+
+
+// -----------------------------------------------------------------------------
+// Use driver to discover linear memory address of chunk.
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TInt CVghwUtils::MapToHWAddress( const TInt aChunkHandle, TUint32& aHWAddress )
+	{
+	UTIL_TRACE("CVghwUtils::MapToHWAddress");
+	return Driver().MapToHWAddress( aChunkHandle, aHWAddress );
+	}
+
+
+// SgImage support function - get underlying VGImage & Pbuffer handles
+EXPORT_C TInt CVghwUtils::EglGetSgHandles( const TUint64 aId, TUint64 *aSgHandles )
+	{
+	UTIL_TRACE("CVghwUtils::EglGetSgHandles");
+	return Driver().EglGetSgHandles( aId, aSgHandles );
+	}
+
+
+// Memory Heap Management functions
+
+EXPORT_C TAny* CVghwUtils::Alloc(TInt aSize)
+	{
+	if (!iInitialized || !iHeap)
+		{
+		UTIL_TRACE("CVghwUtils::Alloc called before EGL has initialised VghwUtils: iInitialized=%d, iDriver=0x%x", iInitialized, iDriver);
+		InitStatics();
+		}
+	VGHWPANIC_ASSERT(iInitialized && iHeap, EVghwPanicVghwHeapDoesNotExist);
+	return iHeap->Alloc(aSize);
+	}
+
+
+EXPORT_C void CVghwUtils::Free(TAny* aPtr)
+	{
+	if (!iInitialized || !iHeap)
+		{
+		UTIL_TRACE("CVghwUtils::Free called before EGL has initialised VghwUtils: iInitialized=%d, iDriver=0x%x", iInitialized, iDriver);
+		InitStatics();
+		}
+	VGHWPANIC_ASSERT(iInitialized && iHeap, EVghwPanicVghwHeapDoesNotExist);
+	iHeap->Free(aPtr);
+	}
+
+
+EXPORT_C RHeap* CVghwUtils::GetHeap()
+	{
+	if (!iInitialized || !iHeap)
+		{
+		UTIL_TRACE("CVghwUtils::GetHeap called before EGL has initialised VghwUtils: iInitialized=%d, iDriver=0x%x", iInitialized, iDriver);
+		InitStatics();
+		}
+	VGHWPANIC_ASSERT(iInitialized && iHeap, EVghwPanicVghwHeapDoesNotExist);
+	return iHeap;
+	}
+
+
+// Switch to VGHW Memory Heap.
+EXPORT_C RHeap* CVghwUtils::SwitchToVghwHeap()
+	{
+	if (!iInitialized || !iHeap)
+		{
+		UTIL_TRACE("CVghwUtils::SwitchToVghwHeap called before EGL has initialised VghwUtils: iInitialized=%d, iDriver=0x%x", iInitialized, iDriver);
+		InitStatics();
+		}
+	VGHWPANIC_ASSERT(iHeap, EVghwPanicVghwHeapDoesNotExist);
+	RHeap* oldHeap = User::SwitchHeap(iHeap); // switch to Guest graphics heap
+	VGHWPANIC_ASSERT(oldHeap != iHeap, EVghwPanicSwitchToVghwHeapOldHeapIsVghwHeap);
+	return oldHeap;
+	}
+
+
+// Switch back to original heap 
+EXPORT_C void CVghwUtils::SwitchFromVghwHeap(RHeap* aOldHeapPtr)
+	{
+	if (!iInitialized || !iHeap)
+		{
+		UTIL_TRACE("CVghwUtils::SwitchFromVghwHeap called before EGL has initialised VghwUtils: iInitialized=%d, iDriver=0x%x", iInitialized, iDriver);
+		InitStatics();
+		}
+	VGHWPANIC_ASSERT(iHeap, EVghwPanicVghwHeapDoesNotExist);
+	VGHWPANIC_ASSERT(aOldHeapPtr, EVghwPanicSwitchFromVghwHeapParamIsNull);
+	VGHWPANIC_ASSERT(aOldHeapPtr != iHeap, EVghwPanicSwitchFromVghwHeapParamIsVghwHeap);
+
+	RHeap* oldHeap = User::SwitchHeap(aOldHeapPtr); // switch from Guest graphics heap back to thread heap
+	VGHWPANIC_ASSERT(oldHeap == iHeap, EVghwPanicSwitchFromVghwHeapOldHeapIsNotVghwHeap);
+	}
+
+
+// if this thread does not have an object try to alloc a new one
+EXPORT_C TEglThreadState* CVghwUtils::CreateThreadState()
+	{
+	TEglThreadState* threadState = reinterpret_cast<TEglThreadState*>(Dll::Tls());
+	if (!threadState)
+		{
+		UTIL_TRACE("CVghwUtils::CreateThreadState - object is currently 0x%x, iInitialized=%d",
+				threadState, iInitialized);
+		if (!iInitialized)
+			{
+			InitStatics();
+			}
+		threadState = TEglThreadState::New();
+		Dll::SetTls(threadState);
+		}
+	return threadState;
+	}
+
+
+// current state object, if any, for this thread
+EXPORT_C TEglThreadState* CVghwUtils::EglThreadState()
+	{
+	TEglThreadState* threadState = reinterpret_cast<TEglThreadState*>(Dll::Tls());
+	return threadState;
+	}
+
+
+// current state object, if Open VG is the current bound API, for this thread 
+EXPORT_C MVgContext* CVghwUtils::VgContext()
+	{
+	TEglThreadState* threadState = reinterpret_cast<TEglThreadState*>(Dll::Tls());
+	return threadState;
+	// ToDo sort this to check for valid Open VG context
+	/*
+	if (threadState && threadState->VgEglContext())
+		return threadState;
+	return NULL;
+	*/
+	}
+
+
+// current state object, if Open GL ES is the current bound API, for this thread (for EGL)
+EXPORT_C MGlesContext* CVghwUtils::GlesContext()
+	{
+	TEglThreadState* threadState = reinterpret_cast<TEglThreadState*>(Dll::Tls());
+	return threadState;
+	// ToDo sort this to check for valid Open GL ES context
+	/*
+	if (threadState && threadState->GlesEglContext())
+		return threadState;
+	return NULL; */
+	}
+
+
+// free current state object, if any, for this thread
+EXPORT_C void CVghwUtils::ReleaseThreadState()
+	{
+	TEglThreadState* threadState = reinterpret_cast<TEglThreadState*>(Dll::Tls());
+	UTIL_TRACE("CVghwUtils::ReleaseThreadState - object = 0x%x", threadState);
+	if (threadState)
+		{
+		threadState->Destroy();
+		Dll::FreeTls();
+		}
+	}
+
+
+EXPORT_C MEglManagementApi* CVghwUtils::EglManagementApi()
+	{
+	return iEglManagementApi;
+	}
+
+
+EXPORT_C void CVghwUtils::SetEglManagementApi(MEglManagementApi* aEglManagementApi)
+	{
+	UTIL_TRACE("CVghwUtils::SetEglManagementApi  aEglManagementApi=0x%x", aEglManagementApi);
+	iEglManagementApi = aEglManagementApi;
+	}
+
+
+/*
+ Stored pointers into Open GL ES 1.1, GL ES 2 and Open VG are problematic if the DLL is later unloaded.
+ (RSgDriver::Open currently loads & unloads all the Open VG & GL ES DLLs, to determine features to publish.)
+ Possibly Open the DLL again when the non-NULL pointer is fetched by EGL, probably needs flags so that
+ this is only done once.
+ */
+EXPORT_C void CVghwUtils::SetVgApiForEgl(MVgApiForEgl* aVgApiForEgl)
+	{
+	UTIL_TRACE("CVghwUtils::SetVgApiForEgl  aVgApiForEgl=0x%x, iVgApiForEgl=0x%x, iLoadedOpenVgDll=0x%x",
+			aVgApiForEgl, iVgApiForEgl, iLoadedOpenVgDll);
+	// don't let a thread set this to NULL if we have forced the DLL to stay loaded
+	if (aVgApiForEgl || !iLoadedOpenVgDll)
+		{
+		iVgApiForEgl = aVgApiForEgl;
+		}
+	}
+
+
+EXPORT_C MVgApiForEgl* CVghwUtils::VgApiForEgl()
+	{
+	if (iVgApiForEgl && !iLoadedOpenVgDll)
+		{ // ensure Open VG DLL stays loaded from now on
+		_LIT(KLibOpenVg, "libOpenVG.dll");
+		RLibrary lib;
+		if (lib.Load(KLibOpenVg) == KErrNone)
+			{
+			UTIL_TRACE("CVghwUtils::VgApiForEgl - Open VG dll loaded, iVgApiForEgl=0x%x", iVgApiForEgl);
+			iLoadedOpenVgDll = ETrue;
+			return iVgApiForEgl;
+			}
+		}
+	UTIL_TRACE("CVghwUtils::VgApiForEgl - Open VG dll not loaded or not safe to use");
+	return NULL;
+	}
+
+
+EXPORT_C void CVghwUtils::SetGles11ApiForEgl(MGles11ApiForEgl* aGles11ApiForEgl)
+	{
+	UTIL_TRACE("CVghwUtils::SetGles11ApiForEgl  aGles11ApiForEgl=0x%x, iGles11ApiForEgl=0x%x, iLoadedOpenGles11Dll=0x%x",
+			aGles11ApiForEgl, iGles11ApiForEgl, iLoadedOpenGles11Dll);
+	// don't let a thread set this to NULL if we have forced the DLL to stay loaded
+	if (aGles11ApiForEgl || !iLoadedOpenGles11Dll)
+		{
+		iGles11ApiForEgl = aGles11ApiForEgl;
+		}
+	}
+
+
+EXPORT_C MGles11ApiForEgl* CVghwUtils::Gles11ApiForEgl()
+	{
+	if (iGles11ApiForEgl && !iLoadedOpenGles11Dll)
+		{ // ensure Open VG DLL stays loaded from now on
+		_LIT(KLibOpenGles, "libGLESv1_CM.dll");
+		RLibrary lib;
+		if (lib.Load(KLibOpenGles) == KErrNone)
+			{
+			UTIL_TRACE("CVghwUtils::Gles11ApiForEgl - Open GL ES 1.1 dll loaded, iGles11ApiForEgl=0x%x", iGles11ApiForEgl);
+			iLoadedOpenGles11Dll = ETrue;
+			return iGles11ApiForEgl;
+			}
+		}
+	UTIL_TRACE("CVghwUtils::Gles11ApiForEgl - Open GL ES 1.1 dll not loaded or not safe to use");
+	return NULL;
+	}
+
+
+EXPORT_C void CVghwUtils::SetGles2ApiForEgl(MGles2ApiForEgl* aGles2ApiForEgl)
+	{
+	UTIL_TRACE("CVghwUtils::SetGles2ApiForEgl  aGles2ApiForEgl=0x%x, iGles2ApiForEgl=0x%x, iLoadedOpenGles2Dll=0x%x",
+			aGles2ApiForEgl, iGles2ApiForEgl, iLoadedOpenGles2Dll);
+	// don't let a thread set this to NULL if we have forced the DLL to stay loaded
+	if (aGles2ApiForEgl || !iLoadedOpenGles2Dll)
+		{
+		iGles2ApiForEgl = aGles2ApiForEgl;
+		}
+	}
+
+
+EXPORT_C MGles2ApiForEgl* CVghwUtils::Gles2ApiForEgl()
+	{
+	if (iGles2ApiForEgl && !iLoadedOpenGles2Dll)
+		{ // ensure Open VG DLL stays loaded from now on
+		_LIT(KLibOpenGles2, "libGLESv2.dll");
+		RLibrary lib;
+		if (lib.Load(KLibOpenGles2) == KErrNone)
+			{
+			UTIL_TRACE("CVghwUtils::Gles2ApiForEgl - Open GL ES 2 dll loaded, iGles2ApiForEgl=0x%x", iGles2ApiForEgl);
+			iLoadedOpenGles2Dll = ETrue;
+			return iGles2ApiForEgl;
+			}
+		}
+	UTIL_TRACE("CVghwUtils::Gles2ApiForEgl - Open GL ES 2 dll not loaded or not safe to use");
+	return NULL;
+	}
+
+
+////////////////////////////////////////////////////////////////////////////////////
+
+// factory method
+TEglThreadState* TEglThreadState::New()
+	{
+	UTIL_TRACE("TEglThreadState::New");
+	RHeap* currentHeap = CVghwUtils::SwitchToVghwHeap();
+	TEglThreadState* self = new TEglThreadState();
+	CVghwUtils::SwitchFromVghwHeap(currentHeap);
+	return self;
+	}
+
+
+TEglThreadState::TEglThreadState() :
+	// EGL thread state
+	iEglError(EGL_SUCCESS),
+	iEglHostHasRecentError(EFalse),
+	// currently bound graphics API, initial value from EGL spec 
+	iEglBoundApi(EGL_OPENGL_ES_API),
+	// Open VG thread state 
+	iVgError(VG_NO_ERROR),
+	iVgEglContext(EGL_NO_CONTEXT),
+	iVgCommandsSinceGetError(EFalse),
+	iVgCommandsSinceFlush(EFalse),
+	iVgCommandsSinceFinish(EFalse),
+	// Open GL ES 1.1 state
+	iGlesError(GL_NO_ERROR),
+	iGlesEglContext(EGL_NO_CONTEXT),
+	iGlesCommandsSinceGetError(EFalse),
+	iGlesCommandsSinceFlush(EFalse),
+	iGlesCommandsSinceFinish(EFalse)
+	{}
+
+
+void TEglThreadState::Destroy()
+	{
+	UTIL_TRACE("TEglThreadState::Destroy");
+	RHeap* currentHeap = CVghwUtils::SwitchToVghwHeap();
+	delete this;
+	CVghwUtils::SwitchFromVghwHeap(currentHeap);
+	}
+
+
+TEglThreadState::~TEglThreadState()
+	{}
+
+
+// -----------------------------------------------------------------------------
+// 
+// -----------------------------------------------------------------------------
+//
+EXPORT_C EGLBoolean TEglThreadState::ExecEglBooleanCmd(EglRFC& aEglApiData)
+	{
+	CVghwUtils::DriverExecuteCommand(aEglApiData.Data());
+
+	EGLBoolean hostResult = (EGLBoolean) aEglApiData.ReturnValue();
+	if (hostResult == EGL_TRUE)
+		{
+		ClearEglError();
+		}
+	else
+		{ // error present in host graphics stack
+		iEglHostHasRecentError = ETrue;
+		}
+	return hostResult;
+	}
+
+
+EXPORT_C EGLContext TEglThreadState::ExecEglContextCmd(EglRFC& aEglApiData)
+	{
+	CVghwUtils::DriverExecuteCommand(aEglApiData.Data());
+
+	EGLContext hostResult = (EGLContext) aEglApiData.ReturnValue();
+	if (hostResult != EGL_NO_CONTEXT)
+		{
+		ClearEglError();
+		}
+	else
+		{ // error present in host graphics stack
+		iEglHostHasRecentError = ETrue;
+		}
+	return hostResult;
+	}
+
+
+EXPORT_C EGLSurface TEglThreadState::ExecEglSurfaceCmd(EglRFC& aEglApiData)
+	{
+	CVghwUtils::DriverExecuteCommand(aEglApiData.Data());
+
+	EGLSurface hostResult = (EGLSurface) aEglApiData.ReturnValue();
+	if (hostResult != EGL_NO_SURFACE)
+		{
+		ClearEglError();
+		}
+	else
+		{ // error present in host graphics stack
+		iEglHostHasRecentError = ETrue;
+		}
+	return hostResult;
+	}
+
+
+/*
+ Get details of the last EGL api error.
+ (Resets stored last error value to EGL_SUCCESS.)
+
+ @return EGL_SUCCESS or an EGL_xxxx error constant.
+ */
+EXPORT_C EGLint TEglThreadState::EglError()
+	{
+	EGLint eglError = iEglError;
+	if (iEglHostHasRecentError)
+		{
+		// last EGL command was executed/failed in the Host side, so need to ask it for the error
+		RemoteFunctionCallData rfcdata; EglRFC eglApiData(rfcdata);
+		eglApiData.Init(EglRFC::EeglGetError);
+		CVghwUtils::DriverExecuteCommand(eglApiData.Data());
+		eglError = (EGLint)eglApiData.ReturnValue();
+		EGL_ERROR_PRINT("TEglThreadState::EglError newest error fetched from Host EGL", eglError);
+		iEglHostHasRecentError = EFalse;
+		}
+	else
+		{
+		EGL_ERROR_PRINT("TEglThreadState::EglError newest EGL error set by DLL", eglError);
+		}
+	iEglError = EGL_SUCCESS;
+	return eglError;
+	}
+
+
+void TEglThreadState::ExecuteVgCommand(OpenVgRFC& aVgApiData)
+	{
+	CVghwUtils::DriverExecuteCommand(aVgApiData.Data());
+	iVgCommandsSinceGetError = ETrue;
+	iVgCommandsSinceFlush = ETrue;
+	iVgCommandsSinceFinish = ETrue;
+	}
+
+
+void TEglThreadState::ExecuteVgFlushCommand()
+	{
+	if (iVgCommandsSinceFlush)
+		{
+		RemoteFunctionCallData data; OpenVgRFC vgApiData(data);
+		vgApiData.Init(OpenVgRFC::EvgFlush);
+
+		CVghwUtils::DriverExecuteCommand(vgApiData.Data());
+		iVgCommandsSinceFlush = EFalse;
+		iVgCommandsSinceFinish = EFalse;
+		}
+	}
+
+
+void TEglThreadState::ExecuteVgFinishCommand()
+	{
+	if (iVgCommandsSinceFinish)
+		{
+		RemoteFunctionCallData data; OpenVgRFC vgApiData(data);
+		vgApiData.Init(OpenVgRFC::EvgFinish);
+
+		CVghwUtils::DriverExecuteCommand(vgApiData.Data());
+		iVgCommandsSinceFinish = EFalse;
+		}
+	}
+
+
+VGErrorCode TEglThreadState::VgError()
+	{
+	VGErrorCode vgError = iVgError;
+	VG_ERROR_PRINT("TEglThreadState::VgError oldest Open VG DLL error", vgError);
+
+	if (iVgCommandsSinceGetError)
+		{ // fetch and clear the host error state
+		VGErrorCode hostVgError = GetHostVgError();
+		VG_ERROR_PRINT("TEglThreadState::VgError oldest Host Open VG DLL error", hostVgError);
+
+		if (vgError == VG_NO_ERROR)
+			{
+			vgError = hostVgError;
+			}
+		iVgCommandsSinceGetError = EFalse;
+		}
+
+	iVgError = VG_NO_ERROR;
+	return vgError;
+	}
+
+
+VGErrorCode TEglThreadState::GetHostVgError()
+	{
+	RemoteFunctionCallData data; OpenVgRFC vgApiData(data);
+	vgApiData.Init( OpenVgRFC::EvgGetError );
+
+	CVghwUtils::DriverExecuteCommand(vgApiData.Data());
+	return (VGErrorCode)vgApiData.ReturnValue();
+	}
+
+
+// Open GL ES
+
+GLenum TEglThreadState::GlesError()
+	{
+	GLenum glesError = iGlesError;
+	GLES_ERROR_PRINT("TEglThreadState::GlesError oldest Open GL ES DLL error", glesError);
+
+	if (iGlesCommandsSinceGetError)
+		{ // fetch and clear the host error state
+		GLenum hostGlesError = GetHostGlesError();
+		GLES_ERROR_PRINT("TEglThreadState::GlesError oldest Host Open GL ES DLL error", hostGlesError);
+
+		if (glesError == GL_NO_ERROR)
+			{
+			glesError = hostGlesError;
+			}
+		iGlesCommandsSinceGetError = EFalse;
+		}
+
+	iGlesError = GL_NO_ERROR;
+	return glesError;
+	}
+
+
+GLenum TEglThreadState::GetHostGlesError()
+	{
+	RemoteFunctionCallData data;
+	OpenGlES11RFC glesApiData(data);
+	glesApiData.Init(OpenGlES11RFC::EglGetError);
+	CVghwUtils::DriverExecuteCommand(glesApiData.Data());
+	return (GLint)glesApiData.ReturnValue();
+	}
+
+
+void TEglThreadState::ExecuteGlesCommand(RemoteFunctionCall& aGlesRequestData)
+	{
+	CVghwUtils::DriverExecuteCommand(aGlesRequestData.Data());
+	iGlesCommandsSinceGetError = ETrue;
+	iGlesCommandsSinceFlush = ETrue;
+	iGlesCommandsSinceFinish = ETrue;
+	}
+
+
+void TEglThreadState::ExecuteGlesFlushCommand()
+	{
+	if (iGlesCommandsSinceFlush)
+		{
+		RemoteFunctionCallData rfcData;
+		OpenGlES11RFC glesApiData( rfcData );
+		glesApiData.Init(OpenGlES11RFC::EglFlush, RemoteFunctionCallData::EOpRequest);
+		CVghwUtils::DriverExecuteCommand(glesApiData.Data());
+		iGlesCommandsSinceFlush = EFalse;
+		iGlesCommandsSinceFinish = EFalse;
+		}
+	}
+
+
+void TEglThreadState::ExecuteGlesFinishCommand()
+	{
+	if (iGlesCommandsSinceFinish)
+		{
+		RemoteFunctionCallData rfcData;
+		OpenGlES11RFC glesApiData( rfcData );
+		glesApiData.Init(OpenGlES11RFC::EglFinish, RemoteFunctionCallData::EOpRequest);
+		CVghwUtils::DriverExecuteCommand(glesApiData.Data());
+		iGlesCommandsSinceFinish = EFalse;
+		}
+	}
+
+
+// Open VG state
+void TEglThreadState::SetVgError(VGErrorCode aVgError)
+	{
+	VGHWPANIC_ASSERT_DEBUG( (aVgError >= VG_BAD_HANDLE_ERROR) && (aVgError <= 0x10FF), EVghwPanicBadVgErrorValue);
+	// for Open VG track the oldest uncleared error
+	VG_ERROR_PRINT("TEglThreadState::SetVgError error", aVgError);
+	if ( (iVgError == VG_NO_ERROR) && (aVgError >= VG_BAD_HANDLE_ERROR) && (aVgError <= 0x10FF) )
+		{
+		if (iVgCommandsSinceGetError)
+			{
+			iVgError = GetHostVgError();
+			VG_ERROR_PRINT("TEglThreadState::SetVgError oldest Host Open VG DLL error", iVgError);
+			if (iVgError != VG_NO_ERROR)
+				{
+				return;
+				}
+			}
+		iVgError = aVgError;
+		}
+	}
+
+
+EGLContext TEglThreadState::VgEglContext()
+	{
+	return iVgEglContext;
+	}
+
+
+// Open GL ES thread state
+void TEglThreadState::SetGlesError(GLenum aGlesError)
+	{
+	VGHWPANIC_ASSERT_DEBUG( (aGlesError >= GL_INVALID_ENUM) && (aGlesError <= 0x05FF), EVghwPanicBadGlesErrorValue);
+	// for Open GL ES track the oldest uncleared error
+	GLES_ERROR_PRINT("TEglThreadState::SetGlesError error", aGlesError);
+	if ( (iGlesError == GL_NO_ERROR) && (aGlesError >= GL_INVALID_ENUM) && (aGlesError <= 0x05FF) )
+		{
+		if (iGlesCommandsSinceGetError)
+			{
+			iGlesError = GetHostGlesError();
+			GLES_ERROR_PRINT("TEglThreadState::SetGlesError oldest Host Open GL ES DLL error", iGlesError);
+			if (iGlesError != GL_NO_ERROR)
+				{
+				return;
+				}
+			}
+		iGlesError = aGlesError;
+		}
+	}
+
+
+EGLContext TEglThreadState::GlesEglContext()
+	{
+	return iGlesEglContext;
+	}
+
+// -----------------------------------------------------------------------------
+// Use driver to discover base address of the frame memory.
+// -----------------------------------------------------------------------------
+//	  
+EXPORT_C TInt TVghwUtils::GetFrameBufferBaseAddress( TUint32& aHWAddress )
+	{
+	UTIL_TRACE("TVghwUtils::GetFrameBufferBaseAddress");
+	return VghwSingleton.Driver().GetFrameBufferBaseAddress( aHWAddress );
+	}
+
+#ifdef _DEBUG
+static void EglErrorPrint(char* aTitle, EGLint aEglError)
+	{
+	char* errName = NULL;
+	switch (aEglError)
+		{
+		case EGL_SUCCESS: errName = "EGL_SUCCESS"; break;
+		case EGL_NOT_INITIALIZED: errName = "EGL_NOT_INITIALIZED"; break;
+		case EGL_BAD_ACCESS: errName = "EGL_BAD_ACCESS"; break;
+		case EGL_BAD_ALLOC: errName = "EGL_BAD_ALLOC"; break;
+		case EGL_BAD_ATTRIBUTE: errName = "EGL_BAD_ATTRIBUTE"; break;
+		case EGL_BAD_CONFIG: errName = "EGL_BAD_CONFIG"; break;
+		case EGL_BAD_CONTEXT: errName = "EGL_BAD_CONTEXT"; break;
+		case EGL_BAD_CURRENT_SURFACE: errName = "EGL_BAD_CURRENT_SURFACE"; break;
+		case EGL_BAD_DISPLAY: errName = "EGL_BAD_DISPLAY"; break;
+		case EGL_BAD_MATCH: errName = "EGL_BAD_MATCH"; break;
+		case EGL_BAD_NATIVE_PIXMAP: errName = "EGL_BAD_NATIVE_PIXMAP"; break;
+		case EGL_BAD_NATIVE_WINDOW: errName = "EGL_BAD_NATIVE_WINDOW"; break;
+		case EGL_BAD_PARAMETER: errName = "EGL_BAD_PARAMETER"; break;
+		case EGL_BAD_SURFACE: errName = "EGL_BAD_SURFACE"; break;
+		case EGL_CONTEXT_LOST: errName = "EGL_CONTEXT_LOST"; break;
+		default: break; // Error is from a new version of EGL
+		}
+
+	if (errName)
+		{
+		UTIL_TRACE( "  %s=%s (0x%x)", aTitle, errName, aEglError);
+		}
+	else
+		{
+		UTIL_TRACE( "  %s=0x%x", aTitle, aEglError);
+		}
+	}
+
+
+static void VgErrorPrint(char* aTitle, VGErrorCode aVgError)
+	{
+	char* errName = NULL;
+	switch (aVgError)
+		{
+		case VG_NO_ERROR: errName = "VG_NO_ERROR"; break;
+		case VG_BAD_HANDLE_ERROR: errName = "VG_BAD_HANDLE_ERROR"; break;
+		case VG_ILLEGAL_ARGUMENT_ERROR: errName = "VG_ILLEGAL_ARGUMENT_ERROR"; break;
+		case VG_OUT_OF_MEMORY_ERROR: errName = "VG_OUT_OF_MEMORY_ERROR"; break;
+		case VG_PATH_CAPABILITY_ERROR: errName = "VG_PATH_CAPABILITY_ERROR"; break;
+		case VG_UNSUPPORTED_IMAGE_FORMAT_ERROR: errName = "VG_UNSUPPORTED_IMAGE_FORMAT_ERROR"; break;
+		case VG_UNSUPPORTED_PATH_FORMAT_ERROR: errName = "VG_UNSUPPORTED_PATH_FORMAT_ERROR"; break;
+		case VG_IMAGE_IN_USE_ERROR: errName = "VG_IMAGE_IN_USE_ERROR"; break;
+		case VG_NO_CONTEXT_ERROR: errName = "VG_NO_CONTEXT_ERROR"; break;
+		default: break; // unknown error code from a new version of Open VG
+		}
+
+	if (errName)
+		{
+		UTIL_TRACE( "  %s=%s (0x%x)", aTitle, errName, aVgError);
+		}
+	else
+		{
+		UTIL_TRACE( "  %s=0x%x", aTitle, aVgError);
+		}
+	}
+
+
+static void GlesErrorPrint(char* aTitle, GLenum aGlesError)
+	{
+	char* errName = NULL;
+	switch (aGlesError)
+		{
+		case GL_NO_ERROR: errName = "GL_NO_ERROR"; break;
+		case GL_INVALID_ENUM: errName = "GL_INVALID_ENUM"; break;
+		case GL_INVALID_VALUE: errName = "GL_INVALID_VALUE"; break;
+		case GL_INVALID_OPERATION: errName = "GL_INVALID_OPERATION"; break;
+		case GL_STACK_OVERFLOW: errName = "GL_STACK_OVERFLOW"; break;
+		case GL_STACK_UNDERFLOW: errName = "GL_STACK_UNDERFLOW"; break;
+		case GL_OUT_OF_MEMORY: errName = "GL_OUT_OF_MEMORY"; break;
+		default: break; // unknown error code from a new version of Open GL ES
+		}
+
+	if (errName)
+		{
+		UTIL_TRACE( "  %s=%s (0x%x)", aTitle, errName, aGlesError);
+		}
+	else
+		{
+		UTIL_TRACE( "  %s=0x%x", aTitle, aGlesError);
+		}
+	}
+#endif
+
+
+// end of file vghwutils.cpp