--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/egl/egltest/src/egltest_image_multiprocess.cpp Tue Feb 02 01:47:50 2010 +0200
@@ -0,0 +1,2407 @@
+// Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+/**
+ @file
+ @test
+*/
+
+#include <test/tefunit.h> // for ASSERT macros
+#ifndef __INIPARSER_H__
+#include <cinidata.h>
+#endif // __INIPARSER_H__
+#include <e32msgqueue.h>
+
+#include "egltest_image_multiprocess.h"
+
+#include <test/egltestcommonconversion.h>
+#include <test/egltestcommoninisettings.h>
+#include <test/egltestcommonsgimageinfo.h>
+#include <test/egltestcommonprocess.h>
+
+//
+// Constant definitions
+//
+const TInt KNumProcesses = 8;
+const TInt KNumImages = 4;
+#define KImageSize TSize(100,100) // use #define to avoid global temporary constructors
+
+
+/**
+@SYMTestCaseID GRAPHICS-EGL-0160
+
+@SYMTestPriority 1
+
+@SYMPREQ 39
+
+@SYMREQ See SGL.GT0386.401 document
+
+@SYMTestCaseDesc
+Check if EGL Implementation allows two processes to work in parallel.
+A process can create an EGLImage from the same RSgImage that already has been linked to an EGLImage by another process.
+
+@SYMTestActions
+Main Process: creates an RsgImage and starts Process and Process.
+Process1: Creates an EGLImage from the RsgImage previous mentioned
+--------
+Process2: Creates an EGLImage from the RsgImage previous mentioned and check that eglCreateImageKHR() does NOT return EGL_NO_IMAGE_KHR
+--------
+Process1: Closes the EGLImage
+Process2: Closes the EGLImage
+Main Process: Closes the RsgImage
+
+@SYMTestExpectedResults
+No errors within both processes.
+No memory or handle leaks
+*/
+TVerdict CEglTest_EGL_Image_Multi_Process_Sibling_Basic::doTestStepL()
+ {
+ SetTestStepID(_L("GRAPHICS-EGL-0160"));
+ SetTestStepName(KEGL_Image_Multi_Process_Sibling_Basic);
+ INFO_PRINTF1(_L("Enter: CEglTest_EGL_Image_Multi_Process_Sibling_Basic::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();
+ CreateEglSessionL();
+ iEglSess->InitializeL();
+ iEglSess->OpenSgDriverL();
+
+ // create a reference bitmap (we give index 0, as there's only 1 image in this test case)
+ TDisplayMode bitmapMode = EglTestConversion::PixelFormatToDisplayMode(KDefaultSourceFormat);
+ CFbsBitmap* bitmap = iEglSess->CreateReferenceBitmapL(bitmapMode, KImageSize, 0);
+ CleanupStack::PushL(bitmap);
+
+ // Create an RSgImage
+ TSgImageInfoOpenVgImage imageInfo = TSgImageInfoOpenVgImage(KDefaultSourceFormat, KImageSize);
+#ifndef SYMBIAN_GRAPHICS_EGL_SGIMAGELITE
+ imageInfo.iShareable = ETrue;
+#endif //SYMBIAN_GRAPHICS_EGL_SGIMAGELITE
+ RSgImage sgImage;
+ CleanupClosePushL(sgImage);
+ ASSERT_EQUALS(sgImage.Create(imageInfo,bitmap->DataAddress(),bitmap->DataStride()), KErrNone);
+
+ // launch 2 processes
+ Test_MultiProcessL(KEglTestStepDllName, 2, TestStepName(), sgImage.Id());
+
+ // destroy sgImage
+ CleanupStack::PopAndDestroy(2, bitmap);
+
+ // clean everything
+ CleanAll();
+ INFO_PRINTF1(_L("Exit: CEglTest_EGL_Image_Multi_Process_Sibling_Basic::doTestStepL"));
+ RecordTestResultL();
+ CloseTMSGraphicsStep();
+ return TestStepResult();
+ }
+
+void CEglTest_EGL_Image_Multi_Process_Sibling_Basic::doProcessFunctionL(TInt aIdx,const TSgDrawableId& aSgId)
+ {
+ INFO_PRINTF2(_L("CEglTest_EGL_Image_Multi_Process_Sibling_Basic::doProcessFunctionL, Process %d"),aIdx);
+ GetDisplayL();
+ CreateEglSessionL(aIdx);
+ iEglSess->InitializeL();
+ iEglSess->OpenSgDriverL();
+
+ RSgImage sgImageFromId;
+ CleanupClosePushL(sgImageFromId);
+ ASSERT_EQUALS(sgImageFromId.Open(aSgId),KErrNone);
+
+ INFO_PRINTF2(_L("Process %d, Creating an EGLImage from the shared RSgImage"),aIdx);
+ EGLImageKHR eglImage = iEglSess->eglCreateImageKhrL(iDisplay, EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR, &sgImageFromId, KEglImageAttribsPreservedTrue);
+ ASSERT_EGL_TRUE(eglImage != EGL_NO_IMAGE_KHR);
+ CleanupStack::PopAndDestroy(&sgImageFromId);
+
+ INFO_PRINTF2(_L("Process %d, EGLImage successfully created, now destroying it"),aIdx);
+ ASSERT_EGL_TRUE(iEglSess->DestroyEGLImage(iDisplay, eglImage));
+
+ // cleanup
+ CleanAll();
+ }
+
+
+/**
+@SYMTestCaseID GRAPHICS-EGL-0161
+
+@SYMTestPriority 1
+
+@SYMPREQ 39
+
+@SYMREQ See SGL.GT0386.401 document
+
+@SYMTestCaseDesc
+Check if EGL Implementation allows two processes to work in parallel.
+
+@SYMTestActions
+Run two processes that independently perform the same actions detailed below.
+This test will check for the “VG_KHR_EGL_image” extension, if it is not
+supported on this platform then the test will return immediately without failure.
+Create and fully construct an RSgImage object
+• Set the iUsage bits to ESgUsageBitOpenVgImage
+Pass the RSgImage object 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 eglCreateImageKHR() does NOT return EGL_NO_IMAGE_KHR
+Use vgCreateEGLImageTargetKHR() to construct a VGImage object from the EGLImage.
+• Check for errors (VGInvalidHandle is not returned)
+Create a second RSgImage, and use it to create a pixmap surface that is
+compatible as a target for the VGImage to be drawn to.
+• Set the iUsage bit to ESgUsageBitOpenVgSurface
+• Use the same pixel format as the RSgImage above.
+Now that a eglContext and an OpenVG context have been created, use the
+OpenVG API vgClearImage to clear to a chosen colour the VGImage previously
+returned by eglCreateImageKHR.
+Use OpenVG to draw the just drawn VGImage to the pixmap surface currently
+linked to the context.
+Call eglWaitClient() to finish the above drawing instructions synchronously.
+Destroy the original image data
+• Pass the VGImage into vgDestroyImage()
+• Pass the EGLImage into eglDestroyImageKHR()
+• Close the first RSgImage
+• Check that the pixmap surface contains expected pixel values using
+OpenVG APIs, vgReadPixels.
+Close the second RSgImage and destroy the pixmap surface
+Check for memory and handle leaks
+
+@SYMTestExpectedResults
+Pixmap surface has the expected contents in both processes (within tolerance)
+No memory or handle leaks
+*/
+TVerdict CEglTest_EGL_Image_Multi_Process_Parallel::doTestStepL()
+ {
+ SetTestStepID(_L("GRAPHICS-EGL-0161"));
+ SetTestStepName(KEGL_Image_Multi_Process_Parallel);
+ INFO_PRINTF1(_L("Enter: CEglTest_EGL_Image_Multi_Process_Parallel::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();
+ }
+
+ // launch 2 processes
+ Test_MultiProcessL(KEglTestStepDllName, 2, TestStepName());
+
+ INFO_PRINTF1(_L("Exit: CEglTest_EGL_Image_Multi_Process_Parallel::doTestStepL"));
+ RecordTestResultL();
+ CloseTMSGraphicsStep();
+ return TestStepResult();
+ }
+
+void CEglTest_EGL_Image_Multi_Process_Parallel::doProcessFunctionL(TInt aIdx)
+ {
+ INFO_PRINTF2(_L("CEglTest_EGL_Image_Multi_Process_Parallel::doProcessFunctionL, Process %d"),aIdx);
+ GetDisplayL();
+ CreateEglSessionL(aIdx);
+ iEglSess->InitializeL();
+ iEglSess->OpenSgDriverL();
+
+ // create a reference bitmap (we give index 3 for example, as there's only 1 image in this test case)
+ TDisplayMode bitmapMode = EglTestConversion::PixelFormatToDisplayMode(KDefaultSourceFormat);
+ CFbsBitmap* bitmap = iEglSess->CreateReferenceBitmapL(bitmapMode, KImageSize, 3);
+ CleanupStack::PushL(bitmap);
+
+ // Create an RSgImage
+ INFO_PRINTF2(_L("Process %d, Creating a RSgImage having the reference bitmap's content"),aIdx);
+ TSgImageInfoOpenVgImage imageInfo = TSgImageInfoOpenVgImage(KDefaultSourceFormat, KImageSize);
+ RSgImage rSgImageLocal;
+ CleanupClosePushL(rSgImageLocal);
+ ASSERT_EQUALS(rSgImageLocal.Create(imageInfo,bitmap->DataAddress(),bitmap->DataStride()), KErrNone);
+
+ INFO_PRINTF2(_L("Process %d, Creating an EGLImage from the shared RSgImage"),aIdx);
+ EGLImageKHR eglImageLocal = iEglSess->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("Process %d, Creating a Surface and a Context bound to OpenVG"),aIdx);
+ TUidPixelFormat pixelFormat = EglTestConversion::VgFormatToSgPixelFormat(KDefaultSurfaceFormat);
+ TSgImageInfoOpenVgTarget imageInfo2 = TSgImageInfoOpenVgTarget(pixelFormat, KImageSize);
+ // Create a pixmap surface matching the native image pixel format
+ iEglSess->CreatePixmapSurfaceAndMakeCurrentAndMatchL(imageInfo2,CTestEglSession::EResourceCloseSgImageEarly);
+
+ INFO_PRINTF2(_L("Process %d, Creating one VGImage from the EGLImage"),aIdx);
+ VGImage vgImageLocal = iEglSess->vgCreateImageTargetKHR((VGeglImageKHR)eglImageLocal);
+ ASSERT_VG_TRUE(vgImageLocal != VG_INVALID_HANDLE);
+ ASSERT_EGL_TRUE(iEglSess->DestroyEGLImage(iDisplay, eglImageLocal));
+
+ // Copy the source VGImage to the surface
+ vgSetPixels(0, 0, vgImageLocal, 0, 0, KImageSize.iWidth, KImageSize.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 process
+ CFbsBitmap* refBitmap = iEglSess->CreateReferenceBitmapL(bitmapMode, KImageSize, 3);
+ CleanupStack::PushL(refBitmap);
+ iEglSess->CheckVgDrawingL(KDefaultSurfaceFormat, refBitmap);
+ CleanupStack::PopAndDestroy(refBitmap);
+ INFO_PRINTF2(_L("Drawing successful, Process %d"),aIdx);
+
+ // cleanup
+ CleanAll();
+ }
+
+/**
+@SYMTestCaseID GRAPHICS-EGL-0162
+
+@SYMTestPriority 1
+
+@SYMPREQ 39
+
+@SYMREQ See SGL.GT0386.401 document
+
+@SYMTestCaseDesc
+Check if EGL Implementation allows two processes to work in parallel.
+A process can create an EGLImage from the same RSgImage that already has been linked to an EGLImage by another process.
+Both process can create a VGImage from it.
+Another process uses the VGImage as a target
+One process uses the VGImage as a source being able to see the drawing done by the other process
+
+@SYMTestActions
+Main Process: creates an RsgImage and starts Process and Process.
+Process1: Creates an egl context and a pizmap surface linked to it. Creates an EGLImage from the RsgImage previous mentioned. Creates a VGImage from the EGLImage.
+Process2: Creates an egl context and a pizmap surface linked to it. Creates an EGLImage from the RsgImage previous mentioned. Creates a VGImage from the EGLImage.
+Process1: Changes the contents of the VGImage
+--------
+Process1: Closes the VGImage and the EGLImage
+Process2: Draws the VGImage to the surface and checks if the contets match the reference bitmap plus the chages made by the first process.
+Process2: Closes the VGImage and the EGLImage
+Main Process: Closes the RsgImage
+
+@SYMTestExpectedResults
+No errors within both processes.
+The content of the pixmap surface will match the one of the reference bitmap changed by the first process.
+No memory or handle leaks.
+*/
+TVerdict CEglTest_EGL_Image_Multi_Process_Sibling_CheckContents::doTestStepL()
+ {
+ SetTestStepID(_L("GRAPHICS-EGL-0162"));
+ SetTestStepName(KEGL_Image_Multi_Process_Sibling_CheckContents);
+ INFO_PRINTF1(_L("Enter: CEglTest_EGL_Image_Multi_Process_Sibling_CheckContents::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();
+ CreateEglSessionL();
+ iEglSess->InitializeL();
+ iEglSess->OpenSgDriverL();
+
+ // create a reference bitmap (we give index 0, as there's only 1 image in this test case)
+ TDisplayMode bitmapMode = EglTestConversion::PixelFormatToDisplayMode(KDefaultSourceFormat);
+ CFbsBitmap* bitmap = iEglSess->CreateReferenceBitmapL(bitmapMode, KImageSize, 0);
+ CleanupStack::PushL(bitmap);
+
+ // Create an RSgImage
+ TSgImageInfoOpenVgImage imageInfo = TSgImageInfoOpenVgImage(KDefaultSourceFormat, KImageSize);
+#ifndef SYMBIAN_GRAPHICS_EGL_SGIMAGELITE
+ imageInfo.iShareable = ETrue;
+#endif //SYMBIAN_GRAPHICS_EGL_SGIMAGELITE
+ RSgImage sgImage;
+ CleanupClosePushL(sgImage);
+ ASSERT_EQUALS(sgImage.Create(imageInfo,bitmap->DataAddress(),bitmap->DataStride()), KErrNone);
+
+ // launch 2 processes
+ Test_MultiProcessL(KEglTestStepDllName, 2, TestStepName(), sgImage.Id());
+
+ // destroy sgImage
+ CleanupStack::PopAndDestroy(&sgImage);
+ CleanupStack::PopAndDestroy(bitmap);
+
+ // clean everything
+ CleanAll();
+ INFO_PRINTF1(_L("Exit: CEglTest_EGL_Image_Multi_Process_Sibling_CheckContents::doTestStepL"));
+ RecordTestResultL();
+ CloseTMSGraphicsStep();
+ return TestStepResult();
+ }
+
+void CEglTest_EGL_Image_Multi_Process_Sibling_CheckContents::doProcessFunctionL(TInt aIdx,const TSgDrawableId& aSgId)
+ {
+ INFO_PRINTF2(_L("CEglTest_EGL_Image_Multi_Process_Sibling_CheckContents::doProcessFunctionL, Process %d"),aIdx);
+ GetDisplayL();
+ CreateEglSessionL(aIdx);
+ iEglSess->InitializeL();
+ iEglSess->OpenSgDriverL();
+
+ RSgImage sgImageFromId;
+ CleanupClosePushL(sgImageFromId);
+ ASSERT_EQUALS(sgImageFromId.Open(aSgId),KErrNone);
+
+ INFO_PRINTF2(_L("Process %d, Creating an EGLImage from the shared RSgImage"),aIdx);
+ EGLImageKHR eglImageLocal = iEglSess->eglCreateImageKhrL(iDisplay, EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR, &sgImageFromId, KEglImageAttribsPreservedTrue);
+ ASSERT_EGL_TRUE(eglImageLocal != EGL_NO_IMAGE_KHR);
+ CleanupStack::PopAndDestroy(&sgImageFromId);
+
+ INFO_PRINTF2(_L("Process %d, Creating a Surface and a Context bound to OpenVG"),aIdx);
+ TUidPixelFormat pixelFormat = EglTestConversion::VgFormatToSgPixelFormat(KDefaultSurfaceFormat);
+ TSgImageInfoOpenVgTarget imageInfo = TSgImageInfoOpenVgTarget(pixelFormat, KImageSize);
+ // Create a pixmap surface matching the native image pixel format
+ iEglSess->CreatePixmapSurfaceAndMakeCurrentAndMatchL(imageInfo,CTestEglSession::EResourceCloseSgImageEarly);
+
+ INFO_PRINTF2(_L("Process %d, Creating one VGImage from the EGLImage"),aIdx);
+ VGImage vgImageLocal = iEglSess->vgCreateImageTargetKHR((VGeglImageKHR)eglImageLocal);
+ ASSERT_VG_TRUE(vgImageLocal != VG_INVALID_HANDLE);
+ ASSERT_EGL_TRUE(iEglSess->DestroyEGLImage(iDisplay, eglImageLocal));
+
+ if(aIdx == 0)
+ {
+ TDisplayMode bitmapMode = EglTestConversion::PixelFormatToDisplayMode(KDefaultSourceFormat);
+ CFbsBitmap* bitmap = iEglSess->CreateReferenceBitmapL(bitmapMode, KImageSize, 4);
+ // 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();
+ }
+
+ // Wait for both processes to reach this point (process 0 will have updated the VGImage)
+ Rendezvous(aIdx);
+
+ if(aIdx == 1)
+ {
+ INFO_PRINTF2(_L("Process %d, Drawing the VGImage to the current surface"),aIdx);
+ // Copy the source VGImage to the surface
+ vgSetPixels(0, 0, vgImageLocal, 0, 0, KImageSize.iWidth, KImageSize.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 process
+ TDisplayMode bitmapMode = EglTestConversion::PixelFormatToDisplayMode(KDefaultSourceFormat);
+ CFbsBitmap* refBitmap = iEglSess->CreateReferenceBitmapL(bitmapMode, KImageSize, 4);
+ CleanupStack::PushL(refBitmap);
+ iEglSess->CheckVgDrawingL(KDefaultSurfaceFormat, refBitmap);
+ CleanupStack::PopAndDestroy(refBitmap);
+ INFO_PRINTF2(_L("Process %d, Drawing successful"),aIdx);
+ }
+
+ // destroy VGImage
+ vgDestroyImage(vgImageLocal);
+ ASSERT_TRUE(vgGetError()==VG_NO_ERROR);
+
+ // cleanup
+ CleanAll();
+ }
+
+/**
+@SYMTestCaseID GRAPHICS-EGL-0350
+
+@SYMTestPriority 1
+
+@SYMPREQ 2637
+
+@SYMTestCaseDesc
+Check sharing SgImage between 2 processes where a writer process populates SgImage through VgImage and a reader process draws SgImage to window surface.
+
+@SYMTestActions
+Main Process: starts Process1 and Process2.
+Process1: Creates an RsgImage and passes RsgImage ID to process2. Creates an egl context and a pixmap surface linked to it. Creates an EGLImage from the RsgImage previous mentioned. Creates a VGImage from the EGLImage.
+Process2: Creates an RsgImage using RsgImage ID passed into it. Creates an egl context and a pixmap surface linked to it. Creates an EGLImage from the RsgImage previous mentioned. Creates a VGImage from the EGLImage.
+--------
+Process2: Draws the VGImage to the surface before Process1 changes the contents of the VGImage.
+--------
+Process1: Changes the contents of the VGImage
+--------
+Process2: Draws the VGImage to the surface after Process1 changes the contents of the VGImage and checks if the contets match the reference bitmap plus the chages made by the process1.
+Process1: Closes the VGImage, the EGLImage, the RsgImage.
+Process2: Closes the VGImage, the EGLImage, the RsgImage.
+
+@SYMTestExpectedResults
+No errors within both processes.
+The content of the pixmap surface will match the one of the reference bitmap changed by the first process.
+No memory or handle leaks.
+*/
+TVerdict CEglTest_EGL_Image_Multi_Process_VgImage_Source::doTestStepL()
+ {
+ SetTestStepID(_L("GRAPHICS-EGL-0350"));
+ SetTestStepName(KEGL_Image_Multi_Process_VgImage_Source);
+ INFO_PRINTF1(_L("Enter: CEglTest_EGL_Image_Multi_Process_VgImage_Source::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();
+ }
+
+ // launch 2 processes
+ Test_MultiProcessL(KEglTestStepDllName, 2, TestStepName());
+
+ INFO_PRINTF1(_L("Exit: CEglTest_EGL_Image_Multi_Process_VgImage_Source::doTestStepL"));
+ RecordTestResultL();
+ CloseTMSGraphicsStep();
+ return TestStepResult();
+ }
+
+void CEglTest_EGL_Image_Multi_Process_VgImage_Source::doProcessFunctionL(TInt aIdx)
+ {
+ INFO_PRINTF2(_L("CEglTest_EGL_Image_Multi_Process_VgImage_Source::doProcessFunctionL, Process %d"),aIdx);
+ GetDisplayL();
+ CreateEglSessionL(aIdx);
+ iEglSess->InitializeL();
+ iEglSess->OpenSgDriverL();
+
+ RMsgQueue<TSgDrawableId> messageQueue;
+ User::LeaveIfError(messageQueue.Open(EProcSlotMsgQueueSgId, EOwnerProcess));
+ CleanupClosePushL(messageQueue);
+
+ RSgImage rSgImageLocal;
+ if(aIdx == 0)
+ {
+ // create a reference bitmap (we give index 0, as there's only 1 image in this test case)
+ TDisplayMode bitmapMode = EglTestConversion::PixelFormatToDisplayMode(KDefaultSourceFormat);
+ CFbsBitmap* bitmap = iEglSess->CreateReferenceBitmapL(bitmapMode, KImageSize, 0);
+ CleanupStack::PushL(bitmap);
+
+ // Create an RSgImage
+ INFO_PRINTF2(_L("Process %d, Creating a RSgImage having the reference bitmap's content"),aIdx);
+ TSgImageInfoOpenVgImage imageInfo = TSgImageInfoOpenVgImage(KDefaultSourceFormat, KImageSize);
+#ifndef SYMBIAN_GRAPHICS_EGL_SGIMAGELITE
+ imageInfo.iShareable = ETrue;
+#endif
+ ASSERT_EQUALS(rSgImageLocal.Create(imageInfo,bitmap->DataAddress(),bitmap->DataStride()), KErrNone);
+ CleanupStack::PopAndDestroy(bitmap);
+
+ INFO_PRINTF2(_L("Process %d, Sending SgImage ID to other process..."), aIdx);
+ messageQueue.SendBlocking(rSgImageLocal.Id());
+ }
+ else if(aIdx == 1)
+ {
+ INFO_PRINTF2(_L("Process %d, Receiving SgImage ID from other process..."), aIdx);
+ TSgDrawableId sgImageId;
+ messageQueue.ReceiveBlocking(sgImageId);
+ ASSERT_EQUALS(rSgImageLocal.Open(sgImageId), KErrNone);
+ }
+
+ INFO_PRINTF2(_L("Process %d, Creating an EGLImage from the shared RSgImage"),aIdx);
+ CleanupClosePushL(rSgImageLocal);
+ EGLImageKHR eglImageLocal = iEglSess->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("Creating a Surface and a Context bound to OpenVG, Process %d"),aIdx);
+ TUidPixelFormat pixelFormat = EglTestConversion::VgFormatToSgPixelFormat(KDefaultSurfaceFormat);
+ TSgImageInfoOpenVgTarget imageInfo = TSgImageInfoOpenVgTarget(pixelFormat, KImageSize);
+ // Create a pixmap surface matching the native image pixel format
+ iEglSess->CreatePixmapSurfaceAndMakeCurrentAndMatchL(imageInfo,CTestEglSession::EResourceCloseSgImageEarly);
+
+ INFO_PRINTF2(_L("Process %d, Creating one VGImage from the EGLImage"),aIdx);
+ VGImage vgImageLocal = iEglSess->vgCreateImageTargetKHR((VGeglImageKHR)eglImageLocal);
+ ASSERT_VG_TRUE(vgImageLocal != VG_INVALID_HANDLE);
+ ASSERT_EGL_TRUE(iEglSess->DestroyEGLImage(iDisplay, eglImageLocal));
+
+ if(aIdx == 1)
+ {
+ INFO_PRINTF2(_L("Process %d, Drawing the VGImage to the current surface before changing contents of the VGImage"),aIdx);
+ // Copy the source VGImage to the surface
+ vgSetPixels(0, 0, vgImageLocal, 0, 0, KImageSize.iWidth, KImageSize.iHeight);
+ ASSERT_TRUE(vgGetError()==VG_NO_ERROR);
+ eglWaitClient();
+
+ // we can now compare the VgImage to the one we expect before we apply any change to it
+ TDisplayMode bitmapMode = EglTestConversion::PixelFormatToDisplayMode(KDefaultSourceFormat);
+ CFbsBitmap* refBitmap = iEglSess->CreateReferenceBitmapL(bitmapMode, KImageSize, 0);
+ CleanupStack::PushL(refBitmap);
+ iEglSess->CheckVgDrawingL(KDefaultSurfaceFormat, refBitmap);
+ CleanupStack::PopAndDestroy(refBitmap);
+ INFO_PRINTF2(_L("Process %d, Drawing successful"),aIdx);
+ }
+
+ // Wait for both processes to reach this point
+ Rendezvous(aIdx);
+
+ if(aIdx == 0)
+ {
+ INFO_PRINTF2(_L("Process %d, Changing contents of the VGImage"),aIdx);
+ TDisplayMode bitmapMode = EglTestConversion::PixelFormatToDisplayMode(KDefaultSourceFormat);
+ CFbsBitmap* bitmap = iEglSess->CreateReferenceBitmapL(bitmapMode, KImageSize, 4);
+ // 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();
+ }
+
+ // Wait for both processes to reach this point (process 0 will have updated the VGImage)
+ Rendezvous(aIdx);
+
+ if(aIdx == 1)
+ {
+ INFO_PRINTF2(_L("Drawing the VGImage to the current surface after changing contents of the VGImage, Process %d"),aIdx);
+ // Copy the source VGImage to the surface
+ vgSetPixels(0, 0, vgImageLocal, 0, 0, KImageSize.iWidth, KImageSize.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 process
+ TDisplayMode bitmapMode = EglTestConversion::PixelFormatToDisplayMode(KDefaultSourceFormat);
+ CFbsBitmap* refBitmap = iEglSess->CreateReferenceBitmapL(bitmapMode, KImageSize, 4);
+ CleanupStack::PushL(refBitmap);
+ iEglSess->CheckVgDrawingL(KDefaultSurfaceFormat, refBitmap);
+ CleanupStack::PopAndDestroy(refBitmap);
+ INFO_PRINTF2(_L("Process %d, Drawing successful"),aIdx);
+ }
+
+ vgDestroyImage(vgImageLocal);
+ ASSERT_TRUE(vgGetError() == VG_NO_ERROR);
+
+ CleanupStack::PopAndDestroy(&messageQueue);
+ CleanAll();
+ }
+
+/**
+@SYMTestCaseID GRAPHICS-EGL-0351
+
+@SYMTestPriority 1
+
+@SYMPREQ 2637
+
+@SYMTestCaseDesc
+Check when sharing SgImage between 2 processes where a writer process populates SgImage through VgImage and a reader process draws SgImage to window surface,
+process2 has reference to SgImage even after process1 loses all references to SgImage
+
+@SYMTestActions
+Main Process: starts Process1 and Process2.
+Process1: Creates an RsgImage and passes RsgImage ID to process2. Creates an egl context and a pixmap surface linked to it. Creates an EGLImage from the RsgImage previous mentioned. Creates a VGImage from the EGLImage.
+Process2: Creates an RsgImage using RsgImage ID passed into it. Creates an egl context and a pixmap surface linked to it. Creates an EGLImage from the RsgImage previous mentioned. Creates a VGImage from the EGLImage.
+Process2: Drawss the VGImage to the surface before Process1 changes the contents of the VGImage.
+--------
+Process1: Changes the contents of the VGImage
+Process1: Closes the VGImage, the EGLImage, the RsgImage.
+--------
+Process2: Draws the VGImage to the surface after Process1 changes the contents of the VGImage and checks if the contents match the reference bitmap plus the changes made by the process1.
+Process2: Closes the VGImage, the EGLImage, the RsgImage.
+
+@SYMTestExpectedResults
+No errors within both processes.
+The content of the pixmap surface will match the one of the reference bitmap changed by the process1.
+No memory or handle leaks.
+*/
+TVerdict CEglTest_EGL_Image_Multi_Process_VgImage_DrawAfterTerminate::doTestStepL()
+ {
+ SetTestStepID(_L("GRAPHICS-EGL-0351"));
+ SetTestStepName(KEGL_Image_Multi_Process_VgImage_DrawAfterTerminate);
+ INFO_PRINTF1(_L("Enter: CEglTest_EGL_Image_Multi_Process_VgImage_DrawAfterTerminate::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();
+
+ // launch 2 processes
+ Test_MultiProcessL(KEglTestStepDllName, 2, TestStepName());
+
+ INFO_PRINTF1(_L("Exit: CEglTest_EGL_Image_Multi_Process_VgImage_DrawAfterTerminate::doTestStepL"));
+ RecordTestResultL();
+ CloseTMSGraphicsStep();
+ return TestStepResult();
+ }
+
+void CEglTest_EGL_Image_Multi_Process_VgImage_DrawAfterTerminate::doProcessFunctionL(TInt aIdx)
+ {
+ INFO_PRINTF2(_L("CEglTest_EGL_Image_Multi_Process_VgImage_DrawAfterTerminate::doProcessFunctionL, Process %d"),aIdx);
+ GetDisplayL();
+ CreateEglSessionL(aIdx);
+ iEglSess->InitializeL();
+ iEglSess->OpenSgDriverL();
+
+ RMsgQueue<TSgDrawableId> messageQueue;
+ User::LeaveIfError(messageQueue.Open(EProcSlotMsgQueueSgId, EOwnerProcess));
+ CleanupClosePushL(messageQueue);
+
+ RSgImage rSgImageLocal;
+ if(aIdx == 0)
+ {
+ // create a reference bitmap (we give index 0, as there's only 1 image in this test case)
+ TDisplayMode bitmapMode = EglTestConversion::PixelFormatToDisplayMode(KDefaultSourceFormat);
+ CFbsBitmap* bitmap = iEglSess->CreateReferenceBitmapL(bitmapMode, KImageSize, 0);
+ CleanupStack::PushL(bitmap);
+
+ // Create an RSgImage
+ INFO_PRINTF2(_L("Process %d, Creating a RSgImage having the reference bitmap's content"),aIdx);
+ TSgImageInfoOpenVgImage imageInfo = TSgImageInfoOpenVgImage(KDefaultSourceFormat, KImageSize);
+#ifndef SYMBIAN_GRAPHICS_EGL_SGIMAGELITE
+ imageInfo.iShareable = ETrue;
+#endif
+ ASSERT_EQUALS(rSgImageLocal.Create(imageInfo,bitmap->DataAddress(),bitmap->DataStride()), KErrNone);
+ CleanupStack::PopAndDestroy(bitmap);
+
+ INFO_PRINTF2(_L("Process %d, Sending SgImage ID to other process..."), aIdx);
+ messageQueue.SendBlocking(rSgImageLocal.Id());
+ }
+ else if(aIdx == 1)
+ {
+ INFO_PRINTF2(_L("Process %d: Receiving SgImage ID from other process..."), aIdx);
+ TSgDrawableId sgImageId;
+ messageQueue.ReceiveBlocking(sgImageId);
+ ASSERT_EQUALS(rSgImageLocal.Open(sgImageId),KErrNone);
+ }
+
+ INFO_PRINTF2(_L("Process %d, Creating an EGLImage from the shared RSgImage"),aIdx);
+ CleanupClosePushL(rSgImageLocal);
+ EGLImageKHR eglImageLocal = iEglSess->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("Creating a Surface and a Context bound to OpenVG, Process %d"),aIdx);
+ TUidPixelFormat pixelFormat = EglTestConversion::VgFormatToSgPixelFormat(KDefaultSurfaceFormat);
+ TSgImageInfoOpenVgTarget imageInfo = TSgImageInfoOpenVgTarget(pixelFormat, KImageSize);
+ // Create a pixmap surface matching the native image pixel format
+ iEglSess->CreatePixmapSurfaceAndMakeCurrentAndMatchL(imageInfo,CTestEglSession::EResourceCloseSgImageEarly);
+
+ INFO_PRINTF2(_L("Process %d, Creating one VGImage from the EGLImage"),aIdx);
+ VGImage vgImageLocal = iEglSess->vgCreateImageTargetKHR((VGeglImageKHR)eglImageLocal);
+ ASSERT_VG_TRUE(vgImageLocal != VG_INVALID_HANDLE);
+ ASSERT_EGL_TRUE(iEglSess->DestroyEGLImage(iDisplay, eglImageLocal));
+
+ if(aIdx == 1)
+ {
+ INFO_PRINTF2(_L("Process %d, Drawing the VGImage to the current surface before changing contents of the VGImage"),aIdx);
+ // Copy the source VGImage to the surface
+ vgSetPixels(0, 0, vgImageLocal, 0, 0, KImageSize.iWidth, KImageSize.iHeight);
+ ASSERT_TRUE(vgGetError()==VG_NO_ERROR);
+ eglWaitClient();
+
+
+ // we can now compare the VgImage to the one we expect before we apply any change to it
+ TDisplayMode bitmapMode = EglTestConversion::PixelFormatToDisplayMode(KDefaultSourceFormat);
+ CFbsBitmap* refBitmap = iEglSess->CreateReferenceBitmapL(bitmapMode, KImageSize, 0);
+ CleanupStack::PushL(refBitmap);
+ iEglSess->CheckVgDrawingL(KDefaultSurfaceFormat, refBitmap);
+ CleanupStack::PopAndDestroy(refBitmap);
+ INFO_PRINTF2(_L("Process %d, Drawing successful"),aIdx);
+ }
+
+ // Wait for both processes to reach this point
+ Rendezvous(aIdx);
+
+ if(aIdx == 0)
+ {
+ INFO_PRINTF2(_L("Process %d, Changing contents of the VGImage"),aIdx);
+ TDisplayMode bitmapMode = EglTestConversion::PixelFormatToDisplayMode(KDefaultSourceFormat);
+ CFbsBitmap* bitmap = iEglSess->CreateReferenceBitmapL(bitmapMode, KImageSize, 2);
+ // 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();
+
+ vgDestroyImage(vgImageLocal);
+ ASSERT_TRUE(vgGetError() == VG_NO_ERROR);
+ CleanupStack::PopAndDestroy(&messageQueue);
+ CleanAll();
+ }
+
+ // Wait for both processes to reach this point
+ Rendezvous(aIdx);
+
+ if(aIdx == 1)
+ {
+ INFO_PRINTF2(_L("Drawing the VGImage to the current surface after changing contents of the VGImage, Process %d"),aIdx);
+ // Copy the source VGImage to the surface
+ vgSetPixels(0, 0, vgImageLocal, 0, 0, KImageSize.iWidth, KImageSize.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 process
+ TDisplayMode bitmapMode = EglTestConversion::PixelFormatToDisplayMode(KDefaultSourceFormat);
+ CFbsBitmap* refBitmap = iEglSess->CreateReferenceBitmapL(bitmapMode, KImageSize, 2);
+ CleanupStack::PushL(refBitmap);
+ iEglSess->CheckVgDrawingL(KDefaultSurfaceFormat, refBitmap);
+ CleanupStack::PopAndDestroy(refBitmap);
+ INFO_PRINTF2(_L("Process %d, Drawing successful"),aIdx);
+
+ vgDestroyImage(vgImageLocal);
+ ASSERT_TRUE(vgGetError() == VG_NO_ERROR);
+
+ CleanupStack::PopAndDestroy(&messageQueue);
+ CleanAll();
+ }
+ }
+
+/**
+@SYMTestCaseID GRAPHICS-EGL-0406
+
+@SYMTestPriority 1
+
+@SYMPREQ PREQ2637
+
+@SYMTestCaseDesc
+To ensure that RSgImage with uploaded data can be shared across processes.
+To ensure that reference counting of RSgImage works correctly.
+
+@SYMTestActions
+From the main process:
+- Create M SgImage(s) with the flag ESgUsageBitOpenVgImage. The size are all the same.
+ We are running through all the possible configurations, with the values assumed being:
+• EUidPixelFormatRGB_565
+• EUidPixelFormatXRGB_8888
+• EUidPixelFormatARGB_8888 (source only)
+• EUidPixelFormatARGB_8888_PRE
+• EUidPixelFormatA_8 (source only)
+- Note that when using EUidPixelFormatA_8 as a source, the reference bitmap display mode used is EGray256,
+ This is to enable using the reference bitmap as an alpha mask.
+- Spawn N client processes. During the process launching, pass to each process single drawable ID from the SgImages.
+ In order to define which SgImage needs to be passed to the particular process, there will be following
+ formula applied: J = P Mod (M), where J is the sequence number of the image, P is the particular process number.
+From processes 1 to N:
+- Open SgImage by using TSgDrawableId, obtained from the SgImage which was passed from the process A.
+- Using EGL extension, create EGLImage specifying as EGLClientBuffer SgImage which was created on
+ previous step, EGL_NATIVE_PIXMAP_KHR as a target and EGL_IMAGE_PRESERVED_KHR as an attribute
+- Using VG extension, create VG image based on EGLImage from the previous step.
+- Close Sg and EGL images
+- Create second SgImage with the same size and pixel format as first SgImage and usage flag is set to ESgUsageBitOpenVgSurface.
+- Create off-screen pixmap surface with underlining second SgImage and make it current for the drawing context.
+- Draw VGImage to the off-screen surface (note that when using EUidPixelFormatA_8 as a source, the
+ reference bitmap is used as an alpha mask).
+- Draw VGImage to the off-screen surface.
+- Retrieve surface data (see vgReadPixels() API)
+
+@SYMTestExpectedResults
+Creation of all drawable resources have been completed without errors.
+Image data obtained in client processes 1-N matches to the data which have been uploaded to the SgImages buffer from
+process A. Reference counting works correctly and keeps VG image alive although bound Sg and EGL images have been destroyed.
+When all resources are closed, resource count maintained by RSgDriver extension is zero in all processes.
+*/
+TVerdict CEglTest_EGL_Image_Multi_Process_FontServer_Upfront::doTestStepL()
+ {
+ SetTestStepID(_L("GRAPHICS-EGL-0406"));
+ SetTestStepName(KEGL_Image_Multi_Process_FontServer_Upfront);
+ INFO_PRINTF1(_L("CEglTest_EGL_Image_Multi_Process_FontServer_Upfront::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();
+ }
+
+ CEglTestCommonIniSettings* iniParser = CEglTestCommonIniSettings::NewL();
+ CleanupStack::PushL(iniParser);
+
+ TInt numPixmapSgSurfaceFormats = iniParser->GetNumberOfFormats(KSectionPixmapSgSurfaceFormats);
+ TInt numImageSourceFormats = iniParser->GetNumberOfFormats(KSectionImageSourceFormats);
+ if(!numImageSourceFormats && !numPixmapSgSurfaceFormats)
+ {
+ ERR_PRINTF1(_L("No formats to iterate through"));
+ User::Leave(KErrArgument);
+ }
+ for(TUint j=0; j < numPixmapSgSurfaceFormats; j++)
+ {
+ iSurfaceFormat = iniParser->GetVgFormat(KSectionPixmapSgSurfaceFormats,j);
+ for(TUint i=0; i < numImageSourceFormats; i++)
+ {
+ iSourceFormat = iniParser->GetPixelFormat(KSectionImageSourceFormats,i);
+ if (iSourceFormat == EUidPixelFormatARGB_8888 && (iSurfaceFormat == VG_sARGB_8888_PRE || iSurfaceFormat == VG_sARGB_8888))
+ {
+ // Don't perform the test for this particular format combination
+ // Causes issues converting pixel values from non-pre to pre
+ continue;
+ }
+#ifndef SYMBIAN_GRAPHICS_EGL_SGIMAGELITE
+ // A_8 related tests are only performed for SgImage-Lite
+ if (iSourceFormat == EUidPixelFormatA_8)
+ continue;
+#endif
+ doTestPartialStepL();
+ }
+ }
+
+ CleanupStack::PopAndDestroy(iniParser);
+ RecordTestResultL();
+ CloseTMSGraphicsStep();
+ return TestStepResult();
+ }
+
+TVerdict CEglTest_EGL_Image_Multi_Process_FontServer_Upfront::doTestPartialStepL()
+ {
+ INFO_PRINTF1(_L("CEglTest_EGL_Image_Multi_Process_FontServer_Upfront::doTestPartialStepL"));
+ PrintUsedPixelConfiguration();
+
+ // Create display object
+ ASSERT_TRUE(iDisplay == EGL_NO_DISPLAY);
+ GetDisplayL();
+ CreateEglSessionL();
+ iEglSess->InitializeL();
+ iEglSess->OpenSgDriverL();
+
+ // list to maintain TSgDrawableId
+ RArray<TSgDrawableId> sgIdList;
+ CleanupClosePushL(sgIdList);
+ RSgImage sgImages[KNumImages];
+
+ INFO_PRINTF2(_L("MAIN PROCESS: Creating %d RSgImage(s)..."), KNumImages);
+ for (TInt i=0; i<KNumImages; i++)
+ {
+ TDisplayMode bitmapMode = EglTestConversion::PixelFormatToDisplayMode(iSourceFormat);
+ CFbsBitmap* bitmap = iEglSess->CreateReferenceBitmapL(bitmapMode, KImageSize, i);
+ CleanupStack::PushL(bitmap);
+
+ TSgImageInfoOpenVgImage imageInfo = TSgImageInfoOpenVgImage(iSourceFormat, KImageSize);
+#ifndef SYMBIAN_GRAPHICS_EGL_SGIMAGELITE
+ imageInfo.iShareable = ETrue;
+#endif
+ ASSERT_EQUALS(sgImages[i].Create(imageInfo, bitmap->DataAddress(), bitmap->DataStride()), KErrNone);
+ CleanupClosePushL(sgImages[i]);
+ ASSERT_EQUALS(sgIdList.Insert(sgImages[i].Id(),i), KErrNone);
+ }
+
+ INFO_PRINTF2(_L("MAIN PROCESS: About to launch %d processes..."), KNumProcesses);
+ Test_MultiProcessL(KEglTestStepDllName, KNumProcesses, TestStepName(), sgIdList); //the function will guarantee that all images will be opened before it returns
+ CleanupStack::PopAndDestroy(2 * KNumImages + 1, &sgIdList); // KNumImages SgImages, KNumImages bitmaps, sgIdList
+ INFO_PRINTF2(_L("MAIN PROCESS: All %d launched processes have completed!"), KNumProcesses);
+
+ CleanAll();
+ INFO_PRINTF1(_L("End of CEglTest_EGL_Image_Multi_Process_FontServer_Upfront::doTestPartialStepL"));
+ return TestStepResult();
+ }
+
+void CEglTest_EGL_Image_Multi_Process_FontServer_Upfront::doProcessFunctionL(TInt aIdx,const TSgDrawableId& aSgId)
+ {
+ INFO_PRINTF2(_L("CEglTest_EGL_Image_Multi_Process_FontServer_Upfront::doProcessFunctionL, Process %d"),aIdx);
+ GetDisplayL();
+ CreateEglSessionL(aIdx);
+ iEglSess->InitializeL();
+ iEglSess->OpenSgDriverL();
+
+ //Retrieve source formats for the launched process from the process parameters.
+ User::LeaveIfError(User::GetTIntParameter(EProcSlotSourceFormat, reinterpret_cast<TInt&>(iSourceFormat)));
+ User::LeaveIfError(User::GetTIntParameter(EProcSlotSurfaceFormat, reinterpret_cast<TInt&>(iSurfaceFormat)));
+
+ RSgImage sgImageFromId;
+ CleanupClosePushL(sgImageFromId);
+ ASSERT_EQUALS(sgImageFromId.Open(aSgId), KErrNone);
+
+ INFO_PRINTF2(_L("Process %d, Creating an EGLImage from the shared RSgImage"),aIdx);
+ EGLImageKHR eglImage = iEglSess->eglCreateImageKhrL(iDisplay, EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR, &sgImageFromId, KEglImageAttribsPreservedTrue);
+ ASSERT_EGL_TRUE(eglImage != EGL_NO_IMAGE_KHR);
+ CleanupStack::PopAndDestroy(&sgImageFromId);
+
+ INFO_PRINTF2(_L("Process %d, Creating a Surface and a Context bound to OpenVG"),aIdx);
+ TUidPixelFormat pixelFormat = EglTestConversion::VgFormatToSgPixelFormat(iSurfaceFormat);
+ TSgImageInfoOpenVgTarget imageInfo = TSgImageInfoOpenVgTarget(pixelFormat, KImageSize);
+ // Create a pixmap surface matching the native image pixel format
+ iEglSess->CreatePixmapSurfaceAndMakeCurrentAndMatchL(imageInfo,CTestEglSession::EResourceCloseSgImageEarly);
+
+ INFO_PRINTF2(_L("Process %d, Creating one VGImage from the EGLImage"),aIdx);
+ VGImage vgImage = iEglSess->vgCreateImageTargetKHR((VGeglImageKHR)eglImage);
+ ASSERT_VG_TRUE(vgImage != VG_INVALID_HANDLE);
+ ASSERT_EGL_TRUE(iEglSess->DestroyEGLImage(iDisplay, eglImage));
+
+ // At this point we draw the VGImage created from the SgImage to the current surface.
+ // # if the source is a A_8, the VGImage acts as a mask and the target surface must contain
+ // as a result the pen colour set above blended with the mask
+ // # otherwise, drawing the VGImage is just a simple copy via vgSetPixels (no blending required)
+ INFO_PRINTF1(_L("Copying the VGImage to the surface"));
+ if (iSourceFormat == EUidPixelFormatA_8)
+ {
+ // clear surface background
+ VGfloat bgColor[] = {0.0, 0.0, 0.0, 1.0}; // opaque black
+ vgSetfv(VG_CLEAR_COLOR, 4, bgColor);
+ vgClear(0, 0, KImageSize.iWidth, KImageSize.iHeight);
+ ASSERT_EGL_TRUE(vgGetError() == VG_NO_ERROR);
+
+ // fill paint
+ VGPaint fillPaint = vgCreatePaint();
+ vgSetPaint(fillPaint, VG_FILL_PATH);
+ ASSERT_EGL_TRUE(vgGetError() == VG_NO_ERROR);
+ vgSetParameteri(fillPaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
+ VGuint fillColor = 0x008000ff; // opaque dark green
+ vgSetColor(fillPaint, fillColor);
+ ASSERT_EGL_TRUE(vgGetError() == VG_NO_ERROR);
+
+ vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_STENCIL);
+ vgSeti(VG_BLEND_MODE, VG_BLEND_SRC_OVER);
+ vgDrawImage(vgImage);
+ ASSERT_EGL_TRUE(vgGetError() == VG_NO_ERROR);
+ eglWaitClient();
+ vgDestroyPaint(fillPaint);
+ ASSERT_EGL_TRUE(vgGetError() == VG_NO_ERROR);
+ }
+ else
+ {
+ vgSetPixels(0, 0, vgImage, 0, 0, KImageSize.iWidth, KImageSize.iHeight);
+ ASSERT_TRUE(vgGetError()==VG_NO_ERROR);
+ eglWaitClient();
+ }
+
+ // Check that the surface contains the expected pixels
+ // # if the source is a A_8, to compare the surface with a reference bitmap, the following is needed:
+ // a) a reference bitmap needs to be cleared to black (same colour as the surface was cleared to)
+ // b) a Pen bitmap, that we clear to dark green (same colour as the fillPaint used to draw to the surface)
+ // c) a mask bitmap, which is the reference bitmap used to create the SgImage
+ // # otherwise, the surface must contain the same pixels as the bitmap used to create the SgImage
+ if (iSourceFormat == EUidPixelFormatA_8)
+ {
+ TDisplayMode maskMode = EglTestConversion::PixelFormatToDisplayMode(iSourceFormat);
+ CFbsBitmap* mask = iEglSess->CreateReferenceBitmapL(maskMode, KImageSize, ImageIndexFromProcessId(aIdx, KNumImages));
+ CleanupStack::PushL(mask);
+
+ // we need a reference bitmap with the same pixel format as the target surface
+ TUidPixelFormat format = EglTestConversion::VgFormatToSgPixelFormat(iSurfaceFormat);
+ TDisplayMode refbitmapMode = EglTestConversion::PixelFormatToDisplayMode(format);
+
+ CFbsBitmap* refBitmap = iEglSess->CreateReferenceMaskedBitmapL(refbitmapMode, KRgbDarkGreen, mask);
+ CleanupStack::PushL(refBitmap);
+
+ // compare the obtained reference bitmap with the surface drawn
+ iEglSess->CheckVgDrawingL(iSurfaceFormat, refBitmap);
+ CleanupStack::PopAndDestroy(2, mask); //mask, refBitmap
+ }
+ else
+ {
+ TDisplayMode bitmapMode = EglTestConversion::PixelFormatToDisplayMode(iSourceFormat);
+ CFbsBitmap* refBitmap = iEglSess->CreateReferenceBitmapL(bitmapMode, KImageSize, ImageIndexFromProcessId(aIdx, KNumImages));
+ CleanupStack::PushL(refBitmap);
+ iEglSess->CheckVgDrawingL(iSurfaceFormat, refBitmap);
+ CleanupStack::PopAndDestroy(refBitmap);
+ }
+ INFO_PRINTF2(_L("Process %d, VG drawing successfully completed and checked"),aIdx);
+
+ // destroy VGImage
+ vgDestroyImage(vgImage);
+ ASSERT_TRUE(vgGetError()==VG_NO_ERROR);
+
+ // cleanup
+ CleanAll();
+ }
+
+
+/**
+@SYMTestCaseID GRAPHICS-EGL-0410
+
+@SYMTestPriority 1
+
+@SYMPREQ PREQ2637
+
+@SYMTestCaseDesc
+To ensure that RSgImage with uploaded data can be shared across processes.
+To ensure that reference counting of RSgImage works correctly
+
+@SYMTestActions
+From the main process:
+- Create M SgImage(s) with the flag ESgUsageBitOpenVgImage. The size are all the same.
+ We are running through all the possible target configurations, with the values assumed being:
+• EUidPixelFormatRGB_565
+• EUidPixelFormatXRGB_8888
+• EUidPixelFormatARGB_8888_PRE
+- Using EGL extension, create M EGLImage(s), specifying as EGLClientBuffer SgImage(s) which were created on
+ first step and EGL_NATIVE_PIXMAP_KHR as a target
+- Using VG extension, create VG images based on EGLImage(s) from the previous step
+- Close Sg and EGL Images
+- Populate data in VGImages (see vgImageSubData(..) API), there will be different data uploaded for each VGImage
+- Spawn N client processes. During the process launching, pass to each process single drawable ID from the SgImages.
+ In order to define which SgImage(s) needs to be passed to the particular processes, there will be following
+ formula applied: J = P Mod (M), where J is the sequence number of the image, P is the particular process number.
+From processes 1 to N:
+- Open SgImage by using TSgDrawableId, obtained from the SgImage which was passed from the process A.
+- Using EGL extension, create EGLImage specifying as EGLClientBuffer SgImage which was created on previous step,
+ EGL_NATIVE_PIXMAP_KHR as a target and EGL_IMAGE_PRESERVED_KHR as an attribute
+- Using VG extension, create VG image based on EGLImage from the previous step.
+- Close Sg and EGL images
+- Create second SgImage with the same size and pixel format as first SgImage and usage flag is set to ESgUsageBitOpenVgSurface.
+- Create off-screen pixmap surface with underlining second SgImage and make it current for the drawing context.
+- Draw VGImage to the off-screen surface.
+- Retrieve surface data (see vgReadPixels() API)
+
+@SYMTestExpectedResults
+Creation of all drawable resources have been completed without errors.
+Image data obtained in client processes 1-N matches to the data which have been uploaded to the SgImages buffer from
+process A. Reference counting works correctly and keep VG image alive although bound Sg and EGL images have been closed.
+When all resources are closed, resource count maintained by RSgDriver extension is zero in all processes.
+*/
+TVerdict CEglTest_EGL_Image_Multi_Process_FontServer_Deferred::doTestStepL()
+ {
+ SetTestStepID(_L("GRAPHICS-EGL-0410"));
+ SetTestStepName(KEGL_Image_Multi_Process_FontServer_Deferred);
+ INFO_PRINTF1(_L("CEglTest_EGL_Image_Multi_Process_FontServer_Deferred::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();
+ }
+
+ CEglTestCommonIniSettings* iniParser = CEglTestCommonIniSettings::NewL();
+ CleanupStack::PushL(iniParser);
+
+ TInt numPixmapSgSurfaceFormats = iniParser->GetNumberOfFormats(KSectionPixmapSgSurfaceFormats);
+ if(!numPixmapSgSurfaceFormats)
+ {
+ ERR_PRINTF1(_L("No formats to iterate through"));
+ User::Leave(KErrArgument);
+ }
+ for(TUint j=0; j < numPixmapSgSurfaceFormats; j++)
+ {
+ iSurfaceFormat = iniParser->GetVgFormat(KSectionPixmapSgSurfaceFormats,j);
+ iSourceFormat = EglTestConversion::VgFormatToSgPixelFormat(iSurfaceFormat);
+#ifndef SYMBIAN_GRAPHICS_EGL_SGIMAGELITE
+ // A_8 related tests are only performed for SgImage-Lite
+ if (iSourceFormat == EUidPixelFormatA_8)
+ continue;
+#endif
+ doTestPartialStepL();
+ }
+
+ CleanupStack::PopAndDestroy(iniParser);
+ RecordTestResultL();
+ CloseTMSGraphicsStep();
+ return TestStepResult();
+ }
+
+TVerdict CEglTest_EGL_Image_Multi_Process_FontServer_Deferred::doTestPartialStepL()
+ {
+ INFO_PRINTF1(_L("CEglTest_EGL_Image_Multi_Process_FontServer_Deferred::doTestPartialStepL"));
+ PrintUsedPixelConfiguration();
+
+ // Create display object
+ ASSERT_TRUE(iDisplay == EGL_NO_DISPLAY);
+ GetDisplayL();
+ CreateEglSessionL();
+ iEglSess->InitializeL();
+ iEglSess->OpenSgDriverL();
+
+ // Create RSgImage's attributes
+ TSgImageInfoTest imageInfo = TSgImageInfoTest(iSourceFormat, KImageSize);
+#ifdef SYMBIAN_GRAPHICS_EGL_SGIMAGELITE
+ imageInfo.iUsage = ESgUsageBitOpenVgImage | ESgUsageBitOpenVgSurface;
+#else
+ imageInfo.iUsage = ESgUsageOpenVgImage | ESgUsageOpenVgTarget;
+ imageInfo.iShareable = ETrue;
+#endif //SYMBIAN_GRAPHICS_EGL_SGIMAGELITE
+ // Create a pixmap surface matching the given pixel format
+ iEglSess->CreatePixmapSurfaceAndMakeCurrentAndMatchL(imageInfo,CTestEglSession::EResourceCloseSgImageEarly);
+
+ // list to maintain TSgDrawableId
+ RArray<TSgDrawableId> sgIdList;
+ CleanupClosePushL(sgIdList);
+ RSgImage sgImages[KNumImages];
+
+ INFO_PRINTF2(_L("MAIN PROCESS: Creating %d RSgImage(s)..."), KNumImages);
+ for (TInt i=0; i<KNumImages; i++)
+ {
+ ASSERT_EQUALS(sgImages[i].Create(imageInfo, NULL, NULL), KErrNone);
+ CleanupClosePushL(sgImages[i]);
+ ASSERT_EQUALS(sgIdList.Insert(sgImages[i].Id(),i), KErrNone);
+
+ EGLImageKHR eglImage = iEglSess->eglCreateImageKhrL(iDisplay, EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR, &sgImages[i], KEglImageAttribsPreservedTrue);
+ ASSERT_EGL_TRUE(eglImage != EGL_NO_IMAGE_KHR);
+
+ VGImage vgImage = iEglSess->vgCreateImageTargetKHR((VGeglImageKHR)eglImage);
+ ASSERT_VG_TRUE(vgImage != VG_INVALID_HANDLE);
+ ASSERT_EGL_TRUE(iEglSess->DestroyEGLImage(iDisplay, eglImage));
+
+ TDisplayMode bitmapMode = EglTestConversion::PixelFormatToDisplayMode(iSourceFormat);
+ CFbsBitmap* bitmap = iEglSess->CreateReferenceBitmapL(bitmapMode, KImageSize, i);
+ // 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(vgImage, address, -stride, iSurfaceFormat, 0,0, bitmapSize.iWidth, bitmapSize.iHeight);
+ delete bitmap;
+ bitmap = NULL;
+ ASSERT_TRUE(vgGetError()==VG_NO_ERROR);
+ eglWaitClient();
+ }
+
+ INFO_PRINTF2(_L("MAIN PROCESS: About to launch %d processes..."), KNumProcesses);
+ Test_MultiProcessL(KEglTestStepDllName, KNumProcesses, TestStepName(), sgIdList);
+ CleanupStack::PopAndDestroy(KNumImages + 1, &sgIdList); //KNumImages SgImages, sgIdList
+ INFO_PRINTF2(_L("MAIN PROCESS: All %d launched processes have completed!"), KNumProcesses);
+
+ CleanAll();
+ INFO_PRINTF1(_L("End of CEglTest_EGL_Image_Multi_Process_FontServer_Deferred::doTestPartialStepL"));
+ return TestStepResult();
+ }
+
+void CEglTest_EGL_Image_Multi_Process_FontServer_Deferred::doProcessFunctionL(TInt aIdx,const TSgDrawableId& aSgId)
+ {
+ INFO_PRINTF2(_L("CEglTest_EGL_Image_Multi_Process_FontServer_Deferred::doProcessFunctionL, Process %d"),aIdx);
+ GetDisplayL();
+ CreateEglSessionL(aIdx);
+ iEglSess->InitializeL();
+ iEglSess->OpenSgDriverL();
+
+ //Retrieve source formats for the launched process from the process parameters.
+ User::LeaveIfError(User::GetTIntParameter(EProcSlotSourceFormat, reinterpret_cast<TInt&>(iSourceFormat)));
+ User::LeaveIfError(User::GetTIntParameter(EProcSlotSurfaceFormat, reinterpret_cast<TInt&>(iSurfaceFormat)));
+
+ RSgImage sgImageFromId;
+ CleanupClosePushL(sgImageFromId);
+ ASSERT_EQUALS(sgImageFromId.Open(aSgId), KErrNone);
+
+ INFO_PRINTF2(_L("Process %d, Creating an EGLImage from the shared RSgImage"),aIdx);
+ EGLImageKHR eglImage = iEglSess->eglCreateImageKhrL(iDisplay, EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR, &sgImageFromId, KEglImageAttribsPreservedTrue);
+ ASSERT_EGL_TRUE(eglImage != EGL_NO_IMAGE_KHR);
+ CleanupStack::PopAndDestroy(&sgImageFromId);
+
+ INFO_PRINTF2(_L("Process %d, Creating a Surface and a Context bound to OpenVG"),aIdx);
+ TUidPixelFormat pixelFormat = EglTestConversion::VgFormatToSgPixelFormat(iSurfaceFormat);
+ TSgImageInfoOpenVgTarget imageInfo = TSgImageInfoOpenVgTarget(pixelFormat, KImageSize);
+ // Create a pixmap surface matching the native image pixel format
+ iEglSess->CreatePixmapSurfaceAndMakeCurrentAndMatchL(imageInfo,CTestEglSession::EResourceCloseSgImageEarly);
+
+ INFO_PRINTF2(_L("Process %d, Creating one VGImage from the EGLImage"),aIdx);
+ VGImage vgImage = iEglSess->vgCreateImageTargetKHR((VGeglImageKHR)eglImage);
+ ASSERT_VG_TRUE(vgImage != VG_INVALID_HANDLE);
+ ASSERT_EGL_TRUE(iEglSess->DestroyEGLImage(iDisplay, eglImage));
+
+ // At this point we draw the VGImage created from the SgImage to the current surface.
+ // # if the source is a A_8, the VGImage acts as a mask and the target surface must contain
+ // as a result the pen colour set above blended with the mask
+ // # otherwise, drawing the VGImage is just a simple copy via vgSetPixels (no blending required)
+ INFO_PRINTF1(_L("Copying the VGImage to the surface"));
+ if (iSourceFormat == EUidPixelFormatA_8)
+ {
+ // clear surface background
+ VGfloat bgColor[] = {0.0, 0.0, 0.0, 1.0}; // opaque black
+ vgSetfv(VG_CLEAR_COLOR, 4, bgColor);
+ vgClear(0, 0, KImageSize.iWidth, KImageSize.iHeight);
+ ASSERT_EGL_TRUE(vgGetError() == VG_NO_ERROR);
+
+ // fill paint
+ VGPaint fillPaint = vgCreatePaint();
+ vgSetPaint(fillPaint, VG_FILL_PATH);
+ ASSERT_EGL_TRUE(vgGetError() == VG_NO_ERROR);
+ vgSetParameteri(fillPaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
+ VGuint fillColor = 0x008000ff; // opaque dark green
+ vgSetColor(fillPaint, fillColor);
+ ASSERT_EGL_TRUE(vgGetError() == VG_NO_ERROR);
+
+ vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_STENCIL);
+ vgSeti(VG_BLEND_MODE, VG_BLEND_SRC_OVER);
+ vgDrawImage(vgImage);
+ ASSERT_EGL_TRUE(vgGetError() == VG_NO_ERROR);
+ eglWaitClient();
+ vgDestroyPaint(fillPaint);
+ ASSERT_EGL_TRUE(vgGetError() == VG_NO_ERROR);
+ }
+ else
+ {
+ vgSetPixels(0, 0, vgImage, 0, 0, KImageSize.iWidth, KImageSize.iHeight);
+ ASSERT_TRUE(vgGetError()==VG_NO_ERROR);
+ eglWaitClient();
+ }
+
+ // Check that the surface contains the expected pixels
+ // # if the source is a A_8, to compare the surface with a reference bitmap, the following is needed:
+ // a) a reference bitmap needs to be cleared to black (same colour as the surface was cleared to)
+ // b) a Pen bitmap, that we clear to dark green (same colour as the fillPaint used to draw to the surface)
+ // c) a mask bitmap, which is the reference bitmap used to create the SgImage
+ // # otherwise, the surface must contain the same pixels as the bitmap used to create the SgImage
+ if (iSourceFormat == EUidPixelFormatA_8)
+ {
+ TDisplayMode maskMode = EglTestConversion::PixelFormatToDisplayMode(iSourceFormat);
+ CFbsBitmap* mask = iEglSess->CreateReferenceBitmapL(maskMode, KImageSize, ImageIndexFromProcessId(aIdx, KNumImages));
+ CleanupStack::PushL(mask);
+
+ // we need a reference bitmap with the same pixel format as the target surface
+ TUidPixelFormat format = EglTestConversion::VgFormatToSgPixelFormat(iSurfaceFormat);
+ TDisplayMode refbitmapMode = EglTestConversion::PixelFormatToDisplayMode(format);
+
+ CFbsBitmap* refBitmap = iEglSess->CreateReferenceMaskedBitmapL(refbitmapMode, KRgbDarkGreen, mask);
+ CleanupStack::PushL(refBitmap);
+
+ // compare the obtained reference bitmap with the surface drawn
+ iEglSess->CheckVgDrawingL(iSurfaceFormat, refBitmap);
+ CleanupStack::PopAndDestroy(2, mask); //mask, refBitmap
+ }
+ else
+ {
+ TDisplayMode bitmapMode = EglTestConversion::PixelFormatToDisplayMode(iSourceFormat);
+ CFbsBitmap* refBitmap = iEglSess->CreateReferenceBitmapL(bitmapMode, KImageSize, ImageIndexFromProcessId(aIdx, KNumImages));
+ CleanupStack::PushL(refBitmap);
+ iEglSess->CheckVgDrawingL(iSurfaceFormat, refBitmap);
+ CleanupStack::PopAndDestroy(refBitmap);
+ }
+ INFO_PRINTF2(_L("Process %d, VG drawing successfully completed and checked"),aIdx);
+
+ // destroy VGImage
+ vgDestroyImage(vgImage);
+ ASSERT_TRUE(vgGetError()==VG_NO_ERROR);
+
+ // cleanup
+ CleanAll();
+ }
+
+
+/**
+@SYMTestCaseID GRAPHICS-EGL-0415
+
+@SYMTestPriority 1
+
+@SYMPREQ PREQ2637
+
+@SYMTestCaseDesc
+To ensure that SgImage with the data rendered as Pixmap surface can be shared across processes.
+To ensure that reference counting of SgImage works correctly
+
+@SYMTestActions
+From the main process:
+- Create M SgImages with the flags ESgUsageBitOpenVgImage & ESgUsageBitOpenVgSurface. The size are all the same.
+ We are running through all the possible target configurations, with the values assumed being:
+• EUidPixelFormatRGB_565
+• EUidPixelFormatXRGB_8888
+• EUidPixelFormatARGB_8888_PRE
+- Choose egl config, supplying as a native pixmap type in attribute (flag EGL_MATCH_NATIVE_PIXMAP) the SgImages which
+ were created on the previous step. The EGL_RENDERABLE_TYPE of the config attributes must include EGL_OPENVG_BIT.
+- Create M pixmap surfaces based on SgImages from the first step. The surface is created with EGL_ALPHA_FORMAT_PRE
+ flag supplied in attribute list if the underlining SgImage was of type ESgPixelFormatARGB_8888_PRE.
+- In iteration from 1 to M perform three following steps:
+ 1. Make the pixmap surface current (see eglMakeCurrent(.) API)
+ 2. Draw something to the current surface, for instance, clear the whole area with color and then draw a
+ few graphics primitives. The drawing needs to be unique for each surface and complicated enough to
+ ensure that bit comparison will reveal any mismatch
+ 3. Make no surface current
+- Close all pixmap surfaces
+- Spawn N client processes. During the process launching, pass to each process single drawable ID from the SgImages.
+ In order to define which SgImage(s) needs to be passed to the particular processes, there will be following
+ formula applied: J = P Mod (M), where J is the sequence number of the image, P is the particular process number.
+From processes 1 to N:
+- Open SgImage by TSgDrawableId obtained from the SgImage which was passed from the process A.
+- Using EGL extension, create EGLImage specifying as EGLClientBuffer SgImage which was opened on the previous
+ step, EGL_NATIVE_PIXMAP_KHR as a target and EGL_IMAGE_PRESERVED_KHR as an attribute
+- Using VG extension, create VG image based on EGLImage from the previous step.
+- Close both Sg and EGL images
+- Create second SgImage with the same size and pixel format as first SgImage and usage flag is set to ESgUsageBitOpenVgSurface.
+- Create off-screen pixmap surface with underlining second SgImage and make it current for the drawing context.
+- Draw VGImage to the off-screen surface.
+- Retrieve surface data (see vgReadPixels() API)
+
+@SYMTestExpectedResults
+Creation of all drawable resources has been completed without errors.
+On return eglChooseConfig() must return EGL_OPENVG_BIT in config attribute list (actual attributes should
+be retrieved via call to eglGetConfigAttrib()).
+Image data obtained in client processes 1 - N matches to the pixmap surface which was drawn in the process A.
+Reference counting works correctly and keep VG image alive although bound Sg and EGL images have been closed.
+When all resources are closed, resource count maintained by RSgDriver extension is zero in all processes.
+*/
+TVerdict CEglTest_EGL_Image_Multi_Process_ThemeServer::doTestStepL()
+ {
+ SetTestStepID(_L("GRAPHICS-EGL-0415"));
+ SetTestStepName(KEGL_Image_Multi_Process_ThemeServer);
+ INFO_PRINTF1(_L("CEglTest_EGL_Image_Multi_Process_ThemeServer::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();
+ }
+
+ CEglTestCommonIniSettings* iniParser = CEglTestCommonIniSettings::NewL();
+ CleanupStack::PushL(iniParser);
+
+ TInt numPixmapSgSurfaceFormats = iniParser->GetNumberOfFormats(KSectionPixmapSgSurfaceFormats);
+ if(!numPixmapSgSurfaceFormats)
+ {
+ ERR_PRINTF1(_L("No formats to iterate through"));
+ User::Leave(KErrArgument);
+ }
+ for(TUint j=0; j < numPixmapSgSurfaceFormats; j++)
+ {
+ iSurfaceFormat = iniParser->GetVgFormat(KSectionPixmapSgSurfaceFormats,j);
+ iSourceFormat = EglTestConversion::VgFormatToSgPixelFormat(iSurfaceFormat);
+#ifndef SYMBIAN_GRAPHICS_EGL_SGIMAGELITE
+ // A_8 related tests are only performed for SgImage-Lite
+ if (iSourceFormat == EUidPixelFormatA_8)
+ continue;
+#endif
+ doTestPartialStepL();
+ }
+
+ CleanupStack::PopAndDestroy(iniParser);
+ RecordTestResultL();
+ CloseTMSGraphicsStep();
+ return TestStepResult();
+ }
+
+TVerdict CEglTest_EGL_Image_Multi_Process_ThemeServer::doTestPartialStepL()
+ {
+ INFO_PRINTF1(_L("CEglTest_EGL_Image_Multi_Process_ThemeServer::doTestPartialStepL"));
+ PrintUsedPixelConfiguration();
+
+ // Create display object
+ ASSERT_TRUE(iDisplay == EGL_NO_DISPLAY);
+ GetDisplayL();
+ CreateEglSessionL();
+ iEglSess->InitializeL();
+ iEglSess->OpenSgDriverL();
+
+ // list to maintain TSgDrawableId
+ RArray<TSgDrawableId> sgIdList;
+ CleanupClosePushL(sgIdList);
+ RSgImage sgImages[KNumImages];
+
+ INFO_PRINTF2(_L("MAIN PROCESS: Creating %d RSgImage(s)..."), KNumImages);
+ for (TInt i=0; i<KNumImages; i++)
+ {
+ // Create RSgImage's attributes
+ TSgImageInfoTest imageInfo = TSgImageInfoTest(iSourceFormat, KImageSize);
+#ifdef SYMBIAN_GRAPHICS_EGL_SGIMAGELITE
+ imageInfo.iUsage = ESgUsageBitOpenVgImage | ESgUsageBitOpenVgSurface;
+#else
+ imageInfo.iUsage = ESgUsageOpenVgImage | ESgUsageOpenVgTarget;
+ imageInfo.iShareable = ETrue;
+#endif //SYMBIAN_GRAPHICS_EGL_SGIMAGELITE
+
+ ASSERT_EQUALS(sgImages[i].Create(imageInfo, NULL, NULL), KErrNone);
+ CleanupClosePushL(sgImages[i]);
+ ASSERT_EQUALS(sgIdList.Insert(sgImages[i].Id(),i), KErrNone);
+
+ INFO_PRINTF1(_L("Calling sequence - eglBindAPI(EGL_OPENVG_API) - eglCreatePixmapSurface - eglCreateContext - eglMakeCurrent"));
+ ASSERT_EGL_TRUE(eglBindAPI(EGL_OPENVG_API));
+
+ const EGLint KAttrib_list_image_pre[] = { EGL_MATCH_NATIVE_PIXMAP, reinterpret_cast<EGLint>(&sgImages[i]),
+ EGL_RENDERABLE_TYPE, EGL_OPENVG_BIT,
+ EGL_SURFACE_TYPE, EGL_PIXMAP_BIT | EGL_VG_ALPHA_FORMAT_PRE_BIT,
+ EGL_NONE };
+ const EGLint KAttrib_list_image_nonpre[] = {EGL_MATCH_NATIVE_PIXMAP, reinterpret_cast<EGLint>(&sgImages[i]),
+ EGL_RENDERABLE_TYPE, EGL_OPENVG_BIT,
+ EGL_SURFACE_TYPE, EGL_PIXMAP_BIT,
+ EGL_NONE };
+ EGLConfig currentConfig;
+ EGLint numconfigs =0;
+ EGLSurface surface = EGL_NO_SURFACE;
+ if (iSourceFormat == EUidPixelFormatARGB_8888_PRE)
+ {
+ ASSERT_EGL_TRUE(eglChooseConfig(iDisplay,KAttrib_list_image_pre,¤tConfig,1,&numconfigs))
+ ASSERT_EGL_TRUE(numconfigs==1);
+ surface = eglCreatePixmapSurface(iDisplay, currentConfig,&sgImages[i], KPixmapAttribsVgAlphaFormatPre);
+ }
+ else
+ {
+ ASSERT_EGL_TRUE(eglChooseConfig(iDisplay,KAttrib_list_image_nonpre,¤tConfig,1,&numconfigs))
+ ASSERT_EGL_TRUE(numconfigs==1);
+ surface = eglCreatePixmapSurface(iDisplay, currentConfig,&sgImages[i], KPixmapAttribsVgAlphaFormatNonPre);
+ }
+ ASSERT_EGL_TRUE(surface != EGL_NO_SURFACE);
+ EGLContext context = eglCreateContext(iDisplay, currentConfig, EGL_NO_CONTEXT, NULL);
+ ASSERT_EGL_TRUE(context != EGL_NO_CONTEXT);
+ ASSERT_EGL_TRUE(eglMakeCurrent(iDisplay, surface, surface, context));
+
+ //Drawing to the current surface (and hence to the RSgImage) to test that the contents are preserved
+ TDisplayMode bitmapMode = EglTestConversion::PixelFormatToDisplayMode(iSourceFormat);
+ CFbsBitmap* bitmap = iEglSess->CreateReferenceBitmapL(bitmapMode, KImageSize, i);
+ // 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;
+ vgWritePixels(address, -stride, iSurfaceFormat, 0,0, bitmapSize.iWidth, bitmapSize.iHeight);
+ delete bitmap;
+ bitmap = NULL;
+ ASSERT_TRUE(vgGetError()==VG_NO_ERROR);
+
+ // Make no surface current and destroy surface
+ ASSERT_EGL_TRUE(eglDestroySurface(iDisplay, surface));
+ ASSERT_EGL_TRUE(eglMakeCurrent(iDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
+ }
+
+ INFO_PRINTF2(_L("MAIN PROCESS: About to launch %d processes..."), KNumProcesses);
+ Test_MultiProcessL(KEglTestStepDllName, KNumProcesses, TestStepName(), sgIdList);
+ CleanupStack::PopAndDestroy(KNumImages + 1, &sgIdList); //KNumImages SgImages, sgIdList
+ INFO_PRINTF2(_L("MAIN PROCESS: All %d launched processes have completed!"), KNumProcesses);
+
+ CleanAll();
+ INFO_PRINTF1(_L("End of CEglTest_EGL_Image_Multi_Process_ThemeServer::doTestPartialStepL"));
+ return TestStepResult();
+ }
+
+void CEglTest_EGL_Image_Multi_Process_ThemeServer::doProcessFunctionL(TInt aIdx,const TSgDrawableId& aSgId)
+ {
+ INFO_PRINTF2(_L("CEglTest_EGL_Image_Multi_Process_ThemeServer::doProcessFunctionL, Process %d"),aIdx);
+ GetDisplayL();
+ CreateEglSessionL(aIdx);
+ iEglSess->InitializeL();
+ iEglSess->OpenSgDriverL();
+
+ //Retrieve source formats for the launched process from the process parameters.
+ User::LeaveIfError(User::GetTIntParameter(EProcSlotSourceFormat, reinterpret_cast<TInt&>(iSourceFormat)));
+ User::LeaveIfError(User::GetTIntParameter(EProcSlotSurfaceFormat, reinterpret_cast<TInt&>(iSurfaceFormat)));
+
+ RSgImage sgImageFromId;
+ CleanupClosePushL(sgImageFromId);
+ ASSERT_EQUALS(sgImageFromId.Open(aSgId), KErrNone);
+
+ INFO_PRINTF2(_L("Process %d, Creating an EGLImage from the shared RSgImage"),aIdx);
+ EGLImageKHR eglImage = iEglSess->eglCreateImageKhrL(iDisplay, EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR, &sgImageFromId, KEglImageAttribsPreservedTrue);
+ ASSERT_EGL_TRUE(eglImage != EGL_NO_IMAGE_KHR);
+ CleanupStack::PopAndDestroy(&sgImageFromId);
+
+ INFO_PRINTF2(_L("Process %d, Creating a Surface and a Context bound to OpenVG"),aIdx);
+ TUidPixelFormat pixelFormat = EglTestConversion::VgFormatToSgPixelFormat(KDefaultSurfaceFormat);
+ TSgImageInfoOpenVgTarget imageInfo = TSgImageInfoOpenVgTarget(pixelFormat, KImageSize);
+ // Create a pixmap surface matching the native image pixel format
+ iEglSess->CreatePixmapSurfaceAndMakeCurrentAndMatchL(imageInfo,CTestEglSession::EResourceCloseSgImageEarly);
+
+ INFO_PRINTF2(_L("Process %d, Creating one VGImage from the EGLImage"),aIdx);
+ VGImage vgImage = iEglSess->vgCreateImageTargetKHR((VGeglImageKHR)eglImage);
+ ASSERT_VG_TRUE(vgImage != VG_INVALID_HANDLE);
+ ASSERT_EGL_TRUE(iEglSess->DestroyEGLImage(iDisplay, eglImage));
+
+ // At this point we draw the VGImage created from the SgImage to the current surface.
+ // # if the source is a A_8, the VGImage acts as a mask and the target surface must contain
+ // as a result the pen colour set above blended with the mask
+ // # otherwise, drawing the VGImage is just a simple copy via vgSetPixels (no blending required)
+ INFO_PRINTF1(_L("Copying the VGImage to the surface"));
+ if (iSourceFormat == EUidPixelFormatA_8)
+ {
+ // clear surface background
+ VGfloat bgColor[] = {0.0, 0.0, 0.0, 1.0}; // opaque black
+ vgSetfv(VG_CLEAR_COLOR, 4, bgColor);
+ vgClear(0, 0, KImageSize.iWidth, KImageSize.iHeight);
+ ASSERT_EGL_TRUE(vgGetError() == VG_NO_ERROR);
+
+ // fill paint
+ VGPaint fillPaint = vgCreatePaint();
+ vgSetPaint(fillPaint, VG_FILL_PATH);
+ ASSERT_EGL_TRUE(vgGetError() == VG_NO_ERROR);
+ vgSetParameteri(fillPaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
+ VGuint fillColor = 0x008000ff; // opaque dark green
+ vgSetColor(fillPaint, fillColor);
+ ASSERT_EGL_TRUE(vgGetError() == VG_NO_ERROR);
+
+ vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_STENCIL);
+ vgSeti(VG_BLEND_MODE, VG_BLEND_SRC_OVER);
+ vgDrawImage(vgImage);
+ ASSERT_EGL_TRUE(vgGetError() == VG_NO_ERROR);
+ eglWaitClient();
+ vgDestroyPaint(fillPaint);
+ ASSERT_EGL_TRUE(vgGetError() == VG_NO_ERROR);
+ }
+ else
+ {
+ vgSetPixels(0, 0, vgImage, 0, 0, KImageSize.iWidth, KImageSize.iHeight);
+ ASSERT_TRUE(vgGetError()==VG_NO_ERROR);
+ eglWaitClient();
+ }
+
+ // Check that the surface contains the expected pixels
+ // # if the source is a A_8, to compare the surface with a reference bitmap, the following is needed:
+ // a) a reference bitmap needs to be cleared to black (same colour as the surface was cleared to)
+ // b) a Pen bitmap, that we clear to dark green (same colour as the fillPaint used to draw to the surface)
+ // c) a mask bitmap, which is the reference bitmap used to create the SgImage
+ // # otherwise, the surface must contain the same pixels as the bitmap used to create the SgImage
+ if (iSourceFormat == EUidPixelFormatA_8)
+ {
+ TDisplayMode maskMode = EglTestConversion::PixelFormatToDisplayMode(iSourceFormat);
+ CFbsBitmap* mask = iEglSess->CreateReferenceBitmapL(maskMode, KImageSize, ImageIndexFromProcessId(aIdx, KNumImages));
+ CleanupStack::PushL(mask);
+
+ // we need a reference bitmap with the same pixel format as the target surface
+ TUidPixelFormat format = EglTestConversion::VgFormatToSgPixelFormat(iSurfaceFormat);
+ TDisplayMode refbitmapMode = EglTestConversion::PixelFormatToDisplayMode(format);
+
+ CFbsBitmap* refBitmap = iEglSess->CreateReferenceMaskedBitmapL(refbitmapMode, KRgbDarkGreen, mask);
+ CleanupStack::PushL(refBitmap);
+
+ // compare the obtained reference bitmap with the surface drawn
+ iEglSess->CheckVgDrawingL(iSurfaceFormat, refBitmap);
+ CleanupStack::PopAndDestroy(2, mask); //mask, refBitmap
+ }
+ else
+ {
+ TDisplayMode bitmapMode = EglTestConversion::PixelFormatToDisplayMode(iSourceFormat);
+ CFbsBitmap* refBitmap = iEglSess->CreateReferenceBitmapL(bitmapMode, KImageSize, ImageIndexFromProcessId(aIdx, KNumImages));
+ CleanupStack::PushL(refBitmap);
+ iEglSess->CheckVgDrawingL(iSurfaceFormat, refBitmap);
+ CleanupStack::PopAndDestroy(refBitmap);
+ }
+ INFO_PRINTF2(_L("Process %d, VG drawing successfully completed and checked"),aIdx);
+
+ // destroy VGImage
+ vgDestroyImage(vgImage);
+ ASSERT_TRUE(vgGetError()==VG_NO_ERROR);
+
+ // cleanup
+ CleanAll();
+ }
+
+
+/**
+@SYMTestCaseID GRAPHICS-EGL-0428
+
+@SYMTestPriority 1
+
+@SYMPREQ 2637
+
+@SYMTestCaseDesc
+Functional test - Killing the RSgImage creating process
+
+@SYMTestPurpose
+To verify correct operation of RSgImage sharing across processes when the creating process is killed
+
+@SYMTestActions
+Run two processes that independently perform the actions detailed below.
+* From Process A
+ Open the RSgDriver
+ Create an RSgImage
+ Signal (by semaphore or otherwise) to process A, passing the drawable ID to it
+
+* From Process B:
+ Open the RSgDriver
+ Using the drawable ID, open the RSgImage
+ Create an EGLImage from the RSgImage
+ Create a VGImage from the EGLImage
+ Close the RSgImage
+ Close the EGLImage
+ Create an off-screen surface
+
+* From Process A:
+ Unexpectedly terminate process A without performing any explicit clean-up
+
+* From Process B:
+ Wait for Process A to be killed
+ Populate the VGImage with data
+ Copy the VGImage to the off-screen surface
+ Close the off-screen surface
+ Close the VGImage
+ Close the RSgDriver
+
+@SYMTestExpectedResults
+Process B should be able to populate the VGImage with data and copy it to the off-screen surface.
+All allocated image memory should be freed
+*/
+TVerdict CEglTest_EGL_Image_Multi_Process_VgImage_ProcessTerminate::doTestStepL()
+ {
+ SetTestStepID(_L("GRAPHICS-EGL-0428"));
+ SetTestStepName(KEGL_Image_Multi_Process_VgImage_ProcessTerminate);
+ INFO_PRINTF1(_L("Enter: CEglTest_EGL_Image_Multi_Process_VgImage_ProcessTerminate::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();
+
+ // launch 2 processes
+ Test_MultiProcessL(KEglTestStepDllName, 2, TestStepName());
+
+ INFO_PRINTF1(_L("Exit: CEglTest_EGL_Image_Multi_Process_VgImage_ProcessTerminate::doTestStepL"));
+ RecordTestResultL();
+ CloseTMSGraphicsStep();
+ return TestStepResult();
+ }
+
+void CEglTest_EGL_Image_Multi_Process_VgImage_ProcessTerminate::doProcessFunctionL(TInt aIdx)
+ {
+ INFO_PRINTF2(_L("CEglTest_EGL_Image_Multi_Process_VgImage_ProcessTerminate::doProcessFunctionL, Process %d"),aIdx);
+ GetDisplayL();
+ CreateEglSessionL(aIdx);
+ iEglSess->InitializeL();
+ iEglSess->OpenSgDriverL();
+
+ //Retrieve source formats for the launched process from the process parameters.
+ User::LeaveIfError(User::GetTIntParameter(EProcSlotSourceFormat, reinterpret_cast<TInt&>(iSourceFormat)));
+ User::LeaveIfError(User::GetTIntParameter(EProcSlotSurfaceFormat, reinterpret_cast<TInt&>(iSurfaceFormat)));
+
+ //create the queue to send/receive SgImage ID between processes
+ RMsgQueue<TSgDrawableId> messageQueueSgId;
+ User::LeaveIfError(messageQueueSgId.Open(EProcSlotMsgQueueSgId, EOwnerProcess));
+ CleanupClosePushL(messageQueueSgId);
+
+ //create the queue to send/receive Process ID between processes
+ RMsgQueue<TProcessId> messageQueueProcId;
+ User::LeaveIfError(messageQueueProcId.Open(EProcSlotMsgQueueProcId, EOwnerProcess));
+ CleanupClosePushL(messageQueueProcId);
+
+ RProcess process;
+ CleanupClosePushL(process);
+ TRequestStatus status;
+
+ RSgImage rSgImageLocal;
+ EGLImageKHR eglImageLocal = EGL_NO_IMAGE_KHR;
+ VGImage vgImageLocal = VG_INVALID_HANDLE;
+ if(aIdx == 0)
+ {
+ // Create an RSgImage
+ INFO_PRINTF2(_L("Process %d, Creating a RSgImage"),aIdx);
+ TSgImageInfoOpenVgImage imageInfo = TSgImageInfoOpenVgImage(iSourceFormat, KImageSize);
+#ifndef SYMBIAN_GRAPHICS_EGL_SGIMAGELITE
+ imageInfo.iShareable = ETrue;
+ imageInfo.iCpuAccess = ESgCpuAccessReadWrite;
+#endif
+ ASSERT_EQUALS(rSgImageLocal.Create(imageInfo, NULL, NULL), KErrNone);
+
+ INFO_PRINTF2(_L("Process %d, Sending SgImage ID to other process..."), aIdx);
+ messageQueueSgId.SendBlocking(rSgImageLocal.Id());
+
+ // Sending Process ID to other process... so that the other process can identify when this one dies.
+ messageQueueProcId.SendBlocking(RProcess().Id());
+ }
+ else if(aIdx == 1)
+ {
+ INFO_PRINTF2(_L("Process %d: Receiving SgImage ID from other process..."), aIdx);
+ TSgDrawableId sgImageId;
+ messageQueueSgId.ReceiveBlocking(sgImageId);
+ ASSERT_EQUALS(rSgImageLocal.Open(sgImageId),KErrNone);
+
+ // Also receiving RProcess ID from other process to be able to identify when it dies
+ TProcessId procId;
+ messageQueueProcId.ReceiveBlocking(procId);
+ process.Open(procId);
+ process.Logon(status);
+
+ INFO_PRINTF2(_L("Process %d, Creating an EGLImage from the shared RSgImage"),aIdx);
+ CleanupClosePushL(rSgImageLocal);
+ eglImageLocal = iEglSess->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("Creating a Surface and a Context bound to OpenVG, Process %d"),aIdx);
+ TUidPixelFormat pixelFormat = EglTestConversion::VgFormatToSgPixelFormat(iSurfaceFormat);
+ TSgImageInfoOpenVgTarget imageInfo = TSgImageInfoOpenVgTarget(pixelFormat, KImageSize);
+ // Create a pixmap surface matching the native image pixel format
+ iEglSess->CreatePixmapSurfaceAndMakeCurrentAndMatchL(imageInfo,CTestEglSession::EResourceCloseSgImageEarly);
+
+ INFO_PRINTF2(_L("Process %d, Creating one VGImage from the EGLImage"),aIdx);
+ vgImageLocal = iEglSess->vgCreateImageTargetKHR((VGeglImageKHR)eglImageLocal);
+ ASSERT_VG_TRUE(vgImageLocal != VG_INVALID_HANDLE);
+ ASSERT_EGL_TRUE(iEglSess->DestroyEGLImage(iDisplay, eglImageLocal));
+ }
+
+ // Wait for both processes to reach this point
+ Rendezvous(aIdx);
+
+ if(aIdx == 0)
+ {
+ // simulate this process being killed
+ // note that we terminate with reason=0 (otherwise the egl test framework would think it's an error)
+ INFO_PRINTF2(_L("Process %d, Simulate the process is being killed!"),aIdx);
+ RProcess().Terminate(KErrNone);
+
+ // this line is unreachable
+ ASSERT(0);
+ }
+ else if(aIdx == 1)
+ {
+ // first wait for the other process to finish
+ User::WaitForRequest(status);
+ ASSERT_EQUALS(status.Int(), KErrNone);
+
+ INFO_PRINTF2(_L("Process %d, Populate contents of the VGImage"),aIdx);
+ TDisplayMode bitmapMode = EglTestConversion::PixelFormatToDisplayMode(iSourceFormat);
+ CFbsBitmap* bitmap = iEglSess->CreateReferenceBitmapL(bitmapMode, KImageSize, 3);
+ CleanupStack::PushL(bitmap);
+ // 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, iSurfaceFormat, 0,0, bitmapSize.iWidth, bitmapSize.iHeight);
+ ASSERT_TRUE(vgGetError()==VG_NO_ERROR);
+ eglWaitClient();
+
+ INFO_PRINTF2(_L("Process %d, Drawing the VGImage to the current surface before changing contents of the VGImage"),aIdx);
+ // Copy the source VGImage to the surface
+ vgSetPixels(0, 0, vgImageLocal, 0, 0, KImageSize.iWidth, KImageSize.iHeight);
+ ASSERT_TRUE(vgGetError()==VG_NO_ERROR);
+ eglWaitClient();
+
+ // we can now compare the VgImage to the one we expect
+ iEglSess->CheckVgDrawingL(iSurfaceFormat, bitmap);
+ CleanupStack::PopAndDestroy(bitmap);
+ INFO_PRINTF2(_L("Process %d, Drawing successful"),aIdx);
+
+ // cleanup
+ vgDestroyImage(vgImageLocal);
+ ASSERT_TRUE(vgGetError() == VG_NO_ERROR);
+ }
+
+ //cleanup and finish
+ CleanupStack::PopAndDestroy(3, &messageQueueSgId); //messageQueueSgId, messageQueueProcId, process
+ CleanAll();
+ }
+
+
+/**
+@SYMTestCaseID GRAPHICS-EGL-0430
+
+@SYMTestPriority 1
+
+@SYMPREQ 2637
+
+@SYMTestCaseDesc
+Functional test - Killing the RSgImage creating process
+
+@SYMTestPurpose
+To verify correct operation of RSgImage sharing across processes when the creating process is killed
+
+@SYMTestActions
+Run two processes that independently perform the actions detailed below.
+* From Process A
+ Open the RSgDriver
+ Create an RSgImage
+ Signal (by semaphore or otherwise) to process B, passing the drawable ID to it
+
+* From Process B:
+ Open the RSgDriver
+ Using the drawable ID, open the RSgImage
+ Close the RSgImage
+ Re-open the RSgImage
+
+* From Process A:
+ Unexpectedly terminate process A without performing any explicit clean-up
+
+* From Process B:
+ Wait for Process A to be killed:
+ Create an EGLImage from the RSgImage
+ Create a VGImage from the EGLImage
+ Close the RSgImage
+ Close the EGLImage
+ Create an off-screen surface
+ Populate the VGImage with data
+ Draw VGImage to the off-screen surface
+ Destroy the off-screen surface
+ Close the VGImage
+ Close the RSgDriver
+ Exit
+
+@SYMTestExpectedResults
+Process B should be able to populate the VGImage with data and copy it to the off-screen surface
+All allocated image memory should be freed
+*/
+TVerdict CEglTest_EGL_Image_Multi_Process_VgImage_ProcessTerminate2::doTestStepL()
+ {
+ SetTestStepID(_L("GRAPHICS-EGL-0430"));
+ SetTestStepName(KEGL_Image_Multi_Process_VgImage_ProcessTerminate2);
+ INFO_PRINTF1(_L("Enter: CEglTest_EGL_Image_Multi_Process_VgImage_ProcessTerminate2::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();
+
+ // launch 2 processes
+ Test_MultiProcessL(KEglTestStepDllName, 2, TestStepName());
+
+ INFO_PRINTF1(_L("Exit: CEglTest_EGL_Image_Multi_Process_VgImage_ProcessTerminate2::doTestStepL"));
+ RecordTestResultL();
+ CloseTMSGraphicsStep();
+ return TestStepResult();
+ }
+
+void CEglTest_EGL_Image_Multi_Process_VgImage_ProcessTerminate2::doProcessFunctionL(TInt aIdx)
+ {
+ INFO_PRINTF2(_L("CEglTest_EGL_Image_Multi_Process_VgImage_ProcessTerminate2::doProcessFunctionL, Process %d"),aIdx);
+ GetDisplayL();
+ CreateEglSessionL(aIdx);
+ iEglSess->InitializeL();
+ iEglSess->OpenSgDriverL();
+
+ //Retrieve source formats for the launched process from the process parameters.
+ User::LeaveIfError(User::GetTIntParameter(EProcSlotSourceFormat, reinterpret_cast<TInt&>(iSourceFormat)));
+ User::LeaveIfError(User::GetTIntParameter(EProcSlotSurfaceFormat, reinterpret_cast<TInt&>(iSurfaceFormat)));
+
+ //create the queue to send/receive SgImage ID between processes
+ RMsgQueue<TSgDrawableId> messageQueueSgId;
+ User::LeaveIfError(messageQueueSgId.Open(EProcSlotMsgQueueSgId, EOwnerProcess));
+ CleanupClosePushL(messageQueueSgId);
+
+ //create the queue to send/receive Process ID between processes
+ RMsgQueue<TProcessId> messageQueueProcId;
+ User::LeaveIfError(messageQueueProcId.Open(EProcSlotMsgQueueProcId, EOwnerProcess));
+ CleanupClosePushL(messageQueueProcId);
+
+ RProcess process;
+ CleanupClosePushL(process);
+ TRequestStatus status;
+
+ RSgImage rSgImageLocal;
+ if(aIdx == 0)
+ {
+ // Create an RSgImage
+ INFO_PRINTF2(_L("Process %d, Creating a RSgImage"),aIdx);
+ TSgImageInfoOpenVgImage imageInfo = TSgImageInfoOpenVgImage(iSourceFormat, KImageSize);
+#ifndef SYMBIAN_GRAPHICS_EGL_SGIMAGELITE
+ imageInfo.iShareable = ETrue;
+ imageInfo.iCpuAccess = ESgCpuAccessReadWrite;
+#endif
+ ASSERT_EQUALS(rSgImageLocal.Create(imageInfo,NULL, NULL), KErrNone);
+
+ INFO_PRINTF2(_L("Process %d, Sending SgImage ID to other process..."), aIdx);
+ messageQueueSgId.SendBlocking(rSgImageLocal.Id());
+
+ // Sending Process ID to other process... so that the other process can identify when this one dies.
+ messageQueueProcId.SendBlocking(RProcess().Id());
+ }
+ else if(aIdx == 1)
+ {
+ INFO_PRINTF2(_L("Process %d: Receiving SgImage ID from other process..."), aIdx);
+ TSgDrawableId sgImageId;
+ messageQueueSgId.ReceiveBlocking(sgImageId);
+ ASSERT_EQUALS(rSgImageLocal.Open(sgImageId),KErrNone);
+
+ // Also receiving RProcess ID from other process to be able to identify when it dies
+ TProcessId procId;
+ messageQueueProcId.ReceiveBlocking(procId);
+ process.Open(procId);
+ process.Logon(status);
+
+ INFO_PRINTF2(_L("Process %d: Closing and Opening SgImage again..."), aIdx);
+ rSgImageLocal.Close();
+ ASSERT_EQUALS(rSgImageLocal.Open(sgImageId),KErrNone);
+ }
+
+ // Wait for both processes to reach this point
+ Rendezvous(aIdx);
+
+ if(aIdx == 0)
+ {
+ // simulate this process being killed
+ // note that we terminate with reason=0 (otherwise the egl test framework would think it's an error)
+ INFO_PRINTF2(_L("Process %d, Simulate the process is being killed!"),aIdx);
+ RProcess().Terminate(KErrNone);
+
+ // this line is unreachable
+ ASSERT(0);
+ }
+ else if(aIdx == 1)
+ {
+ // first wait for the other process to finish
+ User::WaitForRequest(status);
+ ASSERT_EQUALS(status.Int(), KErrNone);
+
+ INFO_PRINTF2(_L("Process %d, Creating an EGLImage from the shared RSgImage"),aIdx);
+ CleanupClosePushL(rSgImageLocal);
+ EGLImageKHR eglImageLocal = iEglSess->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("Creating a Surface and a Context bound to OpenVG, Process %d"),aIdx);
+ TUidPixelFormat pixelFormat = EglTestConversion::VgFormatToSgPixelFormat(iSurfaceFormat);
+ TSgImageInfoOpenVgTarget imageInfo = TSgImageInfoOpenVgTarget(pixelFormat, KImageSize);
+ // Create a pixmap surface matching the native image pixel format
+ iEglSess->CreatePixmapSurfaceAndMakeCurrentAndMatchL(imageInfo,CTestEglSession::EResourceCloseSgImageEarly);
+
+ INFO_PRINTF2(_L("Process %d, Creating one VGImage from the EGLImage"),aIdx);
+ VGImage vgImageLocal = iEglSess->vgCreateImageTargetKHR((VGeglImageKHR)eglImageLocal);
+ ASSERT_VG_TRUE(vgImageLocal != VG_INVALID_HANDLE);
+ ASSERT_EGL_TRUE(iEglSess->DestroyEGLImage(iDisplay, eglImageLocal));
+
+ INFO_PRINTF2(_L("Process %d, Populate contents of the VGImage"),aIdx);
+ TDisplayMode bitmapMode = EglTestConversion::PixelFormatToDisplayMode(iSourceFormat);
+ CFbsBitmap* bitmap = iEglSess->CreateReferenceBitmapL(bitmapMode, KImageSize, 3);
+ CleanupStack::PushL(bitmap);
+ // 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, iSurfaceFormat, 0,0, bitmapSize.iWidth, bitmapSize.iHeight);
+ ASSERT_TRUE(vgGetError()==VG_NO_ERROR);
+ eglWaitClient();
+
+ INFO_PRINTF2(_L("Process %d, Drawing the VGImage to the current surface before changing contents of the VGImage"),aIdx);
+ // Copy the source VGImage to the surface
+ vgSetPixels(0, 0, vgImageLocal, 0, 0, KImageSize.iWidth, KImageSize.iHeight);
+ ASSERT_TRUE(vgGetError()==VG_NO_ERROR);
+ eglWaitClient();
+
+ // we can now compare the VgImage to the one we expect
+ iEglSess->CheckVgDrawingL(iSurfaceFormat, bitmap);
+ CleanupStack::PopAndDestroy(bitmap);
+ INFO_PRINTF2(_L("Process %d, Drawing successful"),aIdx);
+
+ // cleanup
+ vgDestroyImage(vgImageLocal);
+ ASSERT_TRUE(vgGetError() == VG_NO_ERROR);
+ }
+
+ //cleanup and finish
+ CleanupStack::PopAndDestroy(3, &messageQueueSgId); //messageQueueSgId, messageQueueProcId, process
+ CleanAll();
+ }
+
+
+/**
+@SYMTestCaseID GRAPHICS-EGL-0429
+
+@SYMTestPriority 1
+
+@SYMPREQ 2637
+
+@SYMTestCaseDesc
+Functional test - Killing the RSgImage creating process
+
+@SYMTestPurpose
+To verify correct operation of RSgImage sharing across processes when the creating process is killed
+
+@SYMTestActions
+Run two processes that independently perform the actions detailed below.
+* From Process A:
+ Open the RSgDriver
+ Create an RSgImage
+ Signal (by semaphore or otherwise) to process B, passing the drawable ID to it
+
+* From Process B:
+ Open the RSgDriver
+
+* From Process A:
+ Unexpectedly terminate process A without performing any explicit clean-up
+
+* From Process B:
+ Wait for Process A to be killed:
+ Using the drawable ID, attempt to open the RSgImage
+ Close the RSgDriver
+ Exit
+
+@SYMTestExpectedResults
+Process B should be unable to open the RSgImage and the call to Open() should return error code KErrNotFound.
+All allocated image memory should be freed
+*/
+TVerdict CEglTest_EGL_Image_Multi_Process_VgImage_ProcessTerminateNegative::doTestStepL()
+ {
+ SetTestStepID(_L("GRAPHICS-EGL-0429"));
+ SetTestStepName(KEGL_Image_Multi_Process_VgImage_ProcessTerminateNegative);
+ INFO_PRINTF1(_L("Enter: CEglTest_EGL_Image_Multi_Process_VgImage_ProcessTerminateNegative::doTestStepL"));
+
+ TBool ret = CheckForExtensionL(KEGL_RSgimage);
+ if(!ret)
+ {
+ // The extension is not supported
+ RecordTestResultL();
+ CloseTMSGraphicsStep();
+ return TestStepResult();
+ }
+
+ // This test is performed for default pixel format
+ PrintUsedPixelConfiguration();
+
+ // launch 2 processes
+ Test_MultiProcessL(KEglTestStepDllName, 2, TestStepName());
+
+ INFO_PRINTF1(_L("Exit: CEglTest_EGL_Image_Multi_Process_VgImage_ProcessTerminateNegative::doTestStepL"));
+ RecordTestResultL();
+ CloseTMSGraphicsStep();
+ return TestStepResult();
+ }
+
+void CEglTest_EGL_Image_Multi_Process_VgImage_ProcessTerminateNegative::doProcessFunctionL(TInt aIdx)
+ {
+ INFO_PRINTF2(_L("CEglTest_EGL_Image_Multi_Process_VgImage_ProcessTerminateNegative::doProcessFunctionL, Process %d"),aIdx);
+ GetDisplayL();
+ CreateEglSessionL(aIdx);
+ iEglSess->InitializeL();
+ iEglSess->OpenSgDriverL();
+
+ //Retrieve source formats for the launched process from the process parameters.
+ User::LeaveIfError(User::GetTIntParameter(EProcSlotSourceFormat, reinterpret_cast<TInt&>(iSourceFormat)));
+ User::LeaveIfError(User::GetTIntParameter(EProcSlotSurfaceFormat, reinterpret_cast<TInt&>(iSurfaceFormat)));
+
+ //create the queue to send/receive SgImage ID between processes
+ RMsgQueue<TSgDrawableId> messageQueueSgId;
+ User::LeaveIfError(messageQueueSgId.Open(EProcSlotMsgQueueSgId, EOwnerProcess));
+ CleanupClosePushL(messageQueueSgId);
+
+ //create the queue to send/receive Process ID between processes
+ RMsgQueue<TProcessId> messageQueueProcId;
+ User::LeaveIfError(messageQueueProcId.Open(EProcSlotMsgQueueProcId, EOwnerProcess));
+ CleanupClosePushL(messageQueueProcId);
+
+ RProcess process;
+ CleanupClosePushL(process);
+ TRequestStatus status;
+
+ RSgImage rSgImageLocal;
+ TSgDrawableId sgImageId;
+ if(aIdx == 0)
+ {
+ // Create an RSgImage
+ INFO_PRINTF2(_L("Process %d, Creating a RSgImage"),aIdx);
+ TSgImageInfoOpenVgImage imageInfo = TSgImageInfoOpenVgImage(iSourceFormat, KImageSize);
+#ifndef SYMBIAN_GRAPHICS_EGL_SGIMAGELITE
+ imageInfo.iShareable = ETrue;
+ imageInfo.iCpuAccess = ESgCpuAccessReadWrite;
+#endif
+ ASSERT_EQUALS(rSgImageLocal.Create(imageInfo,NULL, NULL), KErrNone);
+
+ INFO_PRINTF2(_L("Process %d, Sending SgImage ID to other process..."), aIdx);
+ messageQueueSgId.SendBlocking(rSgImageLocal.Id());
+
+ // Sending Process ID to other process... so that the other process can identify when this one dies.
+ messageQueueProcId.SendBlocking(RProcess().Id());
+ }
+ else if(aIdx == 1)
+ {
+ INFO_PRINTF2(_L("Process %d: Receiving SgImage ID from other process..."), aIdx);
+ //unlike the other cases, do not open it (yet)
+ messageQueueSgId.ReceiveBlocking(sgImageId);
+
+ // Also receiving RProcess ID from other process to be able to identify when it dies
+ TProcessId procId;
+ messageQueueProcId.ReceiveBlocking(procId);
+ process.Open(procId);
+ process.Logon(status);
+ }
+
+ // Wait for both processes to reach this point
+ Rendezvous(aIdx);
+
+ if(aIdx == 0)
+ {
+ // simulate this process being killed
+ // note that we terminate with reason=0 (otherwise the egl test framework would think it's an error)
+ INFO_PRINTF2(_L("Process %d, Simulate the process is being killed!"),aIdx);
+ RProcess().Terminate(KErrNone);
+
+ // this line is unreachable
+ ASSERT(0);
+ }
+ else if(aIdx == 1)
+ {
+ // first wait for the other process to finish
+ User::WaitForRequest(status);
+ ASSERT_EQUALS(status.Int(), KErrNone);
+
+ // NOTE: We can't guarante when the kernel will have completed the cleanup. This process
+ // could have been notified that the other process has terminated but this does not guarantee
+ // that all handles to the process have been released.
+ // This is not generally a problem in single processor hardware, but can be a problem in dual
+ // processor hardware (ie, NaviEngine) where one processor could be cleaning up the terminated
+ // process, the other processor could already be issuing the notification to the waiting process
+ // Not much we can do other than adding a small delay to ensure this...
+ User::After(1*1000*1000); // 1 second
+
+ // we're expecting it to fail with the appropriate error
+ TInt ret = rSgImageLocal.Open(sgImageId);
+#ifdef SYMBIAN_GRAPHICS_EGL_SGIMAGELITE
+ INFO_PRINTF4(_L("Process %d: Opening SgImage resulted in %d (expected was %d)."), aIdx, ret, KErrNotFound);
+ ASSERT_EQUALS(ret, KErrNotFound);
+#else
+ INFO_PRINTF4(_L("Process %d: Opening SgImage resulted in %d (expected was %d)."), aIdx, ret, KErrArgument);
+ ASSERT_EQUALS(ret, KErrArgument);
+#endif
+ }
+
+ //cleanup and finish
+ CleanupStack::PopAndDestroy(3, &messageQueueSgId); //messageQueueSgId, messageQueueProcId, process
+ CleanAll();
+ }
+
+
+/**
+@SYMTestCaseID GRAPHICS-EGL-0431
+
+@SYMTestPriority 1
+
+@SYMPREQ 2637
+
+@SYMTestCaseDesc
+Functional test - Simultaneous reading and writing of simulated glyphs.
+The rectangular area of RSgImage will be divided into the following section:
+ -----------
+ ¦ 0 ¦ 1 ¦ 2 ¦
+ ¦-----------
+ ¦ 3 ¦ 4 ¦ 5 ¦
+ ¦-----------
+ ¦ 6 ¦ 7 ¦ 8 ¦
+ -----------
+The image size is taken to be 90x90 so that it is easily split between 9 sub-sections
+It is obvoious that each sub-section will therefore be of 30x30:
+
+@SYMTestPurpose
+To determine that the system can cope with simultaneous
+reading and writing from/to area within RSgImage without corrupting each other.
+
+@SYMTestActions
+Run two processes that independently perform the actions detailed below.
+* From Process A:
+ Open the RSgDriver
+ Create an RSgImages with no content
+ For each RSgImage, create an EGLImage and from that create a VGImage
+ Close the RSgImage and the EGLImage
+* From Process B:
+ Open the RSgDriver
+ Open the RSgImage using the drawable ID passed from process A
+ Create an EGLImage and then a VGImage
+ Close the RSgImage and the EGLImage
+ Wait for signal from process A
+
+* Concurrently from Process A and the client process:
+ Process A:
+ For i = 1 to 9
+ Shade section[i] to colour[i]
+ Signal client process that section[i] can be read
+ Repeat until client process signal read complete
+ Shade sections surrounding section[i] to other colors e.g. when i=1,
+ surrounding sections are section 4, 5 and 2
+ End loop
+ End loop
+
+ Process B:
+ For i = 1 to 9
+ Wait for signal that section[i] is ready
+ Create child VGImage for section[i]
+ Read the value of child VGImage and compare it with colour[i]
+ Signal process A to indicate read is complete
+ Destroy child VGImage
+ End loop
+
+* Processes A and B:
+Close the VGImage and RSgImage driver
+
+@SYMTestExpectedResults
+The content of each section read by client process should match the content written by Process A.
+All image memory should be freed
+*/
+TVerdict CEglTest_EGL_Image_Multi_Process_VgImage_ReadWrite::doTestStepL()
+ {
+ SetTestStepID(_L("GRAPHICS-EGL-0431"));
+ SetTestStepName(KEGL_Image_Multi_Process_VgImage_ReadWrite);
+ INFO_PRINTF1(_L("Enter: CEglTest_EGL_Image_Multi_Process_VgImage_ReadWrite::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 ARGB_8888 non pre-multiplied
+ // as we compare pixels manually, we avoid having to do the pre-multiply in the test itself
+ iSourceFormat = EUidPixelFormatARGB_8888;
+ iSurfaceFormat = VG_sARGB_8888;
+ PrintUsedPixelConfiguration();
+
+ // launch 2 processes
+ Test_MultiProcessL(KEglTestStepDllName, 2, TestStepName());
+
+ INFO_PRINTF1(_L("Exit: CEglTest_EGL_Image_Multi_Process_VgImage_ReadWrite::doTestStepL"));
+ RecordTestResultL();
+ CloseTMSGraphicsStep();
+ return TestStepResult();
+ }
+
+void CEglTest_EGL_Image_Multi_Process_VgImage_ReadWrite::doProcessFunctionL(TInt aIdx)
+ {
+ INFO_PRINTF2(_L("CEglTest_EGL_Image_Multi_Process_VgImage_ReadWrite::doProcessFunctionL, Process %d"),aIdx);
+ GetDisplayL();
+ CreateEglSessionL(aIdx);
+ iEglSess->InitializeL();
+ iEglSess->OpenSgDriverL();
+
+ const TSize KTestReadWriteImageSize(90,90);
+ const TInt KTestReadWriteSubImageLength = KTestReadWriteImageSize.iHeight / 3;
+ const TInt KTestNumColors = 9;
+ const VGfloat KTestClearColors[KTestNumColors][4] =
+ {
+ {0.11f, 0.13f, 0.15f, 0.17f}, // arbitrary colour 1
+ {0.21f, 0.23f, 0.25f, 0.27f}, // arbitrary colour 2
+ {0.31f, 0.33f, 0.35f, 0.37f}, // arbitrary colour 3
+ {0.41f, 0.43f, 0.45f, 0.47f}, // arbitrary colour 4
+ {0.51f, 0.53f, 0.55f, 0.57f}, // arbitrary colour 5
+ {0.61f, 0.63f, 0.65f, 0.67f}, // arbitrary colour 6
+ {0.71f, 0.73f, 0.75f, 0.77f}, // arbitrary colour 7
+ {0.81f, 0.83f, 0.85f, 0.87f}, // arbitrary colour 8
+ {0.91f, 0.93f, 0.95f, 0.97f} // arbitrary colour 9
+ };
+
+ //Retrieve source formats for the launched process from the process parameters.
+ User::LeaveIfError(User::GetTIntParameter(EProcSlotSourceFormat, reinterpret_cast<TInt&>(iSourceFormat)));
+ User::LeaveIfError(User::GetTIntParameter(EProcSlotSurfaceFormat, reinterpret_cast<TInt&>(iSurfaceFormat)));
+
+ //create the queue to send/receive SgImage ID between processes
+ RMsgQueue<TSgDrawableId> messageQueueSgId;
+ User::LeaveIfError(messageQueueSgId.Open(EProcSlotMsgQueueSgId, EOwnerProcess));
+ CleanupClosePushL(messageQueueSgId);
+
+ RSgImage rSgImageLocal;
+ if(aIdx == 0)
+ {
+ // Create an RSgImage
+ INFO_PRINTF2(_L("Process %d, Creating a RSgImage"),aIdx);
+ TSgImageInfoOpenVgImage imageInfo = TSgImageInfoOpenVgImage(iSourceFormat, KImageSize);
+#ifndef SYMBIAN_GRAPHICS_EGL_SGIMAGELITE
+ imageInfo.iShareable = ETrue;
+ imageInfo.iCpuAccess = ESgCpuAccessReadWrite;
+#endif
+ ASSERT_EQUALS(rSgImageLocal.Create(imageInfo,NULL, NULL), KErrNone);
+
+ INFO_PRINTF2(_L("Process %d, Sending SgImage ID to other process..."), aIdx);
+ messageQueueSgId.SendBlocking(rSgImageLocal.Id());
+ }
+ else if(aIdx == 1)
+ {
+ INFO_PRINTF2(_L("Process %d: Receiving SgImage ID from other process..."), aIdx);
+ TSgDrawableId sgImageId;
+ messageQueueSgId.ReceiveBlocking(sgImageId);
+ ASSERT_EQUALS(rSgImageLocal.Open(sgImageId),KErrNone);
+ }
+
+ INFO_PRINTF2(_L("Process %d, Creating an EGLImage from the shared RSgImage"),aIdx);
+ CleanupClosePushL(rSgImageLocal);
+ EGLImageKHR eglImageLocal = iEglSess->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
+
+ // OpenVG needs a current VG context before it will allow the call vgCreateEGLImageTargetKHR
+ // The created surface will remain un-used, hence we create it with the default pixel format, as we don't care
+ TUidPixelFormat pixelFormat = EglTestConversion::VgFormatToSgPixelFormat(KDefaultSurfaceFormat);
+ TSgImageInfoOpenVgTarget imageInfo = TSgImageInfoOpenVgTarget(pixelFormat, KTestReadWriteImageSize);
+ iEglSess->CreatePixmapSurfaceAndMakeCurrentAndMatchL(imageInfo,CTestEglSession::EResourceCloseSgImageEarly);
+
+ INFO_PRINTF2(_L("Process %d, Creating one VGImage from the EGLImage"),aIdx);
+ VGImage vgImageLocal = iEglSess->vgCreateImageTargetKHR((VGeglImageKHR)eglImageLocal);
+ ASSERT_VG_TRUE(vgImageLocal != VG_INVALID_HANDLE);
+ ASSERT_EGL_TRUE(iEglSess->DestroyEGLImage(iDisplay, eglImageLocal));
+
+ // Wait for both processes to reach this point
+ Rendezvous(aIdx);
+
+ for (TInt section=0; section<9; section++)
+ {
+ INFO_PRINTF3(_L("Process %d, Starting loop for section[%d]"),aIdx, section);
+ if (aIdx==0)
+ {
+ INFO_PRINTF3(_L("Process %d, Shading section[%d]"),aIdx, section);
+ //Shade section[i] to color[i]
+ vgSetfv(VG_CLEAR_COLOR, 4, KTestClearColors[section]);
+ vgClearImage(vgImageLocal, section%3, section/3, KTestReadWriteSubImageLength, KTestReadWriteSubImageLength);
+ }
+
+ // Wait for both processes to reach this point
+ Rendezvous(aIdx);
+
+ VGImage childImage = VG_INVALID_HANDLE;
+ if (aIdx==1)
+ {
+ INFO_PRINTF3(_L("Process %d, Creating child vgimage for section[%d]"),aIdx, section);
+ //Create child VGImage for section[i]
+ childImage = vgChildImage(vgImageLocal, section%3, section/3, KTestReadWriteSubImageLength, KTestReadWriteSubImageLength);
+ //Read the value of child VGImage and compare it with colour[i]
+ TUint32 vgPixel=0;
+ for (TInt i=0; i<KTestReadWriteSubImageLength; i++)
+ {
+ for (TInt j=0; j<KTestReadWriteSubImageLength; j++)
+ {
+ vgGetImageSubData(childImage, &vgPixel, 1, iSurfaceFormat, i, j, 1, 1);
+ // Should be exact, but give a tolerance of 1 because VG rounds to nearer integer, whereas TInt rounds down
+ ASSERT_TRUE(Abs(((vgPixel & 0xff000000) >> 24) - (255 * KTestClearColors[section][3])) <= 1); //alpha
+ ASSERT_TRUE(Abs(((vgPixel & 0x00ff0000) >> 16) - (255 * KTestClearColors[section][0])) <= 1); //red
+ ASSERT_TRUE(Abs(((vgPixel & 0x0000ff00) >> 8) - (255 * KTestClearColors[section][1])) <= 1); //green
+ ASSERT_TRUE(Abs(((vgPixel & 0x000000ff) >> 0) - (255 * KTestClearColors[section][2])) <= 1); //blue
+ }
+ }
+ }
+ if (aIdx==0)
+ {
+ INFO_PRINTF3(_L("Process %d, Shading surrounding sections to section[%d]"),aIdx, section);
+ for (TInt k=-3; k<=3; k=k+2)
+ {
+ TInt surroundingSection = (KTestNumColors + section + k) % KTestNumColors;
+ vgSetfv(VG_CLEAR_COLOR, 4, KTestClearColors[surroundingSection]);
+ vgClearImage(vgImageLocal, surroundingSection*KTestReadWriteSubImageLength, section*KTestReadWriteSubImageLength, KTestReadWriteSubImageLength, KTestReadWriteSubImageLength);
+ }
+ }
+
+ // Wait for both processes to reach this point
+ Rendezvous(aIdx);
+
+ if (aIdx==1)
+ {
+ INFO_PRINTF3(_L("Process %d, destroying child vgimage for section[%d]"),aIdx, section);
+ //Destroy child VGImage
+ vgDestroyImage(childImage);
+ ASSERT_TRUE(vgGetError() == VG_NO_ERROR);
+ }
+ }
+
+ // cleanup
+ vgDestroyImage(vgImageLocal);
+ ASSERT_TRUE(vgGetError() == VG_NO_ERROR);
+ CleanupStack::PopAndDestroy(&messageQueueSgId);
+ CleanAll();
+ }
+