graphicsdeviceinterface/directgdiadaptation/hwsrc/directgdidriverprocessstate.cpp
changeset 0 5d03bc08d59c
equal deleted inserted replaced
-1:000000000000 0:5d03bc08d59c
       
     1 // Copyright (c) 2007-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 //
       
    15 
       
    16 #include "directgdidriverprocessstate.h"
       
    17 
       
    18 
       
    19 const TInt KMaxProcessStateHeapSize = 0x100000;
       
    20 
       
    21 
       
    22 /** 
       
    23 Reports any error that occurs. 
       
    24 This is #defined so that we retain correct line information for the debug stream.
       
    25 */
       
    26 #define ProcessEglError(err) \
       
    27 	{ \
       
    28 	const EGLint eglError = eglGetError(); \
       
    29 	if (eglError == EGL_BAD_ALLOC) \
       
    30 		err = KErrNoMemory; \
       
    31 	else if (eglError == EGL_CONTEXT_LOST) \
       
    32 		err = KErrDied; \
       
    33 	else \
       
    34 		err = KErrGeneral; \
       
    35 	TBuf16<256> _message; \
       
    36 	_message.Format(_L16("EGL Error: %x\n"), eglError); \
       
    37 	GRAPHICS_LOGD_DEBUG(_message); \
       
    38 	}
       
    39 /**
       
    40 Image source data constructor.
       
    41 @param aSgImageId The unique identifier of the RSgImage used to create the EGLImage and VGImage.
       
    42 @param aEglImage The EGLImage created from the RSgImage.
       
    43 @param aVgImage The VGImage created from aEglImage.
       
    44 @panic  DGDIAdapter 48, if invalid images are passed in.
       
    45 */
       
    46 CImageSourceData::CImageSourceData(const TSgDrawableId& aSgImageId, EGLImageKHR aEglImage, VGImage aVgImage) :
       
    47 	iSgImageId(aSgImageId),
       
    48 	iEglImage(aEglImage),
       
    49 	iVgImage(aVgImage)
       
    50 	{
       
    51 	GRAPHICS_ASSERT_DEBUG(iEglImage != EGL_NO_IMAGE_KHR, EDirectGdiPanicImageSourceDataConstructorError);
       
    52 	GRAPHICS_ASSERT_DEBUG(iVgImage != VG_INVALID_HANDLE, EDirectGdiPanicImageSourceDataConstructorError);
       
    53 	}
       
    54 
       
    55 /**
       
    56 Image source data destructor.
       
    57 @panic  DGDIAdapter 49, if reference count is not zero when this funtion is called.
       
    58 */
       
    59 CImageSourceData::~CImageSourceData()
       
    60 	{
       
    61 	GRAPHICS_ASSERT_ALWAYS(iRefCount == 0, EDirectGdiPanicImageSourceDataRefCountError);
       
    62 	}
       
    63 
       
    64 XDirectGdiDriverProcessState::XDirectGdiDriverProcessState()
       
    65 	{
       
    66 	iCreateMutexErr = iMutex.CreateLocal();
       
    67 	}
       
    68 
       
    69 
       
    70 /**
       
    71 Creates a heap to store EGL and VG images. This heap will be shared between threads in 
       
    72 the current process. This is necessary as EGL images are shared between threads, and an attempt
       
    73 to create an EGL image from a RSgImage in two different threads would fail if the EGL image was not 
       
    74 also shared. Also gets function pointers to image creation and destruction methods in EGL and saves 
       
    75 them for use later. Note that Initialize() must be called before you call CreateVgImage() or
       
    76 DestroyVgImage().
       
    77 
       
    78 @pre The client has called MutexCreationStatus() and checked for KErrNone. 
       
    79 
       
    80 @param aDisplay The current EGL display handle 
       
    81 
       
    82 @return KErrNone if successful, KErrNoMemory if we fail to create the heap, KErrGeneral
       
    83 if we encounter an EGL error, otherwise one of the system-wide error codes.
       
    84  */
       
    85 TInt XDirectGdiDriverProcessState::Initialize(EGLDisplay aDisplay)
       
    86 	{
       
    87 	iMutex.Wait();
       
    88 	
       
    89 	// No need to re-initialize everything if we have already been initialized.
       
    90 	TInt err = KErrNone;
       
    91 	if (iLocalHeap == NULL)
       
    92 		{
       
    93 		// Create a heap that will be used to store EGLImages and VGImages that are created
       
    94 		// when the driver creates a source image (in CDirectGdiDriverImpl::CreateDrawableSource())
       
    95 		iLocalHeap = UserHeap::ChunkHeap(NULL, 0, KMaxProcessStateHeapSize);
       
    96 		if (iLocalHeap == NULL)
       
    97 			{
       
    98 			err = KErrNoMemory;		
       
    99 			}
       
   100 		}
       
   101 	
       
   102 	// Check the availability of the required EGL/VG extensions
       
   103 	if (err == KErrNone)
       
   104 		{
       
   105 		if (!iCheckedExtensionsAvailable)
       
   106 			{
       
   107 			err = CheckAllEglExtensions(aDisplay);				
       
   108 			iCheckedExtensionsAvailable = ETrue;
       
   109 			
       
   110 #ifdef _DEBUG_DIRECTGDI
       
   111 			RDebug::Printf("VG_VENDOR: %s\n", vgGetString(VG_VENDOR));
       
   112 			RDebug::Printf("VG_RENDERER : %s\n", vgGetString(VG_RENDERER));
       
   113 			RDebug::Printf("VG_VERSION : %s\n", vgGetString(VG_VERSION));
       
   114 #endif	
       
   115 			}
       
   116 		}
       
   117 					
       
   118 	// Get function pointers for EGLImage creation and destruction and VGImage creation EGL functions.
       
   119 	// These need to be refreshed every time this process state is initialised as it cannot be guaranteed
       
   120 	// that the function pointers will remain the same after this process state was last closed
       
   121 	// (and EGL was terminated).
       
   122 	if (err == KErrNone)
       
   123 		{
       
   124 		iPfnEglCreateImageKHR = reinterpret_cast<TeglCreateImageKHRTypefPtr>(eglGetProcAddress("eglCreateImageKHR"));		
       
   125 		if (iPfnEglCreateImageKHR == NULL)
       
   126 			{
       
   127 			ProcessEglError(err);
       
   128 			err = KErrNotSupported;
       
   129 			}		
       
   130 		}
       
   131 	
       
   132 	if (err == KErrNone)
       
   133 		{
       
   134 		iPfnEglDestroyImageKHR = reinterpret_cast<TeglDestroyImageKHRTypefPtr>(eglGetProcAddress("eglDestroyImageKHR"));	
       
   135 		if (iPfnEglDestroyImageKHR == NULL)
       
   136 			{
       
   137 			ProcessEglError(err);
       
   138 			err = KErrNotSupported;
       
   139 			}		
       
   140 		}
       
   141 	
       
   142 	if (err == KErrNone)
       
   143 		{
       
   144 		iPfnVgCreateImageTargetKHR = reinterpret_cast<TvgCreateEGLImageTargetKHRTypefPtr>(eglGetProcAddress("vgCreateEGLImageTargetKHR"));		
       
   145 		if (iPfnVgCreateImageTargetKHR == NULL)
       
   146 			{
       
   147 			ProcessEglError(err);
       
   148 			err = KErrNotSupported;
       
   149 			}		
       
   150 		}
       
   151 	iMutex.Signal();
       
   152 		
       
   153 	return err;
       
   154 	}
       
   155 
       
   156 /**
       
   157 Destructor, asserts that the instance count is zero, and the count of images stored is zero.
       
   158 
       
   159 @panic DGDIAdapter 50, if the instance count is not zero (debug-only).
       
   160 @panic DGDIAdapter 51, if the image count is not zero (debug-only).
       
   161  */
       
   162 XDirectGdiDriverProcessState::~XDirectGdiDriverProcessState()
       
   163 	{
       
   164 	if (iLocalHeap != NULL)
       
   165 		{
       
   166 		iLocalHeap->Close();
       
   167 		}
       
   168 	iMutex.Close();
       
   169 		
       
   170 	GRAPHICS_ASSERT_DEBUG(iDriverInstanceCount == 0, EDirectGdiPanicProcessStateInstanceCountError);	
       
   171 	GRAPHICS_ASSERT_DEBUG(iImages.Count() == 0, EDirectGdiPanicProcessStateImageCountError);
       
   172 	}
       
   173 
       
   174 /**
       
   175 Creates a VGImage from the passed RSgImage. This method first creates a EGLImageKHR from
       
   176 the RSgImage, from which it can create a VGImage. The EGLImageKHR and the VGImage are saved
       
   177 so that they can be shared if a user attempts to create another VGImage from the same RSgImage.
       
   178 If a VGImage has already been created from the passed RSgImage, the existing image is returned
       
   179 instead of a new one being created. This will increment the reference count on that stored image.
       
   180 
       
   181 @param aDisplay The EGL display to associate the image with.
       
   182 @param aVgImageRet A handle to the VGImage created is returned here.
       
   183 @param aSgImage The VGImage will be created from this RSgImage.
       
   184 
       
   185 @pre Initialize() has been called.
       
   186 
       
   187 @return KErrNone if the image is created successfully, KErrGeneral if an EGL error occurs,
       
   188 otherwise one of the system-wide error codes.
       
   189 
       
   190 @panic DGDIAdapter 33, if one of the member EGL function pointers is NULL (debug-only).
       
   191 If this happens it may be that Initialize() has not been called for this process state.
       
   192 @panic DGDIAdapter 36, if aDisplay is EGL_NO_DISPLAY (debug-only).
       
   193  */
       
   194  TInt XDirectGdiDriverProcessState::CreateVgImage(EGLDisplay aDisplay, VGImage& aVgImageRet, const RSgImage& aSgImage)
       
   195 	{
       
   196 	VGImage vgImage = VG_INVALID_HANDLE;
       
   197 	TInt err = KErrNone;	
       
   198 	aVgImageRet = VG_INVALID_HANDLE;
       
   199 	
       
   200 	iMutex.Wait();	
       
   201 	// If this image has already been created, just return a handle to the
       
   202 	// previously created one.
       
   203 	if (ImageExists(aSgImage, vgImage))
       
   204 		{
       
   205 		aVgImageRet = vgImage;
       
   206 		iMutex.Signal();
       
   207 		return KErrNone;
       
   208 		}
       
   209 	
       
   210 	// If the function pointers are NULL, Initialize() may not have been called
       
   211 	GRAPHICS_ASSERT_DEBUG(iPfnEglCreateImageKHR, EDirectGdiPanicProcessStateNotInitialized);	
       
   212 	GRAPHICS_ASSERT_DEBUG(iPfnEglDestroyImageKHR, EDirectGdiPanicProcessStateNotInitialized);	
       
   213 	GRAPHICS_ASSERT_DEBUG(iPfnVgCreateImageTargetKHR, EDirectGdiPanicProcessStateNotInitialized);
       
   214 	GRAPHICS_ASSERT_DEBUG(aDisplay != EGL_NO_DISPLAY, EDirectGdiPanicNoDisplay);
       
   215 	
       
   216 	// Create an EGLImage from the passed RSgImage, then create a VGImage from that and 
       
   217 	// assign the VGImage to the newly created source. (The EGL image creation functions
       
   218 	// have already been retreived at this stage as function pointers using eglGetProcAddress()
       
   219 	// in InitialiseEgl())	
       
   220 	
       
   221 	// Pass in the preserved attribute. Without this the existing image data could be trashed.
       
   222 	EGLint createImageAttribs[] = {EGL_IMAGE_PRESERVED_SYMBIAN, EGL_TRUE, 
       
   223 								   		 EGL_NONE};
       
   224 	
       
   225 	EGLImageKHR eglImage = iPfnEglCreateImageKHR(aDisplay, EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR, reinterpret_cast<EGLClientBuffer>(&aSgImage), createImageAttribs);
       
   226 	if (eglImage == EGL_NO_IMAGE_KHR)
       
   227 		{
       
   228 		ProcessEglError(err);
       
   229 		}
       
   230 		
       
   231 	if (err == KErrNone)
       
   232 		{
       
   233 		vgImage = iPfnVgCreateImageTargetKHR(eglImage);	
       
   234 		if (vgImage == VG_INVALID_HANDLE)
       
   235 			{				
       
   236 			ProcessEglError(err);
       
   237 			}		
       
   238 		}
       
   239 		
       
   240 	if (err == KErrNone)
       
   241 		{
       
   242 		// Add the image to the array of images on the process heap
       
   243 		err = AddImage(aSgImage, eglImage, vgImage);
       
   244 		}
       
   245 	
       
   246 	if (err == KErrNone)
       
   247 		{		
       
   248 		aVgImageRet = vgImage;
       
   249 		}
       
   250 	else
       
   251 		{		
       
   252 		// Clean up
       
   253 		if (vgImage != VG_INVALID_HANDLE)
       
   254 			{
       
   255 			vgDestroyImage(vgImage);
       
   256 			}
       
   257 		iPfnEglDestroyImageKHR(aDisplay, eglImage);		
       
   258 		}
       
   259 	
       
   260 	iMutex.Signal();
       
   261 	
       
   262 	return err;
       
   263 	}
       
   264  
       
   265 /**
       
   266 Destroys the passed VGImage. Searches for the image in the image array and
       
   267 decrements its reference count if found. Destroys the image when the reference count
       
   268 reaches zero.
       
   269 
       
   270 @param aDisplay The EGLDisplay the VGImage to be destroyed was created with.
       
   271 @param aVgImage A handle to the VGImage to destroy.
       
   272 
       
   273 @return KErrNone if the image is destroyed successfully, otherwise one of the system-wide
       
   274 error codes.
       
   275 
       
   276 @panic DGDIAdapter 33, if the EGL function pointer for destroying a VGImage is NULL (debug-only).
       
   277  */
       
   278 TInt XDirectGdiDriverProcessState::DestroyVgImage(EGLDisplay aDisplay, VGImage aVgImage)
       
   279 	{	
       
   280 	GRAPHICS_ASSERT_DEBUG(iPfnEglDestroyImageKHR, EDirectGdiPanicProcessStateNotInitialized);
       
   281 	
       
   282 	iMutex.Wait();
       
   283 	TInt err = RemoveImage(aDisplay, aVgImage);	
       
   284 	iMutex.Signal();
       
   285 	
       
   286 	return err;
       
   287 	}
       
   288 
       
   289 /**
       
   290 Increments the instance count.
       
   291 */
       
   292 void XDirectGdiDriverProcessState::OpenDriver()
       
   293 	{
       
   294 	iMutex.Wait();
       
   295 	++iDriverInstanceCount;
       
   296 	iMutex.Signal();
       
   297 	}
       
   298 
       
   299 /**
       
   300 Decrements the instance count.
       
   301 If this is the last instance of a DirectGDI driver, the associated EGL display is terminated, and
       
   302 there should be no images left in the array as they should all have been destroyed.
       
   303 
       
   304 @param aDriverEglDisplay An EGLDisplay associated with the driver being closed. If this is the last
       
   305        driver being closed, the display is destroyed.
       
   306 @panic DGDIAdapter 51, if the image count is not zero (debug-only).
       
   307  */
       
   308 void XDirectGdiDriverProcessState::CloseDriver(EGLDisplay& aDriverEglDisplay)
       
   309 	{
       
   310 	iMutex.Wait();
       
   311 	if (--iDriverInstanceCount == 0 && aDriverEglDisplay != EGL_NO_DISPLAY)
       
   312 		{
       
   313 		eglTerminate(aDriverEglDisplay);	
       
   314 		aDriverEglDisplay = EGL_NO_DISPLAY;
       
   315 		// Set the function pointers to NULL as cannot be guaranteed that they will be recreated at the same address
       
   316 		// when EGL is next initialised.
       
   317 		iPfnEglCreateImageKHR = NULL;
       
   318 		iPfnEglDestroyImageKHR = NULL;
       
   319 		iPfnVgCreateImageTargetKHR = NULL;
       
   320 		GRAPHICS_ASSERT_DEBUG(iImages.Count() == 0, EDirectGdiPanicProcessStateImageCountError);
       
   321 		}
       
   322 	iMutex.Signal();
       
   323 	}
       
   324 
       
   325 /** 
       
   326 Check that the following EGL extensions are available:
       
   327 	EGL_SYMBIAN_PIXMAP_TYPE_RSGIMAGE
       
   328 	EGL_KHR_image
       
   329 	EGL_SYMBIAN_image_preserved
       
   330 	
       
   331 According to the spec, OpenVG extensions cannot be checked until a context has been made current, 
       
   332 which has not happened at this point, so currently there is no check for VG_KHR_EGL_image extension. 
       
   333 	
       
   334 @pre eglInitialize() must have been called for the passed EGLDisplay.	
       
   335 	
       
   336 @param aDisplay The current EGL display handle. 	
       
   337 
       
   338 @return KErrNone if all the extensions are available, KErrNotSupported if one or more
       
   339 of the extensions are not supported by the EGL driver.	
       
   340  */
       
   341 TInt XDirectGdiDriverProcessState::CheckAllEglExtensions(EGLDisplay aDisplay) const
       
   342 	{
       
   343 	_LIT8(KEglRSgImage, "EGL_SYMBIAN_PIXMAP_TYPE_RSGIMAGE");		
       
   344 	_LIT8(KEglKhrImage, "EGL_KHR_image");
       
   345 	_LIT8(KEglImagePreserved, "EGL_SYMBIAN_image_preserved");
       
   346 		
       
   347 	TInt err = CheckForEglExtension(aDisplay, KEglRSgImage);
       
   348 	
       
   349 	if (err == KErrNone)
       
   350 		{
       
   351 		err = CheckForEglExtension(aDisplay, KEglKhrImage);
       
   352 		}
       
   353 	
       
   354 	if (err == KErrNone)
       
   355 		{
       
   356 		err = CheckForEglExtension(aDisplay, KEglImagePreserved);
       
   357 		}
       
   358 			
       
   359 	return err;
       
   360 	}
       
   361 
       
   362 /**
       
   363 Checks whether the passed EGL extension string is available with this EGL driver.
       
   364 
       
   365 @param aDisplay The current EGL display handle.
       
   366 @param aExtensionString The EGL extension string to search for.
       
   367 
       
   368 @return KErrNotSupported is the extension string is not found, KErrNone if it is found successfully.
       
   369  */
       
   370 TInt XDirectGdiDriverProcessState::CheckForEglExtension(EGLDisplay aDisplay,
       
   371 															  const TDesC8& aExtensionString) const
       
   372 {
       
   373 	const TText8* extensions = reinterpret_cast<const TText8*>(eglQueryString(aDisplay, EGL_EXTENSIONS));
       
   374 	
       
   375 	TBool found = EFalse;	
       
   376 	if (extensions)
       
   377 		{		
       
   378 		TPtrC8 ext(extensions);
       
   379 		if (ext.Find(aExtensionString) != KErrNotFound)
       
   380 			{
       
   381 			found = ETrue;
       
   382 			}
       
   383 		}
       
   384 	
       
   385 	return (found) ? KErrNone : KErrNotSupported;
       
   386 	}
       
   387 
       
   388 /**
       
   389 Checks to see that the passed RSgImage exists in the image array. Increases
       
   390 the reference count on the image if it is found. The calling method should be holding the mutex
       
   391 iMutex open before calling this method.
       
   392 
       
   393 @param aSgImage The RSgImage to check for.
       
   394 @param aVgImageRet The handle of the VGImage found is returned here.
       
   395 
       
   396 @pre The mutex iMutex is held.  
       
   397 
       
   398 @return ETrue if the image was found, EFalse otherwise.
       
   399 
       
   400 @panic DGDIAdapter 52, if the mutex has not been opened before calling this method. 
       
   401 	   This panic only happens when _DEBUG_DIRECTGDI is defined.
       
   402  */
       
   403 TBool XDirectGdiDriverProcessState::ImageExists(const RSgImage& aSgImage, VGImage& aVgImageRet)
       
   404 	{
       
   405 #ifdef _DEBUG_DIRECTGDI
       
   406 	GRAPHICS_ASSERT_ALWAYS(iMutex.IsHeld(), EDirectGdiPanicImageMutexError);
       
   407 #endif	
       
   408 	aVgImageRet = VG_INVALID_HANDLE;
       
   409 	
       
   410 	CImageSourceData* imageData = FindImage(aSgImage);
       
   411 	if (imageData)
       
   412 		{
       
   413 		aVgImageRet = imageData->VgImage();
       
   414 		imageData->Open();
       
   415 		}
       
   416 
       
   417 	return (aVgImageRet != VG_INVALID_HANDLE);
       
   418 	}
       
   419 
       
   420 /** 
       
   421 Searches for an image in the array of images using the passed RSgImage id to find it.
       
   422 The calling method should be holding the images mutex iMutex open before calling this method.
       
   423 
       
   424 @param aSgImage The RSgImage to search for.
       
   425 
       
   426 @pre The mutex iMutex is held.
       
   427 
       
   428 @return Pointer to the CImageSourceData object held in the images array for the passed
       
   429 RSgImage if it is found, NULL if the image is not found.
       
   430 
       
   431 @panic DGDIAdapter 52, if the mutex has not been opened before calling this method. 
       
   432 	   This panic only happens when _DEBUG_DIRECTGDI is defined.
       
   433  */
       
   434 CImageSourceData* XDirectGdiDriverProcessState::FindImage(const RSgImage& aSgImage)
       
   435 	{
       
   436 #ifdef _DEBUG_DIRECTGDI
       
   437 	GRAPHICS_ASSERT_ALWAYS(iMutex.IsHeld(), EDirectGdiPanicImageMutexError);
       
   438 #endif
       
   439 	CImageSourceData* imageDataRet = NULL;
       
   440 	
       
   441 	for (TInt i = 0; i < iImages.Count() && !imageDataRet; i++)
       
   442 		{
       
   443 		CImageSourceData* imageData = reinterpret_cast<CImageSourceData*>(iImages[i]);
       
   444 		if (imageData->SgImageId() == aSgImage.Id())
       
   445 			{
       
   446 			imageDataRet = imageData;
       
   447 			}
       
   448 		}
       
   449 	
       
   450 	return imageDataRet;
       
   451 	}
       
   452 	
       
   453 /**
       
   454 Adds an image to the images array by saving its RSgImage id, its EGLImageKHR handle and its VGImage
       
   455 handle. A new CImageSourceData object is created to hold this information. This CImageSourceData object 
       
   456 is also used to maintain a reference count on the number of times this image has been shared.
       
   457 The calling method should be holding the images mutex iMutex open before calling this method.
       
   458 
       
   459 @see RemoveImage()
       
   460 
       
   461 @param aSgImage The RSgImage to store, only the RSgImage id will be stored.
       
   462 @param aEglImage The EGLImageKHR to store.
       
   463 @param aVgImage The VGImage to stord.
       
   464 
       
   465 @pre The mutex iMutex is held.
       
   466 @return KErrNone if the details of the passed image are added to the image array successfully, KErrNoMemory
       
   467 if memory allocation fails, otherwise one of the system-wide error codes.
       
   468 
       
   469 @panic DGDIAdapter 52, if the mutex has not been opened before calling this method. 
       
   470 	   This panic only happens when _DEBUG_DIRECTGDI is defined.
       
   471  */
       
   472 TInt XDirectGdiDriverProcessState::AddImage(const RSgImage& aSgImage, EGLImageKHR aEglImage, VGImage aVgImage)
       
   473 	{
       
   474 #ifdef _DEBUG_DIRECTGDI
       
   475 	GRAPHICS_ASSERT_ALWAYS(iMutex.IsHeld(), EDirectGdiPanicImageMutexError);
       
   476 #endif
       
   477 	TInt err = KErrNone;
       
   478 	RHeap *prevHeap = User::SwitchHeap(iLocalHeap);
       
   479 	
       
   480 	CImageSourceData* imageData = new CImageSourceData(aSgImage.Id(), aEglImage, aVgImage);
       
   481 	if (imageData == NULL)
       
   482 		{
       
   483 		err = KErrNoMemory;
       
   484 		}	
       
   485 	if (err == KErrNone)
       
   486 		{				
       
   487 		err = iImages.InsertInAddressOrder(imageData);
       
   488 		}	
       
   489 	if (err == KErrNone)
       
   490 		{
       
   491 		imageData->Open();
       
   492 		}
       
   493 	else
       
   494 		{
       
   495 		delete imageData;
       
   496 		}
       
   497 		
       
   498 	User::SwitchHeap(prevHeap);	
       
   499 	return err;
       
   500 	}
       
   501 	
       
   502 /**
       
   503 Removes the passed image from the image array by searching for it using its VGImage handle.
       
   504 If the image is found in the image array, its reference count will be decremented. When the count reaches
       
   505 zero the image will be removed from the image array and destroyed.
       
   506 
       
   507 @see AddImage()
       
   508 
       
   509 @param aDisplay The EGL display this image was created with.
       
   510 @param aVgImage The hande to a VGImage to be removed from the image array.
       
   511 
       
   512 @pre The mutex iMutex is held.
       
   513 
       
   514 @return KErrNone if the image is removed from the image array successfully, KErrNotFound if the image
       
   515 cannot be found in the image array, otherwise one of the system-wide error codes.
       
   516 
       
   517 @panic DGDIAdapter 52, if the mutex has not been opened before calling this method. 
       
   518 	   This panic only happens when _DEBUG_DIRECTGDI is defined.
       
   519  */
       
   520 TInt XDirectGdiDriverProcessState::RemoveImage(EGLDisplay aDisplay, VGImage aVgImage)
       
   521 	{
       
   522 #ifdef _DEBUG_DIRECTGDI
       
   523 	GRAPHICS_ASSERT_ALWAYS(iMutex.IsHeld(), EDirectGdiPanicImageMutexError);
       
   524 #endif
       
   525 	TInt err = KErrNone;
       
   526 	TInt index = -1;
       
   527 	CImageSourceData* removeImage = NULL;	
       
   528 	
       
   529 	for (TInt i = 0; i < iImages.Count() && (index == -1); i++)
       
   530 		{
       
   531 		if (CImageSourceData* imageData = reinterpret_cast<CImageSourceData*>(iImages[i]))
       
   532 			{
       
   533 			if (imageData->VgImage() == aVgImage)
       
   534 				{
       
   535 				// Only remove the image if the reference count is zero
       
   536 				if (imageData->Close() == 0)					
       
   537 					removeImage	= imageData;									
       
   538 				index = i;
       
   539 				}
       
   540 			}
       
   541 		}
       
   542 			
       
   543 	if (removeImage)
       
   544 		{
       
   545 		// Clean up the EGL and VG images
       
   546 		vgDestroyImage(removeImage->VgImage());
       
   547 		iPfnEglDestroyImageKHR(aDisplay, removeImage->EglImage());
       
   548 		
       
   549 		RHeap *prevHeap = User::SwitchHeap(iLocalHeap);
       
   550 		iImages.Remove(index);
       
   551 		iImages.GranularCompress();
       
   552 		delete removeImage;
       
   553 		User::SwitchHeap(prevHeap);
       
   554 		}
       
   555 	
       
   556 	if (index == -1)
       
   557 		{
       
   558 		err = KErrNotFound;
       
   559 		}
       
   560 	
       
   561 	return err;
       
   562 	}