diff -r 000000000000 -r 5d03bc08d59c egl/egltest/src/egltest_image_multiprocess.cpp --- /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 // for ASSERT macros +#ifndef __INIPARSER_H__ +#include +#endif // __INIPARSER_H__ +#include + +#include "egltest_image_multiprocess.h" + +#include +#include +#include +#include + +// +// 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(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 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(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 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(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 sgIdList; + CleanupClosePushL(sgIdList); + RSgImage sgImages[KNumImages]; + + INFO_PRINTF2(_L("MAIN PROCESS: Creating %d RSgImage(s)..."), KNumImages); + for (TInt i=0; iCreateReferenceBitmapL(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(iSourceFormat))); + User::LeaveIfError(User::GetTIntParameter(EProcSlotSurfaceFormat, reinterpret_cast(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 sgIdList; + CleanupClosePushL(sgIdList); + RSgImage sgImages[KNumImages]; + + INFO_PRINTF2(_L("MAIN PROCESS: Creating %d RSgImage(s)..."), KNumImages); + for (TInt i=0; ieglCreateImageKhrL(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(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(iSourceFormat))); + User::LeaveIfError(User::GetTIntParameter(EProcSlotSurfaceFormat, reinterpret_cast(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 sgIdList; + CleanupClosePushL(sgIdList); + RSgImage sgImages[KNumImages]; + + INFO_PRINTF2(_L("MAIN PROCESS: Creating %d RSgImage(s)..."), KNumImages); + for (TInt i=0; i(&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(&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(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(iSourceFormat))); + User::LeaveIfError(User::GetTIntParameter(EProcSlotSurfaceFormat, reinterpret_cast(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(iSourceFormat))); + User::LeaveIfError(User::GetTIntParameter(EProcSlotSurfaceFormat, reinterpret_cast(iSurfaceFormat))); + + //create the queue to send/receive SgImage ID between processes + RMsgQueue messageQueueSgId; + User::LeaveIfError(messageQueueSgId.Open(EProcSlotMsgQueueSgId, EOwnerProcess)); + CleanupClosePushL(messageQueueSgId); + + //create the queue to send/receive Process ID between processes + RMsgQueue 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(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(iSourceFormat))); + User::LeaveIfError(User::GetTIntParameter(EProcSlotSurfaceFormat, reinterpret_cast(iSurfaceFormat))); + + //create the queue to send/receive SgImage ID between processes + RMsgQueue messageQueueSgId; + User::LeaveIfError(messageQueueSgId.Open(EProcSlotMsgQueueSgId, EOwnerProcess)); + CleanupClosePushL(messageQueueSgId); + + //create the queue to send/receive Process ID between processes + RMsgQueue 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(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(iSourceFormat))); + User::LeaveIfError(User::GetTIntParameter(EProcSlotSurfaceFormat, reinterpret_cast(iSurfaceFormat))); + + //create the queue to send/receive SgImage ID between processes + RMsgQueue messageQueueSgId; + User::LeaveIfError(messageQueueSgId.Open(EProcSlotMsgQueueSgId, EOwnerProcess)); + CleanupClosePushL(messageQueueSgId); + + //create the queue to send/receive Process ID between processes + RMsgQueue 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(iSourceFormat))); + User::LeaveIfError(User::GetTIntParameter(EProcSlotSurfaceFormat, reinterpret_cast(iSurfaceFormat))); + + //create the queue to send/receive SgImage ID between processes + RMsgQueue 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> 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(); + } +