Example #1
0
void tst_QVolatileImage::sharing()
{
    QVolatileImage img1(100, 100, QImage::Format_ARGB32);
    QVolatileImage img2 = img1;
    img1.beginDataAccess();
    img2.beginDataAccess();
    QVERIFY(img1.constBits() == img2.constBits());
    img2.endDataAccess();
    img1.endDataAccess();
    img1.imageRef(); // non-const call, should detach
    img1.beginDataAccess();
    img2.beginDataAccess();
    QVERIFY(img1.constBits() != img2.constBits());
    img2.endDataAccess();
    img1.endDataAccess();

    // toImage() should return a copy of the internal QImage.
    // imageRef() is a reference to the internal QImage.
    QVERIFY(img1.imageRef().constBits() != img1.toImage().constBits());

#ifdef Q_OS_SYMBIAN
    CFbsBitmap *bmp = new CFbsBitmap;
    QVERIFY(bmp->Create(TSize(100, 50), EColor16MAP) == KErrNone);
    QVolatileImage bmpimg(bmp);
    QVolatileImage bmpimg2;
    bmpimg2 = bmpimg;
    QCOMPARE(bmpimg.constBits(), (const uchar *) bmp->DataAddress());
    QCOMPARE(bmpimg2.constBits(), (const uchar *) bmp->DataAddress());
    // Now force a detach, which should copy the pixel data under-the-hood.
    bmpimg.imageRef();
    QVERIFY(bmpimg.constBits() != (const uchar *) bmp->DataAddress());
    QCOMPARE(bmpimg2.constBits(), (const uchar *) bmp->DataAddress());
    delete bmp;
#endif
}
void AConvolute64KBlurGauss( CFbsBitmap& aTarget,
                             const CFbsBitmap& aSource,
                             const TInt aBlendFactor )
    {
    TInt width  = aTarget.SizeInPixels().iWidth;
    TInt height = aTarget.SizeInPixels().iHeight;

    // CFbsBitmap::ScanLineLength returns bytes 
    TInt targetScanW  = CFbsBitmap::ScanLineLength(
                                aTarget.SizeInPixels().iWidth,
                                aTarget.DisplayMode());
    TInt sourceScanW  = CFbsBitmap::ScanLineLength(
                                aSource.SizeInPixels().iWidth,
                                aSource.DisplayMode());

    TInt combinedScanW = (targetScanW << 16) + sourceScanW;

    // Prepare the data addresses
    aTarget.LockHeap( ETrue ); // Lock the global bitmap heap
    TUint* targetAddr = reinterpret_cast<TUint*>( aTarget.DataAddress() );
    TUint* sourceAddr = reinterpret_cast<TUint*>( aSource.DataAddress() );

    ADoConvolute64KBlurGauss(targetAddr, sourceAddr, combinedScanW, width, height, aBlendFactor);

    aTarget.UnlockHeap( ETrue ); // Unlock the global bitmap heap
    }
    //------------------------------------------------------------------------
    static void ProcessRgbToRgb( const CFbsBitmap& aTarget,
                                 const CFbsBitmap& aSource,
                                 const TInt aTreshold,
                                 const TInt aBlendFactor )
        {
        // ScanLineLength returns bytes, but width must match the Type
        TInt width  = CFbsBitmap::ScanLineLength( aSource.SizeInPixels().iWidth,
                                                  aSource.DisplayMode() ) / sizeof(Type);
        TInt height = aSource.SizeInPixels().iHeight;

        TInt pixelCount = width * height;
        TInt shade;
        TInt r,g,b;

        aTarget.LockHeap( ETrue ); // Lock the global bitmap heap
        Type* dataT = reinterpret_cast<Type*>( aTarget.DataAddress() );
        Type* dataS = reinterpret_cast<Type*>( aSource.DataAddress() );

        for( TInt index = 0; index < pixelCount; ++index )
            {
            r = AknsRlRgb<Type,X,R,G,B>::R8(*dataS);
            g = AknsRlRgb<Type,X,R,G,B>::G8(*dataS);
            b = AknsRlRgb<Type,X,R,G,B>::B8(*dataS);

            // Pixel intensity = grayscale value
            shade = AknsRlUtil::Grayscale( TUint8(r), TUint8(g), TUint8(b) );

            // Convert to B&W
            if( shade < aTreshold )
                shade = 0;
            else
                shade = 255;

            // Exposure blending
            // Note: It is assumed that arithmetic shifting is supported
            // -> negative values are shifted correctly
            r = (shade * aBlendFactor + (255 - aBlendFactor) * r) >> 8;
            g = (shade * aBlendFactor + (255 - aBlendFactor) * g) >> 8;
            b = (shade * aBlendFactor + (255 - aBlendFactor) * b) >> 8;

            if( r < 0 ) r = 0; else if( r > 255 ) r = 255;
            if( g < 0 ) g = 0; else if( g > 255 ) g = 255;
            if( b < 0 ) b = 0; else if( b > 255 ) b = 255;

            AknsRlRgb<Type,X,R,G,B>::SetRgb8( dataT, TUint8(r), TUint8(g), TUint8(b) );

            dataT++;
            dataS++;
            }

        aTarget.UnlockHeap( ETrue ); // Unlock the global bitmap heap
        }
    //------------------------------------------------------------------------
    static void ProcessRgbToGray( const CFbsBitmap& aTarget,
                                  const CFbsBitmap& aSource,
                                  const TInt aTreshold )
        {
        TInt width  = aSource.SizeInPixels().iWidth;
        TInt height = aSource.SizeInPixels().iHeight;

        // ScanLineLength returns bytes, but width must match the Type
        TInt scanT = CFbsBitmap::ScanLineLength(width, aTarget.DisplayMode());
        TInt scanS = CFbsBitmap::ScanLineLength(width, aSource.DisplayMode()) / sizeof(Type);

        TInt shade;

        TInt pitchT = scanT - width;
        TInt pitchS = scanS - width;

        aTarget.LockHeap( ETrue ); // Lock the global bitmap heap
        TUint8* dataT = reinterpret_cast<TUint8*>( aTarget.DataAddress() );
        Type* dataS = reinterpret_cast<Type*>( aSource.DataAddress() );

        TInt x, y;
        for( y=0; y < height; y++ )
            {
            for( x=0; x < width; x++ )
                {
                // Pixel intensity = grayscale value
                shade = AknsRlUtil::Grayscale( AknsRlRgb<Type,X,R,G,B>::R8(*dataS),
                                               AknsRlRgb<Type,X,R,G,B>::G8(*dataS),
                                               AknsRlRgb<Type,X,R,G,B>::B8(*dataS) );

                // Convert to B&W
                if( shade < aTreshold )
                    *dataT = 0;
                else
                    *dataT = 255;

                dataT++;
                dataS++;
                }

            dataT = dataT + pitchT;
            dataS = dataS + pitchS;
            }

        aTarget.UnlockHeap( ETrue ); // Unlock the global bitmap heap
        }
void CEglTest_EGL_Image_Multi_Thread_Parallel::doThreadFunctionL(TInt aIdx)
	{
	INFO_PRINTF2(_L("CEglTest_EGL_Image_Multi_Thread_Parallel::doThreadFunctionL, Thread %d"),aIdx);
	GetDisplayL();
	CTestEglSession* eglSess = CTestEglSession::NewLC(Logger(), iDisplay, aIdx);
	eglSess->InitializeL();	
	eglSess->OpenSgDriverL();
	
	// create a reference bitmap (we give index 7, as there's only 1 image in this test case)
	TDisplayMode bitmapMode = EglTestConversion::PixelFormatToDisplayMode(KDefaultSourceFormat);
	CFbsBitmap* bitmap = eglSess->CreateReferenceBitmapL(bitmapMode, KPixmapSize, 7);
	CleanupStack::PushL(bitmap);

	// Create an RSgImage
	INFO_PRINTF2(_L("Thread %d, Creating a RSgImage having the reference bitmap's content"),aIdx);
	TSgImageInfoOpenVgImage imageInfo = TSgImageInfoOpenVgImage(KDefaultSourceFormat, KPixmapSize);
    RSgImage rSgImageLocal;
	CleanupClosePushL(rSgImageLocal);
	ASSERT_EQUALS(rSgImageLocal.Create(imageInfo,bitmap->DataAddress(),bitmap->DataStride()), KErrNone);

	INFO_PRINTF2(_L("Thread %d, Creating an EGLImage from the shared RSgImage"),aIdx);
	EGLImageKHR eglImageLocal = eglSess->eglCreateImageKhrL(iDisplay, EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR, &rSgImageLocal, KEglImageAttribsPreservedTrue);
	ASSERT_EGL_TRUE(eglImageLocal != EGL_NO_IMAGE_KHR);
	CleanupStack::PopAndDestroy(&rSgImageLocal); 	//transferring ownership of the buffer to the EGLImage
	CleanupStack::PopAndDestroy(bitmap);

	INFO_PRINTF2(_L("Thread %d, Creating a Surface and a Context bound to OpenVG"),aIdx);
	TUidPixelFormat pixelFormat = EglTestConversion::VgFormatToSgPixelFormat(KDefaultSurfaceFormat);
	TSgImageInfoOpenVgTarget imageInfo2 = TSgImageInfoOpenVgTarget(pixelFormat, KPixmapSize);
	// Create a pixmap surface matching the native image pixel format
	eglSess->CreatePixmapSurfaceAndMakeCurrentAndMatchL(imageInfo2,CTestEglSession::EResourceCloseSgImageEarly);
	
	INFO_PRINTF2(_L("Thread %d, Creating one VGImage from the EGLImage"),aIdx);
	VGImage vgImageLocal = eglSess->vgCreateImageTargetKHR((VGeglImageKHR)eglImageLocal);	
	ASSERT_VG_TRUE(vgImageLocal != VG_INVALID_HANDLE);
	ASSERT_EGL_TRUE(eglSess->DestroyEGLImage(iDisplay, eglImageLocal));
		
	// Copy the source VGImage to the surface
	vgSetPixels(0, 0, vgImageLocal, 0, 0, KPixmapSize.iWidth, KPixmapSize.iHeight);
	ASSERT_TRUE(vgGetError()==VG_NO_ERROR);
	eglWaitClient();

	// destroy VGImage
	vgDestroyImage(vgImageLocal);
	ASSERT_TRUE(vgGetError()==VG_NO_ERROR);

	// we can now compare the VgImage to the one we would expect for this particular thread
	CFbsBitmap* refBitmap = eglSess->CreateReferenceBitmapL(bitmapMode, KPixmapSize, 7);
	CleanupStack::PushL(refBitmap);
	eglSess->CheckVgDrawingL(KDefaultSurfaceFormat, refBitmap);
	CleanupStack::PopAndDestroy(refBitmap);
	INFO_PRINTF2(_L("Drawing successful, Thread %d"),aIdx);

	// cleanup
	eglSess->CloseSgDriver();
  	CleanupStack::PopAndDestroy(eglSess);	
	}
Example #6
0
void tst_QVolatileImage::ensureFormat()
{
    QImage source(12, 23, QImage::Format_ARGB32_Premultiplied);
    QVolatileImage img(source);
    QVERIFY(!img.isNull());
    QVERIFY(img.imageRef() == source);
    QVERIFY(img.toImage() == source);

    QVERIFY(img.ensureFormat(QImage::Format_ARGB32_Premultiplied)); // no-op
    QVERIFY(img.imageRef() == source);
    QVERIFY(img.toImage() == source);
    QVERIFY(img.format() == QImage::Format_ARGB32_Premultiplied);

    QVERIFY(img.ensureFormat(QImage::Format_RGB32)); // new data under-the-hood
    QVERIFY(img.imageRef() != source);
    QVERIFY(img.toImage() != source);
    QVERIFY(img.format() == QImage::Format_RGB32);

#ifdef Q_OS_SYMBIAN
    CFbsBitmap *bmp = new CFbsBitmap;
    QVERIFY(bmp->Create(TSize(100, 50), EColor16MAP) == KErrNone);
    QVolatileImage bmpimg(bmp);
    QVERIFY(bmpimg.ensureFormat(QImage::Format_ARGB32_Premultiplied)); // no-op
    QCOMPARE(bmpimg.constBits(), (const uchar *) bmp->DataAddress());

    // A different format should cause data copying.
    QVERIFY(bmpimg.ensureFormat(QImage::Format_RGB32));
    QVERIFY(bmpimg.constBits() != (const uchar *) bmp->DataAddress());
    const uchar *prevBits = bmpimg.constBits();

    QVERIFY(bmpimg.ensureFormat(QImage::Format_RGB16));
    QVERIFY(bmpimg.constBits() != (const uchar *) bmp->DataAddress());
    QVERIFY(bmpimg.constBits() != prevBits);
    prevBits = bmpimg.constBits();

    QVERIFY(bmpimg.ensureFormat(QImage::Format_MonoLSB));
    QVERIFY(bmpimg.constBits() != (const uchar *) bmp->DataAddress());
    QVERIFY(bmpimg.constBits() != prevBits);

    delete bmp;
#endif
}
/**
@SYMTestCaseID GRAPHICS-EGL-0157

@SYMTestPriority 1

@SYMPREQ 39

@SYMREQ See SGL.GT0386.401 document

@SYMTestCaseDesc
Check if EGL Implementation allows two threads to work in parallel.
Each thread is allowed to create a VGImage from the same EGLImage

@SYMTestActions
Main Thread: creates an RSgImage with the same content as the reference bitmap and creates an EGLImage from it; starts thread1 and thread2.
Thread1: Creates an egl context and a pixmap surface linked to it. Creates an VGImage from the EGLImage previous mentioned
Thread2: Creates an egl context and a pixmap surface linked to it. Creates an VGImage from the EGLImage previous mentioned
--------
Thread 1: Changes the content of the RSgImage by using the VGImage that has a reference to it.
--------
Thread1: Passes the VGImage into vgDestroyImage()
Thread2: Copies the VGImage to the pixmap surface and checks the contents
Thread2: Passes the VGImage into vgDestroyImage()
Main Thread: Closes the EGLImage
Main Thread: Closes the RSgImage

@SYMTestExpectedResults
No error is generated within both threads. The changes apported by the first thread affects the second thread. The content the pixmap surface will matches the one of the reference bitmap changed by the first thread.
No memory or handle leaks
*/
TVerdict CEglTest_EGL_Image_Multi_Thread_Sibling_VGImage::doTestStepL()
	{
	SetTestStepID(_L("GRAPHICS-EGL-0157"));
	INFO_PRINTF1(_L("Enter: CEglTest_EGL_Image_Multi_Thread_Sibling_VGImage::doTestStepL"));

	TBool ret = CheckForExtensionL(KEGL_RSgimage | KEGL_KHR_image_base | KEGL_KHR_image_pixmap | KVG_KHR_EGL_image);
	if(!ret)
		{
		// The extension is not supported
		RecordTestResultL();
		CloseTMSGraphicsStep();
		return TestStepResult();
		}

	// Create display object
	ASSERT_TRUE(iDisplay == EGL_NO_DISPLAY);
    GetDisplayL();
    CTestEglSession* eglSess = CTestEglSession::NewLC(Logger(), iDisplay, 0);
	eglSess->InitializeL();

	// Make sure the driver is ready
	eglSess->OpenSgDriverL();

	// create a reference bitmap (we give index 3, as there's only 1 image in this test case)
	TDisplayMode bitmapMode = EglTestConversion::PixelFormatToDisplayMode(KDefaultSourceFormat);
	CFbsBitmap* bitmap = eglSess->CreateReferenceBitmapL(bitmapMode, KPixmapSize, 3);
	CleanupStack::PushL(bitmap);
	
	// Create an RSgImage (member variable as it is 'shared' in the thread funtion...) 
	INFO_PRINTF1(_L("Parent Thread, Creating the shared RSgImage"));
	TSgImageInfoOpenVgImage imageInfo = TSgImageInfoOpenVgImage(KDefaultSourceFormat, KPixmapSize);
	ASSERT_EQUALS(iSgImageShared.Create(imageInfo,bitmap->DataAddress(),bitmap->DataStride()), KErrNone);
	CleanupStack::PopAndDestroy(bitmap);
	
	// Create an EGLImage from the RSgImage (member variable as it is 'shared' in the thread funtion...) 
	INFO_PRINTF1(_L("Parent Thread, Creating the shared EGLImage"));
	iEGLImageShared = eglSess->eglCreateImageKhrL(iDisplay,EGL_NO_CONTEXT,EGL_NATIVE_PIXMAP_KHR,&iSgImageShared,KEglImageAttribsPreservedTrue);
	ASSERT_EGL_TRUE(iEGLImageShared != EGL_NO_IMAGE_KHR);
	iSgImageShared.Close();

	// launch 2 threads
	Test_MultiThreadL(2, ETrue);
	
	// cleanup
	ASSERT_EGL_TRUE(eglSess->DestroyEGLImage(iDisplay, iEGLImageShared));
	CleanupStack::PopAndDestroy(eglSess);
	TerminateDisplayL();	
	INFO_PRINTF1(_L("Exit: CEglTest_EGL_Image_Multi_Thread_Sibling_VGImage::doTestStepL"));	
	RecordTestResultL();
	CloseTMSGraphicsStep();
	return TestStepResult();
	}
    //------------------------------------------------------------------------
    static void ProcessGrayToRgb( const CFbsBitmap& aTarget,
                                  const CFbsBitmap& aSource,
                                  const TInt aTreshold )
        {
        TInt width  = aSource.SizeInPixels().iWidth;
        TInt height = aSource.SizeInPixels().iHeight;

        // ScanLineLength returns bytes, but width must match the Type
        TInt scanT = CFbsBitmap::ScanLineLength(width, aTarget.DisplayMode()) / sizeof(Type);
        TInt scanS = CFbsBitmap::ScanLineLength(width, aSource.DisplayMode());

        TInt pitchT = scanT - width;
        TInt pitchS = scanS - width;

        aTarget.LockHeap( ETrue ); // Lock the global bitmap heap
        Type* dataT = reinterpret_cast<Type*>( aTarget.DataAddress() );
        TUint8* dataS = reinterpret_cast<TUint8*>( aSource.DataAddress() );

        TInt x, y;
        for( y=0; y < height; y++ )
            {
            for( x=0; x < width; x++ )
                {
                // Convert to B&W
                if( *dataS < aTreshold )
                    AknsRlRgb<Type,X,R,G,B>::SetRgb8( dataT, TUint8(0), TUint8(0), TUint8(0) );
                else
                    AknsRlRgb<Type,X,R,G,B>::SetRgb8( dataT, TUint8(255), TUint8(255), TUint8(255) );

                dataT++;
                dataS++;
                }

            dataT = dataT + pitchT;
            dataS = dataS + pitchS;
            }

        aTarget.UnlockHeap( ETrue ); // Unlock the global bitmap heap
        }
/**
@SYMTestCaseID
GRAPHICS-UI-BENCH-0157

@SYMPREQ PREQ39

@SYMREQ REQ9236 
@SYMREQ REQ9237

@SYMTestCaseDesc
Measure the performance of BitBlt() for the current screen mode and for various bitmap pixel formats,
with a bitmap that is accessed by the CPU via DataAddresss(), and is therefore never cached by DirectGDI.

@SYMTestActions
Create a copy of a test bitmap.
Call DataAddress() on the bitmap.
Draw an entire bitmap using BitBlt(), with no overlapping or clipping. 
Measure the time taken.

@SYMTestExpectedResults
The performance to be logged as a pixel rate, per bitmap.
*/
void CTBitBltPerfDirectGdi::BitBltCpuAccessL()
	{
	INFO_PRINTF1(_L("CTBitBltPerfDirectGdi::BitBltCpuAccess"));
	
	_LIT(KTestName, "DirectGdiBitBltCpuAccess");

	for (TInt source = 0; source < iBitmapImage.Count(); ++source)
		{
		CFbsBitmap* bitmapBitBltImage = CopyIntoNewBitmapL(iBitmapImage[source], iBitmapImage[source]->DisplayMode());
		TESTL(bitmapBitBltImage != NULL);
		CleanupStack::PushL(bitmapBitBltImage);
		bitmapBitBltImage->DataAddress();	// CPU Access so that it is not cached by DirectGDI.
		BitBltBitmapTestL(EBitBlt, bitmapBitBltImage, NULL, KCropTo, KTestName, iContext);
		CleanupStack::PopAndDestroy(1, bitmapBitBltImage);		
		}
	}
TInt CScreenCaptureUtil::CopySurfaceToBitmapL(CFbsBitmap& aCopyToBitmap)
	{
	RSurfaceManager::TInfoBuf infoBuf;
	RSurfaceManager::TSurfaceInfoV01& info = infoBuf();

	User::LeaveIfError(iSurfaceManager.SurfaceInfo(iLocalSurface, infoBuf));
	
	TInt bytesPerPixel=0;
	TDisplayMode	bitmapMode = ENone;
	
	switch (info.iPixelFormat)
		{
		case EUidPixelFormatXRGB_8888:
			{
			bitmapMode = EColor16MU;
			bytesPerPixel = 4;
			break;
			}
		default:
			{
			return KErrCorrupt;
			}
		}
	
	if ((aCopyToBitmap.SizeInPixels() != info.iSize) || (aCopyToBitmap.DisplayMode() != bitmapMode))
		{
		return KErrCorrupt;
		}
	
	RChunk chunk;
	CleanupClosePushL(chunk);
	User::LeaveIfError(iSurfaceManager.MapSurface(iLocalSurface, chunk));
	TUint8* surfacePtr = chunk.Base();
	TUint8* bitmapPtr = (TUint8*)aCopyToBitmap.DataAddress();
	TInt copyBytes=info.iSize.iWidth*bytesPerPixel;
	for (TInt y=0; y<info.iSize.iHeight; y++)
		{
		Mem::Copy(bitmapPtr,surfacePtr,copyBytes);
		surfacePtr += info.iStride;
		bitmapPtr += aCopyToBitmap.DataStride();
		}
	CleanupStack::PopAndDestroy(&chunk);
	return KErrNone;
	}
Example #11
0
void tst_QVolatileImage::create()
{
    QVolatileImage nullImg;
    QVERIFY(nullImg.isNull());

    QVolatileImage img(100, 200, QImage::Format_ARGB32);
    QVERIFY(!img.isNull());
    QCOMPARE(img.width(), 100);
    QCOMPARE(img.height(), 200);
    QCOMPARE(img.format(), QImage::Format_ARGB32);
    QCOMPARE(img.byteCount(), img.bytesPerLine() * img.height());
    QCOMPARE(img.hasAlphaChannel(), true);
    QCOMPARE(img.depth(), 32);

    QImage source(12, 23, QImage::Format_ARGB32_Premultiplied);
    img = QVolatileImage(source);
    QVERIFY(!img.isNull());
    QCOMPARE(img.width(), 12);
    QCOMPARE(img.height(), 23);
    QCOMPARE(img.format(), source.format());
    QCOMPARE(img.byteCount(), img.bytesPerLine() * img.height());
    QVERIFY(img.imageRef() == source);
    QVERIFY(img.toImage() == source);
    QCOMPARE(img.hasAlphaChannel(), true);
    QCOMPARE(img.hasAlphaChannel(), img.imageRef().hasAlphaChannel());
    QCOMPARE(img.hasAlphaChannel(), img.toImage().hasAlphaChannel());
    QCOMPARE(img.depth(), 32);

#ifdef Q_OS_SYMBIAN
    CFbsBitmap *bmp = new CFbsBitmap;
    QVERIFY(bmp->Create(TSize(100, 50), EColor16MAP) == KErrNone);
    QVolatileImage bmpimg(bmp);
    QVERIFY(!bmpimg.isNull());
    QCOMPARE(bmpimg.width(), 100);
    QCOMPARE(bmpimg.height(), 50);
    // Verify that we only did handle duplication, not pixel data copying.
    QCOMPARE(bmpimg.constBits(), (const uchar *) bmp->DataAddress());
    delete bmp;
    // Check if content is still valid.
    QImage copyimg = bmpimg.toImage();
    QCOMPARE(copyimg.format(), QImage::Format_ARGB32_Premultiplied);
#endif
}
/**
@SYMTestCaseID GRAPHICS-EGL-0130

@SYMTestPriority 1

@SYMPREQ 39

@SYMREQ See SGL.GT0386.401 document

@SYMTestCaseDesc
When a RSgImage is used as both the source and target of a draw operation, then the operation should not panic.
However the outcome is undefined.

@SYMTestActions
Create and fully construct an RSgImage object
Pass the RSgImage objects into eglCreateImageKHR() with
•	The target parameter set to EGL_NATIVE_PIXMAP_KHR
•	Use the current display and EGL_NO_CONTEXT
•	Use a NULL attr_list
Check that those calls to eglCreateImageKHR() do NOT return EGL_NO_IMAGE_KHR
Use vgCreateEGLImageTargetKHR() to construct a VGImage object from the just created EGLImage.
•	Check for errors
Create Pixmap Surface from the previous RSgImage and make it current in a way that is compatible as a target for the VGImage to be drawn to.
•	Set the iUsage bit to ESgUsageBitOpenVgSurface and ESgUsageBitOpenGlesSurface
Use OpenVG to draw a single patern to the left half of the VGImage created from the EGLImage.
Try to draw this VGImage to the right half of the pixmap surface currently linked to the context.
Call eglWaitClient() to finish the above drawing instructions synchronously.
Check that the pixmap contains expected pixel values.
Pass the VGImage into vgDestroyImage()
Pass the EGLImage into eglDestroyImageKHR()
Close the RSgImage
Destroy the pixmap
Check for memory and handle leaks

@SYMTestExpectedResults
This test is not supposed to panic.
The contents, though, are undefined since we are reading from and writing to the same memory
No memory or handle leaks.
*/
TVerdict CEglTest_EGL_Image_Self_Drawing::doTestStepL()
	{
	SetTestStepID(_L("GRAPHICS-EGL-0130"));
	INFO_PRINTF1(_L("CEglTest_EGL_Image_Self_Drawing::doTestStepL"));

	TBool ret = CheckForExtensionL(KEGL_RSgimage | KEGL_KHR_image_base | KEGL_KHR_image_pixmap | KVG_KHR_EGL_image);
	if(!ret)
		{
		// The extension is not supported
		RecordTestResultL();
		CloseTMSGraphicsStep();
		return TestStepResult();
		}

	// This test is performed for default pixel format
	PrintUsedPixelConfiguration();

	// Create display object
	GetDisplayL();
	CreateEglSessionL();
	iEglSess->InitializeL();
	iEglSess->OpenSgDriverL();

	// Create a reference bitmap which we use to init the SgImage (we use index=8)
	TDisplayMode bitmapMode = EglTestConversion::PixelFormatToDisplayMode(iSourceFormat);
	CFbsBitmap* bitmap = iEglSess->CreateReferenceBitmapL(bitmapMode, KPixmapSize, 8);
	CleanupStack::PushL(bitmap);

	INFO_PRINTF1(_L("Creating one RSgImage"));
	TSgImageInfoTest imageInfo;
	imageInfo.iSizeInPixels = KPixmapSize;
	imageInfo.iPixelFormat = iSourceFormat;
#ifdef SYMBIAN_GRAPHICS_EGL_SGIMAGELITE
	imageInfo.iUsage = ESgUsageBitOpenVgImage | ESgUsageBitOpenVgSurface;
#else
	imageInfo.iUsage = ESgUsageOpenVgImage | ESgUsageOpenVgTarget;
#endif //SYMBIAN_GRAPHICS_EGL_SGIMAGELITE
	RSgImage sgImage;
	CleanupClosePushL(sgImage);
	ASSERT_EQUALS(sgImage.Create(imageInfo, bitmap->DataAddress(),bitmap->DataStride()), KErrNone);

	INFO_PRINTF1(_L("Creating one EGLImage from it"));
	EGLImageKHR imageKHR = iEglSess->eglCreateImageKhrL(iDisplay, EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR, &sgImage, KEglImageAttribsPreservedTrue);
	ASSERT_EGL_TRUE(imageKHR != EGL_NO_IMAGE_KHR);

	INFO_PRINTF1(_L("Calling eglBindAPI(EGL_OPENVG_API)"));
	ASSERT_EGL_TRUE(eglBindAPI(EGL_OPENVG_API));

    EGLint numConfigsWithPre = 0;
    EGLConfig configWithPre;
    const EGLint KAttribImagePre[] = { EGL_MATCH_NATIVE_PIXMAP,  reinterpret_cast<EGLint>(&sgImage),
                                       EGL_RENDERABLE_TYPE,      EGL_OPENVG_BIT,
                                       EGL_SURFACE_TYPE,         EGL_PIXMAP_BIT | EGL_VG_ALPHA_FORMAT_PRE_BIT,
                                       EGL_NONE };
    ASSERT_EGL_TRUE(eglChooseConfig(iDisplay, KAttribImagePre, &configWithPre, 1, &numConfigsWithPre));

	// Create a pixmap surface from the native image
	INFO_PRINTF1(_L("Calling eglCreatePixmapSurface"));
	EGLSurface surface = eglCreatePixmapSurface(iDisplay, configWithPre, &sgImage, KPixmapAttribsVgAlphaFormatPre );
	ASSERT_EGL_TRUE(surface != EGL_NO_SURFACE);

	// Create a context for drawing to/reading from the pixmap surface and make it current
	INFO_PRINTF1(_L("Calling eglCreateContext"));
	EGLContext context = eglCreateContext(iDisplay, configWithPre, EGL_NO_CONTEXT, NULL);
	ASSERT_EGL_TRUE(context != EGL_NO_CONTEXT);

	INFO_PRINTF1(_L("Calling eglMakeCurrent"));
	ASSERT_EGL_TRUE(eglMakeCurrent(iDisplay, surface, surface, context));

	// Create a VGImage from the EGLImage
	INFO_PRINTF1(_L("Creating 1 VGImage from the EGLImage"));
	VGImage vgImage = iEglSess->vgCreateImageTargetKHR((VGeglImageKHR)imageKHR);
	ASSERT_VG_TRUE(vgImage != VG_INVALID_HANDLE);

    //Copy the source VGImage to the surface
	vgSetPixels(0, 0, vgImage, 0, 0, KPixmapSize.iWidth, KPixmapSize.iHeight);
	ASSERT_TRUE(vgGetError()==VG_NO_ERROR);
	eglWaitClient();

	//cleanup
	vgDestroyImage(vgImage);
	ASSERT_TRUE(vgGetError()==VG_NO_ERROR);
	ASSERT_EGL_TRUE(iEglSess->DestroyEGLImage(iDisplay, imageKHR));
	CleanupStack::PopAndDestroy(2, bitmap); // bitmap, sgImage
	//This test doesn't check the drawing because the content of the image are undefined
	//since we are using the same buffer both as target and as source
	//The main purpose of this test is to ensure we don't get a panic
	ASSERT_EGL_TRUE(eglDestroyContext(iDisplay, context));					//Closing eglContext
	context = EGL_NO_CONTEXT;
	ASSERT_EGL_TRUE(eglDestroySurface(iDisplay,surface));					//Destroying Target Surface handle
	CleanAll();

	RecordTestResultL();
	CloseTMSGraphicsStep();
	return TestStepResult();
	}
Example #13
0
void* QVGPixmapData::toNativeType(NativeType type)
{
    if (type == QPixmapData::SgImage) {
#if defined(QT_SYMBIAN_SUPPORTS_SGIMAGE) && !defined(QT_NO_EGL)
        toVGImage();

        if (!isValid() || vgImage == VG_INVALID_HANDLE)
            return 0;

        TInt err = 0;

        RSgDriver driver;
        err = driver.Open();
        if (err != KErrNone)
            return 0;

        TSgImageInfo sgInfo;
        sgInfo.iPixelFormat = EUidPixelFormatARGB_8888_PRE;
        sgInfo.iSizeInPixels.SetSize(w, h);
        sgInfo.iUsage = ESgUsageBitOpenVgImage | ESgUsageBitOpenVgSurface;

        RSgImage *sgImage = q_check_ptr(new RSgImage());
        err = sgImage->Create(sgInfo, NULL, NULL);
        if (err != KErrNone) {
            driver.Close();
            return 0;
        }

        pfnVgCreateEGLImageTargetKHR vgCreateEGLImageTargetKHR = (pfnVgCreateEGLImageTargetKHR) eglGetProcAddress("vgCreateEGLImageTargetKHR");

        if (eglGetError() != EGL_SUCCESS || !(QEgl::hasExtension("EGL_KHR_image") || QEgl::hasExtension("EGL_KHR_image_pixmap")) || !vgCreateEGLImageTargetKHR) {
            driver.Close();
            return 0;
        }

        const EGLint KEglImageAttribs[] = {EGL_IMAGE_PRESERVED_SYMBIAN, EGL_TRUE, EGL_NONE};
        EGLImageKHR eglImage = QEgl::eglCreateImageKHR(QEgl::display(),
                EGL_NO_CONTEXT,
                EGL_NATIVE_PIXMAP_KHR,
                (EGLClientBuffer)sgImage,
                (EGLint*)KEglImageAttribs);
        if (eglGetError() != EGL_SUCCESS) {
            sgImage->Close();
            driver.Close();
            return 0;
        }

        VGImage dstVgImage = vgCreateEGLImageTargetKHR(eglImage);
        if (vgGetError() != VG_NO_ERROR) {
            QEgl::eglDestroyImageKHR(QEgl::display(), eglImage);
            sgImage->Close();
            driver.Close();
            return 0;
        }

        vgCopyImage(dstVgImage, 0, 0,
                vgImage, 0, 0,
                w, h, VG_FALSE);

        if (vgGetError() != VG_NO_ERROR) {
            sgImage->Close();
            sgImage = 0;
        }
        // release stuff
        vgDestroyImage(dstVgImage);
        QEgl::eglDestroyImageKHR(QEgl::display(), eglImage);
        driver.Close();
        return reinterpret_cast<void*>(sgImage);
#endif
    } else if (type == QPixmapData::FbsBitmap) {
        CFbsBitmap *bitmap = q_check_ptr(new CFbsBitmap);

        if (bitmap) {
            if (bitmap->Create(TSize(source.width(), source.height()),
                              EColor16MAP) == KErrNone) {
                const uchar *sptr = source.constBits();
                bitmap->BeginDataAccess();

                uchar *dptr = (uchar*)bitmap->DataAddress();
                Mem::Copy(dptr, sptr, source.byteCount());

                bitmap->EndDataAccess();
            } else {
                delete bitmap;
                bitmap = 0;
            }
        }

        return reinterpret_cast<void*>(bitmap);
    }
    return 0;
}
Example #14
0
void QVGPixmapData::fromNativeType(void* pixmap, NativeType type)
{
    if (type == QPixmapData::SgImage && pixmap) {
#if defined(QT_SYMBIAN_SUPPORTS_SGIMAGE) && !defined(QT_NO_EGL)
        RSgImage *sgImage = reinterpret_cast<RSgImage*>(pixmap);

        destroyImages();
        prevSize = QSize();

        TInt err = 0;

        RSgDriver driver;
        err = driver.Open();
        if (err != KErrNone) {
            cleanup();
            return;
        }

        if (sgImage->IsNull()) {
            cleanup();
            driver.Close();
            return;
        }

        TSgImageInfo sgImageInfo;
        err = sgImage->GetInfo(sgImageInfo);
        if (err != KErrNone) {
            cleanup();
            driver.Close();
            return;
        }

        pfnVgCreateEGLImageTargetKHR vgCreateEGLImageTargetKHR = (pfnVgCreateEGLImageTargetKHR) eglGetProcAddress("vgCreateEGLImageTargetKHR");

        if (eglGetError() != EGL_SUCCESS || !(QEgl::hasExtension("EGL_KHR_image") || QEgl::hasExtension("EGL_KHR_image_pixmap")) || !vgCreateEGLImageTargetKHR) {
            cleanup();
            driver.Close();
            return;
        }

        const EGLint KEglImageAttribs[] = {EGL_IMAGE_PRESERVED_SYMBIAN, EGL_TRUE, EGL_NONE};
        EGLImageKHR eglImage = QEgl::eglCreateImageKHR(QEgl::display(),
                EGL_NO_CONTEXT,
                EGL_NATIVE_PIXMAP_KHR,
                (EGLClientBuffer)sgImage,
                (EGLint*)KEglImageAttribs);

        if (eglGetError() != EGL_SUCCESS) {
            cleanup();
            driver.Close();
            return;
        }

        vgImage = vgCreateEGLImageTargetKHR(eglImage);
        if (vgGetError() != VG_NO_ERROR) {
            cleanup();
            QEgl::eglDestroyImageKHR(QEgl::display(), eglImage);
            driver.Close();
            return;
        }

        w = sgImageInfo.iSizeInPixels.iWidth;
        h = sgImageInfo.iSizeInPixels.iHeight;
        d = 32; // We always use ARGB_Premultiplied for VG pixmaps.
        is_null = (w <= 0 || h <= 0);
        source = QImage();
        recreate = false;
        prevSize = QSize(w, h);
        setSerialNumber(++qt_vg_pixmap_serial);
        // release stuff
        QEgl::eglDestroyImageKHR(QEgl::display(), eglImage);
        driver.Close();
#endif
    } else if (type == QPixmapData::FbsBitmap) {
        CFbsBitmap *bitmap = reinterpret_cast<CFbsBitmap*>(pixmap);

        bool deleteSourceBitmap = false;

#ifdef Q_SYMBIAN_HAS_EXTENDED_BITMAP_TYPE

        // Rasterize extended bitmaps

        TUid extendedBitmapType = bitmap->ExtendedBitmapType();
        if (extendedBitmapType != KNullUid) {
            bitmap = createBlitCopy(bitmap);
            deleteSourceBitmap = true;
        }
#endif

        if (bitmap->IsCompressedInRAM()) {
            bitmap = createBlitCopy(bitmap);
            deleteSourceBitmap = true;
        }

        TDisplayMode displayMode = bitmap->DisplayMode();
        QImage::Format format = qt_TDisplayMode2Format(displayMode);

        TSize size = bitmap->SizeInPixels();

        bitmap->BeginDataAccess();
        uchar *bytes = (uchar*)bitmap->DataAddress();
        QImage img = QImage(bytes, size.iWidth, size.iHeight, format);
        img = img.copy();
        bitmap->EndDataAccess();

        if(displayMode == EGray2) {
            //Symbian thinks set pixels are white/transparent, Qt thinks they are foreground/solid
            //So invert mono bitmaps so that masks work correctly.
            img.invertPixels();
        } else if(displayMode == EColor16M) {
            img = img.rgbSwapped(); // EColor16M is BGR
        }

        fromImage(img, Qt::AutoColor);

        if(deleteSourceBitmap)
            delete bitmap;
    }
}
Example #15
0
void tst_QVolatileImage::bitmap()
{
#ifdef Q_OS_SYMBIAN
    CFbsBitmap *bmp = new CFbsBitmap;
    QVERIFY(bmp->Create(TSize(100, 50), EColor64K) == KErrNone);
    QVolatileImage bmpimg(bmp);
    CFbsBitmap *dupbmp = static_cast<CFbsBitmap *>(bmpimg.duplicateNativeImage());
    QVERIFY(dupbmp);
    QVERIFY(dupbmp != bmp);
    QCOMPARE(dupbmp->DataAddress(), bmp->DataAddress());
    delete dupbmp;
    delete bmp;
    bmpimg.beginDataAccess();
    qMemSet(bmpimg.bits(), 0, bmpimg.byteCount());
    qMemSet(bmpimg.bits(), 1, bmpimg.bytesPerLine() * bmpimg.height());
    bmpimg.endDataAccess();

    // Test bgr->rgb conversion in case of EColor16M.
    bmp = new CFbsBitmap;
    QVERIFY(bmp->Create(TSize(101, 89), EColor16M) == KErrNone);
    bmp->BeginDataAccess();
    TUint32 *addr = bmp->DataAddress();
    uint rgb = QColor(10, 20, 30).rgb();
    qMemCopy(bmp->DataAddress(), &rgb, 3);
    bmp->EndDataAccess();
    TRgb symrgb;
    bmp->GetPixel(symrgb, TPoint(0, 0));
    QVERIFY(symrgb.Red() == 10 && symrgb.Green() == 20 && symrgb.Blue() == 30);
    bmpimg = QVolatileImage(bmp);
    QVERIFY(bmpimg.toImage().pixel(0, 0) == rgb);
    // check if there really was a conversion
    bmp->BeginDataAccess();
    bmpimg.beginDataAccess();
    qMemCopy(&rgb, bmpimg.constBits(), 3);
    uint rgb2 = rgb;
    qMemCopy(&rgb2, bmp->DataAddress(), 3);
    QVERIFY(rgb != rgb2);
    bmpimg.endDataAccess(true);
    bmp->EndDataAccess(true);
    delete bmp;

    bmp = new CFbsBitmap;
    QVERIFY(bmp->Create(TSize(101, 89), EGray2) == KErrNone);
    bmpimg = QVolatileImage(bmp); // inverts pixels, but should do it in place
    QCOMPARE(bmpimg.constBits(), (const uchar *) bmp->DataAddress());
    QCOMPARE(bmpimg.format(), QImage::Format_MonoLSB);
    bmpimg.ensureFormat(QImage::Format_ARGB32_Premultiplied);
    QVERIFY(bmpimg.constBits() != (const uchar *) bmp->DataAddress());
    QCOMPARE(bmpimg.format(), QImage::Format_ARGB32_Premultiplied);
    delete bmp;

    // The following two formats must be optimal always.
    bmp = new CFbsBitmap;
    QVERIFY(bmp->Create(TSize(101, 89), EColor16MAP) == KErrNone);
    bmpimg = QVolatileImage(bmp);
    QCOMPARE(bmpimg.format(), QImage::Format_ARGB32_Premultiplied);
    QCOMPARE(bmpimg.constBits(), (const uchar *) bmp->DataAddress());
    bmpimg.ensureFormat(QImage::Format_ARGB32_Premultiplied);
    QCOMPARE(bmpimg.constBits(), (const uchar *) bmp->DataAddress());
    delete bmp;
    bmp = new CFbsBitmap;
    QVERIFY(bmp->Create(TSize(101, 89), EColor16MU) == KErrNone);
    bmpimg = QVolatileImage(bmp);
    QCOMPARE(bmpimg.format(), QImage::Format_RGB32);
    QCOMPARE(bmpimg.constBits(), (const uchar *) bmp->DataAddress());
    bmpimg.ensureFormat(QImage::Format_RGB32);
    QCOMPARE(bmpimg.constBits(), (const uchar *) bmp->DataAddress());
    delete bmp;

#else
    QSKIP("CFbsBitmap is only available on Symbian, skipping bitmap test", SkipSingle);
#endif
}
void S60ImageUtil::calculateVisibleRect(Image* aImage)
{
   if (aImage->iHasMask) {
      CFbsBitmap* mask = aImage->GetMask();
      TInt xmin = aImage->iWidth;
      TInt xmax = 0;
      TInt ymin = aImage->iHeight;
      TInt ymax = 0;
#if defined USE_AKN_LIB
      //Iterating the pixels with GetPixel() works for sure on all symbian,
      //but it's pretty slow and we have to look at every one pixel.
      //On a 800 x 800 image we do 640 000 GetPixel() iterations.
      TRgb color;
      TRgb white(255, 255, 255);
      for (TInt y = 0; y < aImage->iHeight; y++) {
         for (TInt x = 0; x < aImage->iWidth; x++) {
            mask->GetPixel(color, TPoint(x, y));
            if (color == white) {
               if (xmin > x) {
                  xmin = x;
               }
               if (xmax < x) {
                  xmax = x;
               }
               if (ymin > y) {
                  ymin = y;
               }
               if (ymax < y) {
                  ymax = y;
               }
            }
         }
      }
#else
      //Iterating the pixels by hand in memory probably works on all symbian,
      //it's much faster since we look at 8 pixels at a time, 
      //It needs some testing and verification.
      //On a 800 x 800 image we do roughly 83 000 iterations.
      TDisplayMode dMode = mask->DisplayMode();
      if (dMode == EGray2) {
# ifndef NAV2_CLIENT_SERIES60_V1
         mask->LockHeap();
# endif
         TUint32* imgPtr = mask->DataAddress();
         TSize imgSize = mask->SizeInPixels();
         TInt imgByteWidth = imgSize.iWidth >> 3;
         TInt imgBitsLeft = imgSize.iWidth % 8;
         TInt lineLength = CFbsBitmap::ScanLineLength(imgSize.iWidth, dMode);
         TUint8* pCurrByteLine = (TUint8*) imgPtr;
         TUint8 currByte;
         TInt currXPixelOffset;
         TInt currXPixel;
         for (TInt y = 0; y < imgSize.iHeight; y++) {
            for (TInt x = 0; x < imgByteWidth; x++) {
               currByte = pCurrByteLine[x];
               //If currByte is != 0, it contains at least one white pixel.
               if (currByte) {
                  if (ymin > y) {
                     ymin = y;
                  }
                  if (ymax < y) {
                     ymax = y;
                  }
                  currXPixelOffset = x << 3;
                  //Check if this byte of pixels might contain xmin or xmax.
                  if ((currXPixelOffset < xmin) || 
                      ((currXPixelOffset + 7) > xmax)) {
                     for (TInt b = 0; b < 8; b++) {
                        //Some of the 8 pixels in the byte are visible.
                        //Find which ones that mather for the x-axis.
                        if  (currByte & (1 << b)) {
                           currXPixel = currXPixelOffset + b;
                           if (xmin > currXPixel) {
                              xmin = currXPixel;
                           }
                           if (xmax < currXPixel) {
                              xmax = currXPixel;
                           }
                        }
                     }
                  }
               }
            }
            //Here we take care of bit padded bytes when the
            //image width is not evenly dividable by a byte.
            if (imgBitsLeft != 0) {
               currByte = pCurrByteLine[imgByteWidth];
               currXPixelOffset = imgByteWidth << 3;
               for (TInt b = 0; b < imgBitsLeft; b++) {
                  if  (currByte & (1 << b)) {
                     currXPixel = currXPixelOffset + b;
                     if (xmax < currXPixel) {
                        xmax = currXPixel;
                     }
                  }
               }
            }
            //Move to next line in image.
            pCurrByteLine = pCurrByteLine + lineLength;
         }
      }
CFbsBitmap* AknBitmapMirrorUtils::CreateBitmapOptimizedL(CFbsBitmap* aSourceBitmap, TInt aMirrorDirection)
    {
    // Check if displaymode is optimized, fallback to non-optimized version if not.
    TBool fallback = ETrue;
    TDisplayMode displayMode = aSourceBitmap->DisplayMode();
    switch( displayMode )
        {
        case EGray256:
        case EColor256:
        case EColor4K:
        case EColor64K:
            fallback = EFalse;
            break;
        default:
            fallback = ETrue;
        }

    // Check if mirroring mode is supported, fallback to non-optimized version if not.
	if ((aMirrorDirection != EAknVerticalMirroring) && (aMirrorDirection != EAknHorizontalMirroring))
		{
		fallback = ETrue;	
		}

    if( fallback )
		return CreateBitmapL(aSourceBitmap, aMirrorDirection);
    
	// Prepare destination bitmap
    User::LeaveIfNull(aSourceBitmap);
    CFbsBitmap* destinationBitmap = new (ELeave) CFbsBitmap();
    CleanupStack::PushL(destinationBitmap);   

    TSize sourceBitmapSize = aSourceBitmap->SizeInPixels();            
    TRect sourceRect = TRect(TPoint(0,0), sourceBitmapSize);
    TSize destinationBitmapSize(sourceRect.Width(), sourceRect.Height()); 

    User::LeaveIfError(destinationBitmap->Create(destinationBitmapSize, aSourceBitmap->DisplayMode()));

	// Check source, if rom bitmap or compressed then create uncompressed ram bitmap
    TBool srcTemporary = EFalse;
    if( aSourceBitmap->IsRomBitmap() )
        {
        srcTemporary = ETrue;
        }
        
    // Heap lock for FBServ large chunk to prevent background
    // compression of aSrcBitmap after if IsCompressedInRAM returns EFalse
    aSourceBitmap->LockHeapLC( ETrue ); // fbsheaplock
    TBool fbsHeapLock = ETrue;        
        
    if( aSourceBitmap->IsCompressedInRAM() )
        {
        srcTemporary = ETrue;
        }
    if( aSourceBitmap->ExtendedBitmapType() != KNullUid  )
        {
        srcTemporary = ETrue;
        }

    CFbsBitmap* realSource = aSourceBitmap;
    if( srcTemporary )
        {
        CleanupStack::PopAndDestroy(); // fbsheaplock
        fbsHeapLock = EFalse;
        
        realSource = new (ELeave) CFbsBitmap();
        CleanupStack::PushL( realSource );
        User::LeaveIfError( realSource->Create( sourceBitmapSize, aSourceBitmap->DisplayMode() ) );
        CFbsBitmapDevice* dev = CFbsBitmapDevice::NewL( realSource );
        CleanupStack::PushL( dev );
        CFbsBitGc* gc = NULL;
        User::LeaveIfError( dev->CreateContext( gc ) );
        CleanupStack::PushL( gc );
        gc->BitBlt( TPoint(0,0), aSourceBitmap );
        CleanupStack::PopAndDestroy(2); // dev, gc
        }

	// Heap lock for FBServ large chunk is only needed with large bitmaps.
    if (!fbsHeapLock)
    	{
	    if ( realSource->IsLargeBitmap() || destinationBitmap->IsLargeBitmap() )
	        {
	        destinationBitmap->LockHeapLC( ETrue ); // fbsheaplock
	        }
	    else
	        {
	        CleanupStack::PushL( (TAny*)NULL );
	        }
    	}

    TUint32* srcAddress = realSource->DataAddress();
    TUint32* trgAddress = destinationBitmap->DataAddress();

    if ( displayMode == EColor4K || displayMode == EColor64K )
        {
        TInt srcScanLen16 = CFbsBitmap::ScanLineLength(sourceBitmapSize.iWidth, displayMode) / 2;
        TInt trgScanLen16 = CFbsBitmap::ScanLineLength(destinationBitmapSize.iWidth, displayMode) / 2;
        TInt srcScanLen32 = CFbsBitmap::ScanLineLength(sourceBitmapSize.iWidth, displayMode) / 4;
        TInt trgScanLen32 = CFbsBitmap::ScanLineLength(destinationBitmapSize.iWidth, displayMode) / 4;

	    switch (aMirrorDirection)
	        {
	        case EAknVerticalMirroring:
	            {
		        TUint32* trgAddress32 = trgAddress;
	            TUint32* srcAddress32 = srcAddress;            	
           		TInt trgPos = 0;
            	for ( TInt yPos=destinationBitmapSize.iHeight-1; yPos >= 0; yPos-- )
            		{
		            srcAddress32 = srcAddress + srcScanLen32*yPos;
            		trgAddress32 = trgAddress + trgScanLen32*trgPos;            			
            		memcpy(trgAddress32, srcAddress32, srcScanLen32*4);
            		trgPos++;
            		}
	            break;
	            }
	        case EAknHorizontalMirroring:
	            {
		        TUint16* trgAddress16 = reinterpret_cast<TUint16*>(trgAddress);
	            TUint16* srcAddress16 = reinterpret_cast<TUint16*>(srcAddress);            	
           		TInt xTrgPos = 0;
            	for ( TInt yPos=destinationBitmapSize.iHeight-1; yPos >= 0; yPos-- )
            		{
	           		xTrgPos = 0;            		            		
	            	for ( TInt xPos=destinationBitmapSize.iWidth-1; xPos >= 0; xPos-- )
	            		{
						trgAddress16[xTrgPos] = srcAddress16[xPos];
						xTrgPos++;
	            		}
            		srcAddress16 += srcScanLen16;
	            	trgAddress16 += trgScanLen16;	            		
            		}
	            
	            break;
	            }
	        default:
	            {
	            break;
	            }
	        }
        }
	else if( (displayMode==EGray256) || (displayMode==EColor256) )
        {
        TInt srcScanLen8 = CFbsBitmap::ScanLineLength(sourceBitmapSize.iWidth, displayMode);
        TInt trgScanLen8 = CFbsBitmap::ScanLineLength(destinationBitmapSize.iWidth, displayMode);
        TInt srcScanLen32 = CFbsBitmap::ScanLineLength(sourceBitmapSize.iWidth, displayMode) / 4;
        TInt trgScanLen32 = CFbsBitmap::ScanLineLength(destinationBitmapSize.iWidth, displayMode) / 4;
                
	    switch (aMirrorDirection)
	        {
	        case EAknVerticalMirroring:
	            {
		        TUint32* trgAddress32 = trgAddress;
	            TUint32* srcAddress32 = srcAddress;            	
           		TInt trgPos = 0;
            	for ( TInt yPos=destinationBitmapSize.iHeight-1; yPos >= 0; yPos-- )
            		{
		            srcAddress32 = srcAddress + srcScanLen32*yPos;
            		trgAddress32 = trgAddress + trgScanLen32*trgPos;            			
            		memcpy(trgAddress32, srcAddress32, srcScanLen32*4);
            		trgPos++;
            		}
	            break;
	            }
	        case EAknHorizontalMirroring:
	            {
		        TUint8* trgAddress8 = reinterpret_cast<TUint8*>(trgAddress);
	            TUint8* srcAddress8 = reinterpret_cast<TUint8*>(srcAddress);            	
           		TInt xTrgPos = 0;
            	for ( TInt yPos=destinationBitmapSize.iHeight-1; yPos >= 0; yPos-- )
            		{
	           		xTrgPos = 0;            		            		
	            	for ( TInt xPos=destinationBitmapSize.iWidth-1; xPos >= 0; xPos-- )
	            		{
						trgAddress8[xTrgPos] = srcAddress8[xPos];
						xTrgPos++;
	            		}
            		srcAddress8 += srcScanLen8;
	            	trgAddress8 += trgScanLen8;	            			            
            		}
	            break;
	            }
	        default:
	            {
	            break;
	            }        	            
	        }
        }

	CleanupStack::PopAndDestroy(); // fbsheaplock

    if( srcTemporary )
        {
        CleanupStack::PopAndDestroy(); // realSource
        }

    CleanupStack::Pop(); // destinationBitmap
    return destinationBitmap;   
    }
/**
@SYMTestCaseID GRAPHICS-EGL-0127

@SYMTestPriority 1

@SYMPREQ 39

@SYMREQ See SGL.GT0386.401 document

@SYMTestCaseDesc
Check that iUsage bits are enforced.
It’s not possible to create a VGImage from an RSgImage can’t be used as a VGImage source.

@SYMTestActions
Create a reference Bitmap
Create and fully construct an RSgImage object having the same content as the reference bitmap
•	Set the iUsage bits to ESgUsageBitOpenGlesSurface
Pass the RSgImage objects into eglCreateImageKHR() with
•	The target parameter set to EGL_NATIVE_PIXMAP_KHR
•	Use the current display and EGL_NO_CONTEXT
•	Use a NULL attr_list
Check that those calls to eglCreateImageKHR() returns EGL_NO_IMAGE_KHR
The following will only be exercised if OpenGL_ES2 is supported
•	Set the iUsage bits to ESgUsageBitOpenGles2Texture2D
Pass the RSgImage objects into eglCreateImageKHR() with
•	The target parameter set to EGL_NATIVE_PIXMAP_KHR
•	Use the current display and EGL_NO_CONTEXT
•	Use a NULL attr_list
Check that those calls to eglCreateImageKHR() do NOT return EGL_NO_IMAGE_KHR
Create and make current and EGL context bound to OVG APIs and linked to a pixmap surface.
•	Set the iUsage bit of the underlying RSgImage to ESgUsageBitOpenVgSurface
Use vgCreateEGLImageTargetKHR() to construct a VGImage object from the just created EGLImage.
This call should return VG_UNSUPPORTED_IMAGE_FORMAT_ERROR since the underlying RSgImage needs iUsage of ESgOpenVgImage to make this call succeed.
Pass the EGLImage into eglDestroyImageKHR()
Close the RSgImage
Destroy the pixmap
Check for memory and handle leaks

@SYMTestExpectedResults
eglCreateImageKHR() does return EGL_BAD_PARAMETER
No memory or handle leaks
*/
TVerdict CEglTest_EGL_Image_UsageBits_Enforcement::doTestStepL()
	{
	SetTestStepID(_L("GRAPHICS-EGL-0127"));
	INFO_PRINTF1(_L("CEglTest_EGL_Image_UsageBits_Enforcement::doTestStepL"));

	TBool ret = CheckForExtensionL(KEGL_RSgimage | KEGL_KHR_image_base | KEGL_KHR_image_pixmap | KVG_KHR_EGL_image);
	if(!ret)
		{
		// The extension is not supported
		RecordTestResultL();
		CloseTMSGraphicsStep();
		return TestStepResult();
		}

	// This test is performed for default pixel format
	PrintUsedPixelConfiguration();

	// Create display object
	GetDisplayL();
	CreateEglSessionL();
	iEglSess->InitializeL();
	iEglSess->OpenSgDriverL();

	// Create a reference bitmap which we use to init the SgImage (we use index=8)
	TDisplayMode bitmapMode = EglTestConversion::PixelFormatToDisplayMode(iSourceFormat);
	CFbsBitmap* bitmap = iEglSess->CreateReferenceBitmapL(bitmapMode, KPixmapSize, 8);
	CleanupStack::PushL(bitmap);

	// Create RSgImage's attributes.
	TSgImageInfoTest imageInfo;
	imageInfo.iSizeInPixels = KPixmapSize;
	imageInfo.iPixelFormat = iSourceFormat;
#ifdef SYMBIAN_GRAPHICS_EGL_SGIMAGELITE
	imageInfo.iUsage = ESgUsageBitOpenGlesSurface;
#else
	imageInfo.iUsage = ESgUsageDirectGdiSource;
	imageInfo.iShareable = EFalse;
	imageInfo.iCpuAccess = ESgCpuAccessNone;
	imageInfo.iScreenId = KSgScreenIdMain;
	imageInfo.iUserAttributes = NULL;
	imageInfo.iUserAttributeCount = 0;
#endif //SYMBIAN_GRAPHICS_EGL_SGIMAGELITE

	RSgImage sgImage;
	CleanupClosePushL(sgImage);
	ASSERT_EQUALS(sgImage.Create(imageInfo, bitmap->DataAddress(), bitmap->DataStride()), KErrNone);

	//First Subtest: Attempted creation of an EGLImageKhr from an RSgImage with the wrong Usage should fail
	INFO_PRINTF1(_L("Attempt creation of an EGLImage from a RSgImage with incorrect iUsage ESgUsageBitOpenGlesSurface"));
	INFO_PRINTF1(_L("Correct iUsage needs to have at least one of ESgUsageBitOpenVgImage, ESgUsageOpenGlesTexture2D or ESgUsageOpenGles2Texture2D bits set"));

	EGLImageKHR imageKHR = iEglSess->eglCreateImageKhrL(iDisplay, EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR, &sgImage, KEglImageAttribsPreservedTrue);
	ASSERT_EGL_TRUE(imageKHR == EGL_NO_IMAGE_KHR);
	ASSERT_EGL_ERROR(EGL_BAD_PARAMETER);
    CleanupStack::PopAndDestroy(&sgImage);

	if(iEglSess->IsOpenGLES2Supported())
	    {
	    TSgImageInfoTest imageInfo2;
		imageInfo2.iSizeInPixels = KPixmapSize;
		imageInfo2.iPixelFormat = iSourceFormat;
#ifdef SYMBIAN_GRAPHICS_EGL_SGIMAGELITE
		imageInfo2.iUsage = ESgUsageBitOpenGles2Texture2D;
#else
		imageInfo2.iUsage = ESgUsageOpenGlesTexture2D;
#endif //SYMBIAN_GRAPHICS_EGL_SGIMAGELITE

	    // Create a SgImage
		RSgImage sgImage2;
		CleanupClosePushL(sgImage2);
		ASSERT_EQUALS(sgImage2.Create(imageInfo2, bitmap->DataAddress(), bitmap->DataStride()), KErrNone);

	    // The creation of an EGLImage from a RSgImage with correct usage (ESgUsageBitOpenGles2Texture2D or ESgUsageOpenGlesTexture2D) should pass
		EGLImageKHR imageKHR2 = iEglSess->eglCreateImageKhrL(iDisplay, EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR, &sgImage2, KEglImageAttribsPreservedTrue);
		ASSERT_EGL_TRUE(imageKHR2 != EGL_NO_IMAGE_KHR);

	    //Create an OffScreen Pixmap, we need it to make a Context current
	    imageInfo2.iSizeInPixels = KPixmapSize;
	    imageInfo2.iPixelFormat = iSourceFormat;
#ifdef SYMBIAN_GRAPHICS_EGL_SGIMAGELITE
		imageInfo2.iUsage = ESgUsageBitOpenVgSurface;
#else
		imageInfo2.iUsage = ESgUsageOpenVgTarget;
#endif //SYMBIAN_GRAPHICS_EGL_SGIMAGELITE
	    iEglSess->CreatePixmapSurfaceAndMakeCurrentAndMatchL(imageInfo2,CTestEglSession::EResourceCloseSgImageEarly);

	    // Create a VGImage from the EGLImage
	    //Second Subtest: creation of an VGImage from an EGLImage whose RSgImage has NOT ESgUsageBitOpenVgImage as usage will fail
	    VGImage vgImageTarget = iEglSess->vgCreateImageTargetKHR((VGeglImageKHR)imageKHR2);
	    ASSERT_VG_TRUE(vgImageTarget == VG_INVALID_HANDLE);
	    ASSERT_TRUE(vgGetError()==VG_UNSUPPORTED_IMAGE_FORMAT_ERROR);

        CleanupStack::PopAndDestroy(&sgImage2);
        ASSERT_EGL_TRUE(iEglSess->DestroyEGLImage(iDisplay, imageKHR2));
	    }

	//cleanup
	CleanupStack::PopAndDestroy(bitmap);
	CleanAll();

	RecordTestResultL();
	CloseTMSGraphicsStep();
	return TestStepResult();
	}
void CEglTest_EGL_Image_Multi_Thread_Sibling_VGImage::doThreadFunctionL(TInt aIdx)
	{	
	INFO_PRINTF2(_L("CEglTest_EGL_Image_Multi_Thread_Sibling_VGImage::doThreadFunctionL, Thread %d"),aIdx);
	CTestEglSession* eglSess = CTestEglSession::NewLC(Logger(), iDisplay, aIdx);
	eglSess->InitializeL();
	eglSess->OpenSgDriverL();

	INFO_PRINTF2(_L("Thread %d, Creating a Surface and a Context bound to OpenVG"),aIdx);
	TUidPixelFormat pixelFormat = EglTestConversion::VgFormatToSgPixelFormat(KDefaultSurfaceFormat);
	TSgImageInfoOpenVgTarget imageInfo = TSgImageInfoOpenVgTarget(pixelFormat, KPixmapSize);
	// Create a pixmap surface matching the native image pixel format
	eglSess->CreatePixmapSurfaceAndMakeCurrentAndMatchL(imageInfo,CTestEglSession::EResourceCloseSgImageEarly);
	
	// Create a VGImage from the EGLImage
	INFO_PRINTF2(_L("Thread %d, Creating one VGImage from the shared EGLImage"),aIdx);
	VGImage vgImageLocal = eglSess->vgCreateImageTargetKHR((VGeglImageKHR)iEGLImageShared);	
	ASSERT_VG_TRUE(vgImageLocal != VG_INVALID_HANDLE);
	
	Rendezvous(aIdx);
		
	if(aIdx == 0)
		{
		INFO_PRINTF2(_L("Thread %d, Updating contents of the VGImage from the shared EGLImage"),aIdx);
		TDisplayMode bitmapMode = EglTestConversion::PixelFormatToDisplayMode(KDefaultSourceFormat);
		CFbsBitmap* bitmap = eglSess->CreateReferenceBitmapL(bitmapMode, KPixmapSize, 8);
    	// Add pixel data to the VGImage reference from the bitmap reference. 
        // Mind the fact that CFbsBitmap and VGImages use different coordinates origin!
		TSize bitmapSize = bitmap->SizeInPixels();
    	TUint8* address = reinterpret_cast<TUint8*>(bitmap->DataAddress());
    	TInt stride = bitmap->DataStride();
    	address += (bitmapSize.iHeight - 1) * stride;
        vgImageSubData(vgImageLocal, address, -stride, KDefaultSurfaceFormat, 0,0, bitmapSize.iWidth, bitmapSize.iHeight);
		delete bitmap;
        bitmap = NULL;
		ASSERT_TRUE(vgGetError()==VG_NO_ERROR);
		eglWaitClient();
		}

	Rendezvous(aIdx);
	
	if(aIdx == 1)
		{
		INFO_PRINTF2(_L("Thread %d, Drawing the VGImage to the current surface"),aIdx);
		// Copy the source VGImage to the surface
    	vgSetPixels(0, 0, vgImageLocal, 0, 0, KPixmapSize.iWidth, KPixmapSize.iHeight);
		ASSERT_TRUE(vgGetError()==VG_NO_ERROR);
		eglWaitClient();

		// we can now compare the VgImage to the one we expect after changing it in the other thread
		TDisplayMode bitmapMode = EglTestConversion::PixelFormatToDisplayMode(KDefaultSourceFormat);
		CFbsBitmap* refBitmap = eglSess->CreateReferenceBitmapL(bitmapMode, KPixmapSize, 8);
		CleanupStack::PushL(refBitmap);
		eglSess->CheckVgDrawingL(KDefaultSurfaceFormat, refBitmap);
		CleanupStack::PopAndDestroy(refBitmap);
		INFO_PRINTF2(_L("Thread %d, Drawing successful"),aIdx);
		}		
	
	// cleanup
	vgDestroyImage(vgImageLocal);
	ASSERT_TRUE(vgGetError() == VG_NO_ERROR);
	eglSess->CloseSgDriver();
	CleanupStack::PopAndDestroy(eglSess);
	}
void CEglTest_EGL_Image_Multi_Thread_DrawAfterTerminate::doThreadFunctionL(TInt aIdx)
	{
	INFO_PRINTF2(_L("CEglTest_EGL_Image_Multi_Thread_DrawAfterTerminate::doThreadFunctionL, Thread %d"),aIdx);
	GetDisplayL();
	CTestEglSession* eglSess = CTestEglSession::NewLC(Logger(), iDisplay, aIdx);
	eglSess->InitializeL();
	eglSess->OpenSgDriverL();

	TRequestStatus statusThread1;
	VGImage vgImageLocal = VG_INVALID_HANDLE;
	EGLint surfaceWidth;
	EGLint surfaceHeigth;
	
	//Thread0 asks to be notified when Thread1 exits
	//Creates a RSgImage having the reference bitmap as content
	//Creates a EGLImage from the RSgImage
	//Creates a surface
	//Creates a VGImage from the EGLImage
	if(aIdx == 0)
		{
		// Thread0 asks to be notified when Thread1 exits
		iThreadStatus[1].iThread.Logon(statusThread1);

	    RSgImage rSgImageLocal;
		CleanupClosePushL(rSgImageLocal);

		// create a reference bitmap (we give index 9, as there's only 1 image in this test case)
		TDisplayMode bitmapMode = EglTestConversion::PixelFormatToDisplayMode(KDefaultSourceFormat);
		CFbsBitmap* bitmap = eglSess->CreateReferenceBitmapL(bitmapMode, KPixmapSize, 9);
		CleanupStack::PushL(bitmap);

		// Create an RSgImage
		INFO_PRINTF2(_L("Thread %d, Creating a RSgImage having the reference bitmap's content"),aIdx);
		TSgImageInfoOpenVgImage imageInfo = TSgImageInfoOpenVgImage(KDefaultSourceFormat, KPixmapSize);
		ASSERT_EQUALS(rSgImageLocal.Create(imageInfo,bitmap->DataAddress(),bitmap->DataStride()), KErrNone);
		CleanupStack::PopAndDestroy(bitmap);

		INFO_PRINTF2(_L("Thread %d, Creating an EGLImage from the shared RSgImage"),aIdx);
		EGLImageKHR eglImageLocal = eglSess->eglCreateImageKhrL(iDisplay, EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR, &rSgImageLocal, KEglImageAttribsPreservedTrue);
		ASSERT_EGL_TRUE(eglImageLocal != EGL_NO_IMAGE_KHR);
		CleanupStack::PopAndDestroy(&rSgImageLocal); 	//transferring ownership of the buffer to the EGLImage

		INFO_PRINTF2(_L("Thread %d, Creating a Surface and a Context bound to OpenVG"),aIdx);
		TUidPixelFormat pixelFormat = EglTestConversion::VgFormatToSgPixelFormat(KDefaultSurfaceFormat);
		TSgImageInfoOpenVgTarget imageInfo2 = TSgImageInfoOpenVgTarget(pixelFormat, KPixmapSize);
		// Create a pixmap surface matching the native image pixel format
		eglSess->CreatePixmapSurfaceAndMakeCurrentAndMatchL(imageInfo2,CTestEglSession::EResourceCloseSgImageEarly);

		//We now store the size of the surface because after eglTerminate is called on the display
		//it will not be possible to use explicitly all the resources linked to it
		//i.e. every call to an EGL API who takes a display as an argument will raise a EGL_BAD_DISPLAY error
		eglQuerySurface(iDisplay, eglSess->Surface(), EGL_WIDTH, &surfaceWidth);
		eglQuerySurface(iDisplay, eglSess->Surface(), EGL_HEIGHT, &surfaceHeigth);		
		
		INFO_PRINTF2(_L("Thread %d, Creating one VGImage from the EGLImage"),aIdx);
		vgImageLocal = eglSess->vgCreateImageTargetKHR((VGeglImageKHR)eglImageLocal);	
		ASSERT_VG_TRUE(vgImageLocal != VG_INVALID_HANDLE);
		ASSERT_EGL_TRUE(eglSess->DestroyEGLImage(iDisplay, eglImageLocal));
		}
	
	Rendezvous(aIdx);
	
	//Thread1 calls eglTerminate and exit
	if(aIdx == 1)
		{
		INFO_PRINTF2(_L(", Thread %d, Calling eglTerminate and exiting"),aIdx);
		TerminateDisplayL();
		}
	
	Rendezvous(aIdx);
	
	//Thread0 resumes when Thread1 exits
	//and it uses the resources that are linked to the just destroyed display
	if(aIdx == 0)
		{
		User::WaitForRequest(statusThread1);

		// It's still possible to use the current context, surface and VGImage even though the display has been terminated
		//Copy the source VGImage to the surface
    	vgSetPixels(0, 0, vgImageLocal, 0, 0, KPixmapSize.iWidth, KPixmapSize.iHeight);
		ASSERT_TRUE(vgGetError()==VG_NO_ERROR);
		eglWaitClient();

		// we can now compare the VgImage to the one we would expect for this particular thread
		TDisplayMode bitmapMode = EglTestConversion::PixelFormatToDisplayMode(KDefaultSourceFormat);
		CFbsBitmap* refBitmap = eglSess->CreateReferenceBitmapL(bitmapMode, KPixmapSize, 9);
		CleanupStack::PushL(refBitmap);
		eglSess->CheckVgDrawingL(KDefaultSurfaceFormat, refBitmap);
		CleanupStack::PopAndDestroy(refBitmap);
		INFO_PRINTF2(_L("Drawing successful, Thread %d"),aIdx);

		vgDestroyImage(vgImageLocal);
		ASSERT_TRUE(vgGetError() == VG_NO_ERROR);
		eglReleaseThread();
		}
	
	// cleanup
	eglSess->CloseSgDriver();
	CleanupStack::PopAndDestroy(eglSess);
	}
Example #21
0
/*
 * Landmark objects will make use of an SVG file for rendering (demo purposes)
 */
void CLMXObject::ConstructL()
{
    _LIT(KIconFile, "\\resource\\apps\\Landmarks_0x2002E1AF.mif");

    CGulIcon* icon = CreateIconL(KIconFile, EMbmLandmarks_0x2002e1afIcon, EMbmLandmarks_0x2002e1afIcon_mask);
    CleanupStack::PushL(icon);

    CFbsBitmap* bitmap = icon->Bitmap();    // Ownership NOT transferred
    CFbsBitmap* mask   = icon->Mask();      // Ownership NOT transferred

    // Always expect 16M bitmap to make conversion to GL_RGBA easier 
    if (bitmap->DisplayMode() != EColor16M)
    {
        bitmap = new(ELeave) CFbsBitmap;
        CleanupStack::PushL(bitmap);

        User::LeaveIfError(bitmap->Create(icon->Bitmap()->SizeInPixels(), EColor16M));

        CFbsBitmapDevice* bitmapDevice = CFbsBitmapDevice::NewL(bitmap);
        CleanupStack::PushL(bitmapDevice);

        CFbsBitGc* bitmapContext = 0;
        User::LeaveIfError(bitmapDevice->CreateContext(bitmapContext));
        CleanupStack::PushL(bitmapContext);

        bitmapContext->BitBlt(TPoint(0, 0), icon->Bitmap());

        CleanupStack::PopAndDestroy(2, bitmapDevice);

        icon->SetBitmap(bitmap);    // Ownership transferred

        CleanupStack::Pop(bitmap);
    }

    // Always expect 256 mask to make conversion to GL_RGBA easier 
    if (mask->DisplayMode() != EGray256)
    {
        mask = new(ELeave) CFbsBitmap;
        CleanupStack::PushL(mask);

        User::LeaveIfError(mask->Create(icon->Mask()->SizeInPixels(), EGray256));

        CFbsBitmapDevice* bitmapDevice = CFbsBitmapDevice::NewL(mask);
        CleanupStack::PushL(bitmapDevice);

        CFbsBitGc* bitmapContext = 0;
        User::LeaveIfError(bitmapDevice->CreateContext(bitmapContext));
        CleanupStack::PushL(bitmapContext);

        bitmapContext->BitBlt(TPoint(0, 0), icon->Mask());

        CleanupStack::PopAndDestroy(2, bitmapDevice);

        icon->SetMask(mask);    // Ownership transferred

        CleanupStack::Pop(mask);
    }

    // Now bitmap and mask point to either original or converted bitmaps, 
    // and ownership belongs to icon

    const TSize bitmapSize = bitmap->SizeInPixels();

    // sizeof(TUint32) == sizeof(RGBA)
    const TInt dataSize = bitmapSize.iWidth * bitmapSize.iHeight * sizeof(TUint32);
    TUint8* data = new(ELeave) TUint8[dataSize];

    // Perform copy and conversion from BGR(A) to RGB(A)
    bitmap->LockHeap();
    mask->LockHeap();

    // TODO: Alpha component removed, as it seems to be corrupted from
    // subsequent reads from SVG file

    TUint8* rgb = reinterpret_cast<TUint8*>(bitmap->DataAddress());
//    TUint8* alpha = reinterpret_cast<TUint8*>(mask->DataAddress());

    for(TInt i = 0, j = 0; i < dataSize; i += 4, j += 3)
    {
        data[i + 0] = rgb[j + 2];
        data[i + 1] = rgb[j + 1];
        data[i + 2] = rgb[j + 0];
        data[i + 3] = 0xc0; //alpha[i / 4];
    }

    // Generate OpenGL texture
    ::glGenTextures(1, &iTextureId); 
    ::glBindTexture(GL_TEXTURE_2D, iTextureId);

    ::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    ::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    ::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    ::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    ::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bitmapSize.iWidth, bitmapSize.iHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);

    mask->UnlockHeap();
    bitmap->UnlockHeap();

    delete data;

    CleanupStack::PopAndDestroy(icon);
}