os/graphics/graphicsresourceservices/graphicsresourceimplementation/test/src/tgraphicsresourceinternal.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     1 // Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 //
    15 
    16 /**
    17  @file
    18  @test
    19  @internalComponent - Internal Symbian test code
    20 */
    21 
    22 #include "tgraphicsresourceinternal.h"
    23 
    24 #include <sgresource/sgresource.h>
    25 #include <sgresource/sgimage.h>
    26 
    27 #include "tgraphicsresourceteststepbase.h"
    28 #include "tgraphicsresourceinternalextensions.h"
    29 
    30 
    31 CTGraphicsResourceInternal::CTGraphicsResourceInternal()
    32 	{
    33 	SetTestStepName(KTGraphicsResourceInternalStep);
    34 	}
    35 
    36 CTGraphicsResourceInternal::~CTGraphicsResourceInternal()
    37 	{
    38 	}
    39 
    40 /**
    41 Overrides of base class pure virtual
    42 Our implementation only gets called if the base class doTestStepPreambleL() did
    43 not leave. That being the case, the current test result value will be EPass.
    44 @leave Gets system wide error code
    45 @return TVerdict code
    46 */
    47 TVerdict CTGraphicsResourceInternal::doTestStepL()
    48 	{
    49 #ifndef _DEBUG
    50 	INFO_PRINTF1(_L("Some tests cannot run in release builds, skipping..."));
    51 #else
    52 	// These tests use KInternalTestsSecondProcess, which can only run in UDEB mode
    53 	// otherwise a panic will occur when attempting to find the UDEB extension interface
    54 	// MSgDriver_Test...
    55 	
    56 	SetTestStepID(_L("GRAPHICS-RESOURCE-0200"));
    57 	TestDriverMemoryLeakL();
    58 	RecordTestResultL();
    59 
    60 	SetTestStepID(_L("GRAPHICS-RESOURCE-0201"));
    61 	TestOOML();
    62 	RecordTestResultL();
    63 
    64 	SetTestStepID(_L("GRAPHICS-RESOURCE-0202"));
    65 	TestInitializeAndShutdownL();
    66 	RecordTestResultL();
    67 
    68 	SetTestStepID(_L("GRAPHICS-RESOURCE-0203"));
    69 	TestInitializeAndShutdownManyTimesL();
    70 	RecordTestResultL();
    71 	
    72 	SetTestStepID(_L("GRAPHICS-RESOURCE-0111"));
    73 	TestResourceProfilingL();
    74 	RecordTestResultL();	
    75 #endif
    76 	
    77 	SetTestStepID(_L("GRAPHICS-RESOURCE-0204"));
    78 	TestUsageBitsL();
    79 	RecordTestResultL();
    80 
    81 	return TestStepResult();
    82 	}
    83 
    84 
    85 /**
    86 @SYMTestCaseID			GRAPHICS-RESOURCE-0200
    87 @SYMTestCaseDesc		Test SGAlloc panic occurs when we deliberately leak resources.
    88 @SYMPREQ				PREQ2637
    89 @SYMFssID				RSgImage::Create()
    90 						RSgDriver:AllocMarkEnd()
    91 @SYMTestPriority		Medium
    92 @SYMTestType			UT
    93 @SYMTestPurpose			To ensure that leaking resources causes the internal Memory Leak checking routine to panic
    94 @SYMTestActions			Initialise the graphics resource component. Call AllocMarkStart to begin memory leak checking
    95 						Create a new RSgImage and then call AllocMarkEnd before closing the RSgImage to cause an 
    96 						SGALLOC panic
    97 @SYMTestExpectedResults	The panic SGALLOC:xxxxxxxx where xxxxxxxx is the address of the leak.
    98  */	
    99 void CTGraphicsResourceInternal::TestDriverMemoryLeakL()
   100 	{
   101 	TSgResIntTestInfo testInfo = { ESgResIntDriverMemoryLeak };
   102 	CreateSecondProcessAndCheckAllocPanicL(KInternalTestsSecondProcess, testInfo, KSgAllocPanic);
   103 	}
   104 
   105 /**
   106 @SYMTestCaseID			GRAPHICS-RESOURCE-0201
   107 @SYMTestCaseDesc		Test Graphics Resource with low memory conditions.
   108 @SYMPREQ				PREQ2637
   109 @SYMFssID				RSgImage
   110 						RSgDrawable
   111 						RSgDriver
   112 @SYMTestPriority		High
   113 @SYMTestType			UT
   114 @SYMTestPurpose			To ensure the correct errors or KErrNoMemory are returned by graphics resource apis under low
   115 						memory conditions.
   116 @SYMTestActions			Force allocations to fail on the RSgDrivers heap, try running each of the conformance tests and
   117 						stress tests to ensure no RSgDriver allocated memory or heap memory is leaked. It also creates
   118 						an image in this process which is used in another process for OOM testing. 
   119 @SYMTestExpectedResults	Return codes of the functions tested should be either the expected value or KErrNoMemory
   120 						This is handled by CTSgTestStepBase::CheckErrorL. No ALLOC or SGALLOC panics should occur.
   121  */	
   122 void CTGraphicsResourceInternal::TestOOML()
   123 	{
   124 	// drawable OOM test
   125 	TSgResIntTestInfo testInfo = { ESgResIntDrawableOOM };
   126 	TInt result = CreateSecondProcessAndDoTestL(KInternalTestsSecondProcess, testInfo);
   127 	TEST(result & EFirstTestPassed);
   128 	
   129 	// image OOM test
   130     testInfo.iTestCase = ESgResIntImageOOM;
   131     
   132     RSgDriver sgDriver;
   133     TInt err = sgDriver.Open();
   134     TESTEL(err == KErrNone, err);
   135     CleanupClosePushL(sgDriver);
   136     
   137     RSgImage image1;
   138     TSgImageInfo info1(TSize(8, 8), EUidPixelFormatRGB_565, ESgUsageBitOpenVgImage);
   139     err = image1.Create(info1);
   140     TESTEL(err == KErrNone, err);
   141     CleanupClosePushL(image1);
   142     testInfo.iDrawableId = image1.Id();
   143             
   144     result = CreateSecondProcessAndDoTestL(KInternalTestsSecondProcess, testInfo);
   145     TEST(result & EFirstTestPassed);
   146         
   147     CleanupStack::PopAndDestroy(2, &sgDriver); 
   148 	}
   149 /**
   150 @SYMTestCaseID			GRAPHICS-RESOURCE-0202
   151 @SYMTestCaseDesc		Test valid resource count
   152 @SYMPREQ				PREQ2637
   153 @SYMFssID				RSgImage
   154 						RSgDrawable
   155 						RSgDriver
   156 @SYMTestPriority		Low
   157 @SYMTestType			UT
   158 @SYMTestPurpose			To ensure that RSgDriver reports the correct local resource count when images are opened and closed.
   159 @SYMTestActions			Open an RSgDriver and create an image, then close it checking the resource count of the
   160 						driver is valid at each stage (0,1,0).
   161 @SYMTestExpectedResults	Resource counts should be as expected.
   162  */	
   163 void CTGraphicsResourceInternal::TestInitializeAndShutdownL()
   164 	{
   165 	TSgResIntTestInfo testInfo = { ESgResIntInitializeAndShutdown };
   166 	TInt result = CreateSecondProcessAndDoTestL(KInternalTestsSecondProcess, testInfo);
   167 	TEST(result & EFirstTestPassed);
   168 	TEST(result & ESecondTestPassed);
   169 	TEST(result & EThirdTestPassed);
   170 	}
   171 
   172 /*
   173 @SYMTestCaseID			GRAPHICS-RESOURCE-0203
   174 @SYMTestCaseDesc		Test valid resource count with multiple driver sessions
   175 @SYMPREQ				PREQ2637
   176 @SYMFssID				RSgImage
   177 						RSgDrawable
   178 						RSgDriver
   179 @SYMTestPriority		Low
   180 @SYMTestType			UT
   181 @SYMTestPurpose			To ensure that RSgDriver reports the correct local resource count when images are opened and closed.
   182 @SYMTestActions			Open an RSgDriver and create an image, then close it checking the resource count of the
   183 						driver is valid at each stage (0,1,0). Attempt to close the driver multiple times and then perform the
   184 						same tests again.
   185 @SYMTestExpectedResults	Resource counts should be as expected.
   186  */	
   187 void CTGraphicsResourceInternal::TestInitializeAndShutdownManyTimesL()
   188 	{
   189 	TSgResIntTestInfo testInfo = { ESgResIntInitializeAndShutdownManyTimes };
   190 	TInt result = CreateSecondProcessAndDoTestL(KInternalTestsSecondProcess, testInfo);
   191 	TEST(result & EFirstTestPassed);
   192 	TEST(result & ESecondTestPassed);
   193 	TEST(result & EThirdTestPassed);
   194 	TEST(result & EFourthTestPassed);
   195 	}
   196 
   197 /*
   198 @SYMTestCaseID			GRAPHICS-RESOURCE-0111
   199 @SYMTestCaseDesc		Test MSgDriver_Profiling extension.
   200 @SYMPREQ				PREQ2637
   201 @SYMFssID				RSgImage
   202 						RSgDriver
   203 						MSgDriver_Profiling
   204 @SYMTestPriority		Medium
   205 @SYMTestType			UT
   206 @SYMTestPurpose			To test that the extension MSgDriver_Profiling correctly reports
   207 						the correct global and local resource count and memory usage when
   208 						resources are created in separate processes.
   209 @SYMTestActions			Get the MSgDriver_Profiling extension, query memory/resource usage.
   210 						Create an image and check  the memory usage and count.
   211 						Launch a separate process that checks the same memory usage/count.
   212 						Create an image in this separate process and check the global resource 
   213 						count and memory. Close the image nad check the memory usage and resource
   214 						count. Terminate the second process. Check the local and global count 
   215 						in the first process. Close the image in this process and check the global 
   216 						and local resource count.
   217 @SYMTestExpectedResults When creating the first image, the local resource count should equal one,
   218 						the global count should increment. The local memory usage should increase
   219 						by at least the size of the image in pixels * byte-depth. The global memory
   220 						usage should increase by the same amount.
   221 						Second process should report the same global resouce count and memory as
   222 						the first process. 
   223 						Second process image creation to cause same usage/count increase as did 
   224 						first image.
   225 						Closing the image in the second process should set count and memory usage 
   226 						back to initial values, and local count/usage to zero. 
   227 						Closing the image in the first process should set the count and memory usage
   228 						back to their pre-test values, and local count/usage to zero.
   229  */	
   230 void CTGraphicsResourceInternal::TestResourceProfilingL()
   231 	{
   232 	__UHEAP_MARK;
   233 	
   234 	RSgDriver sgDriver;
   235 	TInt err = sgDriver.Open();
   236 	TESTE(err == KErrNone, err);
   237 
   238 	if (KErrNone == err)
   239 		{
   240 		MSgDriver_Profiling* profiling = NULL;
   241 		err = sgDriver.GetInterface(profiling);
   242 		if (!profiling || err != KErrNone)
   243 			{
   244 			ERR_PRINTF2(_L("Failed to get MSgDriver_Profiling extension [%d]"), err);
   245 			SetTestStepResult(EFail);
   246 			return;
   247 			}
   248 		
   249 		const TInt originalGlobalResourceCount = profiling->GlobalResourceCount();
   250 		const TInt originalGlobalGraphicsMemory = profiling->GlobalGraphicsMemoryUsed();
   251 
   252 		TEST(profiling->LocalGraphicsMemoryUsed() == 0);
   253 		
   254 		RSgImage image;
   255 		const TSize KImageSize(8, 8);
   256 		err = image.Create(TSgImageInfo(KImageSize, EUidPixelFormatARGB_8888, ESgUsageBitOpenVgImage));
   257 		TESTE(err == KErrNone, err);
   258 
   259 		// Check that having created an image, the global resource count and memory usage has
   260 		// increased.
   261 		TInt localGraphicsMemory = profiling->LocalGraphicsMemoryUsed();
   262 		TEST(localGraphicsMemory >= (KImageSize.iWidth * KImageSize.iHeight * 4));
   263 		TEST(profiling->GlobalResourceCount() == (originalGlobalResourceCount + 1));
   264 		TEST(profiling->GlobalGraphicsMemoryUsed() == (localGraphicsMemory + originalGlobalResourceCount));
   265 		
   266 		TSgResIntTestInfo testInfo = { ESgResIntResourceProfiling };
   267 		testInfo.iGlobalGraphicsMemory = profiling->GlobalGraphicsMemoryUsed();
   268 		testInfo.iGlobalResourceCount = profiling->GlobalResourceCount();
   269 		TInt result = CreateSecondProcessAndDoTestL(KInternalTestsSecondProcess, testInfo);
   270 		TEST(result & EFirstTestPassed);
   271 		TEST(result & ESecondTestPassed);
   272 		TEST(result & EThirdTestPassed);
   273 		TEST(result & EFourthTestPassed);
   274 		TEST(result & EFifthTestPassed);
   275 		TEST(result & ESixthTestPassed);
   276 		TEST(result & ESeventhTestPassed);
   277 		TEST(result & EEighthTestPassed);
   278 		TEST(result & ENinthTestPassed);
   279 		TEST(result & ETenthTestPassed);
   280 		TEST(result & EEleventhTestPassed);
   281 		
   282 		// Check that the global and local counts are unchanged.
   283 		TEST(profiling->LocalGraphicsMemoryUsed() == localGraphicsMemory);
   284 		TEST(profiling->GlobalResourceCount() == (originalGlobalResourceCount + 1));
   285 		TEST(profiling->GlobalGraphicsMemoryUsed() == (localGraphicsMemory + originalGlobalResourceCount));
   286 				
   287 		// Check that closing the image shows the image memory is back to zero.
   288 		image.Close();		
   289 		TEST(profiling->LocalGraphicsMemoryUsed() == 0);
   290 		TEST(profiling->GlobalGraphicsMemoryUsed() == originalGlobalGraphicsMemory);
   291 		TEST(profiling->GlobalResourceCount() == originalGlobalResourceCount);
   292 		
   293 		// Cleanup
   294 		sgDriver.Close();
   295 		profiling = NULL;
   296 		}
   297 	__UHEAP_MARKEND;
   298 	}
   299 
   300  /*
   301  Used for Usage Bit test (GRAPHICS-RESOURCE-0204)
   302  */
   303 struct TUsageBitTest
   304     {
   305     TUint32     iUsageBit;              // usage bit to create an image
   306     TInt        iPixelFormat;           // pixel format to create an inmage
   307     
   308     TInt        iExpectedReturnCode;    // expected return code for RSgImage::Create with the usage bit iRequestedUsageBit
   309     TUint32     iExpectedUsageBit;      // expected usage bit of TSgImageInfo that is obtained by calling RSgImage::GetInfo
   310     };
   311 
   312 /*
   313  set of usage bit test cases
   314  */
   315 const static TUsageBitTest KUsageBitTestCases[] = {
   316         // with ESgPixelFormatARGB_8888_PRE
   317         { ESgUsageBitOpenVgImage,       ESgPixelFormatARGB_8888_PRE, KErrNone,           ESgUsageBitOpenVgImage}, // 0
   318         { ESgUsageBitOpenGlesTexture2D, ESgPixelFormatARGB_8888_PRE, KErrNone,           ESgUsageBitOpenGlesTexture2D}, // 1
   319         { ESgUsageBitOpenGles2Texture2D,ESgPixelFormatARGB_8888_PRE, KErrNotSupported,   ESgUsageBitOpenGles2Texture2D}, // 2
   320         { ESgUsageBitOpenVgSurface,     ESgPixelFormatARGB_8888_PRE, KErrNone,           ESgUsageBitOpenVgSurface | ESgUsageBitOpenGlesSurface}, // 3
   321         { ESgUsageBitOpenGlesSurface,   ESgPixelFormatARGB_8888_PRE, KErrNone,           ESgUsageBitOpenVgSurface | ESgUsageBitOpenGlesSurface }, // 4
   322         { ESgUsageBitOpenGles2Surface,  ESgPixelFormatARGB_8888_PRE, KErrNotSupported,   0 }, // 5
   323         { ESgUsageBitOpenGlSurface,     ESgPixelFormatARGB_8888_PRE, KErrNotSupported,   0 }, // 6
   324         
   325         { ESgUsageBitOpenVgImage | ESgUsageBitOpenGlesTexture2D,    ESgPixelFormatARGB_8888_PRE, KErrNone, ESgUsageBitOpenVgImage | ESgUsageBitOpenGlesTexture2D},// 7
   326         { ESgUsageBitOpenVgImage | ESgUsageBitOpenVgSurface,        ESgPixelFormatARGB_8888_PRE, KErrNone, ESgUsageBitOpenVgImage | ESgUsageBitOpenVgSurface | ESgUsageBitOpenGlesSurface}, // 8
   327         { ESgUsageBitOpenVgSurface | ESgUsageBitOpenGlesSurface,    ESgPixelFormatARGB_8888_PRE, KErrNone, ESgUsageBitOpenVgSurface | ESgUsageBitOpenGlesSurface}, // 9
   328         { ESgUsageBitOpenVgSurface | ESgUsageBitOpenGles2Surface,   ESgPixelFormatARGB_8888_PRE, KErrNotSupported, 0}, // 10
   329         { ESgUsageBitOpenVgSurface | ESgUsageBitOpenGlSurface,      ESgPixelFormatARGB_8888_PRE, KErrNotSupported, 0}, // 11
   330         { ESgUsageBitOpenVgSurface | ESgUsageBitOpenGles2Texture2D, ESgPixelFormatARGB_8888_PRE, KErrNotSupported, 0},//  12
   331         
   332         { ESgUsageBitOpenVgImage | ESgUsageBitOpenGlesTexture2D |ESgUsageBitOpenVgSurface |ESgUsageBitOpenGlesSurface, ESgPixelFormatARGB_8888_PRE, KErrNone, 
   333           ESgUsageBitOpenVgImage | ESgUsageBitOpenGlesTexture2D |ESgUsageBitOpenVgSurface |ESgUsageBitOpenGlesSurface}, //  13
   334         
   335 
   336         //with ESgPixelFormatA_8
   337         { ESgUsageBitOpenVgImage,       ESgPixelFormatA_8, KErrNone,           ESgUsageBitOpenVgImage}, // 14
   338         { ESgUsageBitOpenGlesTexture2D, ESgPixelFormatA_8, KErrNone,           ESgUsageBitOpenGlesTexture2D}, // 15
   339         { ESgUsageBitOpenGles2Texture2D,ESgPixelFormatA_8, KErrNotSupported,   ESgUsageBitOpenGles2Texture2D}, // 16
   340         { ESgUsageBitOpenVgSurface,     ESgPixelFormatA_8, KErrNotSupported,   0 }, // 17
   341         { ESgUsageBitOpenGlesSurface,   ESgPixelFormatA_8, KErrNotSupported,   0 }, // 18
   342         { ESgUsageBitOpenGles2Surface,  ESgPixelFormatA_8, KErrNotSupported,   0 }, // 19
   343         { ESgUsageBitOpenGlSurface,     ESgPixelFormatA_8, KErrNotSupported,   0 }, // 20
   344         
   345         // with EUidPixelFormatARGB_8888
   346         { ESgUsageBitOpenVgImage,       ESgPixelFormatARGB_8888, KErrNone,           ESgUsageBitOpenVgImage}, // 21
   347         { ESgUsageBitOpenGlesTexture2D, ESgPixelFormatARGB_8888, KErrNone,           ESgUsageBitOpenGlesTexture2D}, // 22
   348         { ESgUsageBitOpenGles2Texture2D,ESgPixelFormatARGB_8888, KErrNotSupported,   ESgUsageBitOpenGles2Texture2D}, // 23
   349         { ESgUsageBitOpenVgSurface,     ESgPixelFormatARGB_8888, KErrNone,           ESgUsageBitOpenVgSurface | ESgUsageBitOpenGlesSurface}, // 3
   350         { ESgUsageBitOpenGlesSurface,   ESgPixelFormatARGB_8888, KErrNone,           ESgUsageBitOpenVgSurface | ESgUsageBitOpenGlesSurface }, // 4
   351         { ESgUsageBitOpenGles2Surface,  ESgPixelFormatARGB_8888, KErrNotSupported,   0 }, // 24
   352         { ESgUsageBitOpenGlSurface,     ESgPixelFormatARGB_8888, KErrNotSupported,   0 }, // 25
   353         
   354         // with ESgPixelFormatXRGB_8888
   355         { ESgUsageBitOpenVgImage,       ESgPixelFormatXRGB_8888, KErrNone,           ESgUsageBitOpenVgImage}, // 26
   356         { ESgUsageBitOpenGlesTexture2D, ESgPixelFormatXRGB_8888, KErrNone,           ESgUsageBitOpenGlesTexture2D}, // 27
   357         { ESgUsageBitOpenGles2Texture2D,ESgPixelFormatXRGB_8888, KErrNotSupported,   ESgUsageBitOpenGles2Texture2D}, // 28
   358         { ESgUsageBitOpenVgSurface,     ESgPixelFormatXRGB_8888, KErrNone,           ESgUsageBitOpenVgSurface | ESgUsageBitOpenGlesSurface}, // 29
   359         { ESgUsageBitOpenGlesSurface,   ESgPixelFormatXRGB_8888, KErrNone,           ESgUsageBitOpenVgSurface | ESgUsageBitOpenGlesSurface }, // 30
   360         { ESgUsageBitOpenGles2Surface,  ESgPixelFormatXRGB_8888, KErrNotSupported,   0 }, // 31
   361         { ESgUsageBitOpenGlSurface,     ESgPixelFormatXRGB_8888, KErrNotSupported,   0 }, // 32
   362         
   363         // invalid usage bit
   364         { 0x0000, ESgPixelFormatRGB_565, KErrArgument, 0 }, // 33
   365         { 0x1000, ESgPixelFormatRGB_565, KErrNotSupported, 0 }, // 34
   366     };
   367 
   368 const TInt KUsageBitTestCount = sizeof(KUsageBitTestCases)/sizeof(KUsageBitTestCases[0]);
   369 
   370 /*
   371 @SYMTestCaseID          GRAPHICS-RESOURCE-0204
   372 @SYMTestCaseDesc        Test usage bit
   373 @SYMPREQ                PREQ2637
   374 @SYMFssID               RSgImage
   375                         RSgDrawable
   376                         RSgDriver
   377 @SYMTestPriority        High
   378 @SYMTestType            UT
   379 @SYMTestPurpose         To ensure that an image can be created using various usage bit, and the usage bit of created image
   380                         is correct.
   381 @SYMTestActions         Create an image with selection of usage bit. Check if the return code of SgImage::Create
   382                         is correct. If creation succeeds, open the image and check if the usage bit is the same 
   383                         to the one expected. 
   384                         NOTE: The usage bit may not be the same as the one that is used to create an image - it 
   385                         depends on the implementation.
   386 @SYMTestExpectedResults The usage bit should match the expected usage bit.
   387  */ 
   388 void CTGraphicsResourceInternal::TestUsageBitsL()
   389     {
   390  
   391     RSgDriver driver;
   392     User::LeaveIfError(driver.Open());
   393     CleanupClosePushL(driver);
   394     
   395     for(TInt i=0; i < KUsageBitTestCount; ++i)
   396         {
   397         TSgImageInfo info(TSize(8, 8), KUsageBitTestCases[i].iPixelFormat,  KUsageBitTestCases[i].iUsageBit);
   398             
   399         RSgImage image;
   400         TInt err = image.Create(info);
   401         CleanupClosePushL(image);
   402         
   403         if(err != KUsageBitTestCases[i].iExpectedReturnCode)
   404             {
   405             ERR_PRINTF3(_L("Test case index: %d, Test failed with error: %d"), i, err);
   406             SetTestStepResult(EFail);
   407             }
   408         
   409         if(err == KErrNone)
   410             {    
   411             TSgImageInfo info1;
   412             User::LeaveIfError(image.GetInfo(info1));   
   413             if(info1.iUsage != KUsageBitTestCases[i].iExpectedUsageBit)
   414                 {
   415                 ERR_PRINTF3(_L("Test case index: %d, info1 usage bit 0x%04X"), i, info1.iUsage);
   416                 SetTestStepResult(EFail);
   417                 }
   418             }
   419             
   420         CleanupStack::PopAndDestroy(&image);
   421         }
   422     
   423     CleanupStack::PopAndDestroy(&driver);
   424     }
   425