graphicsdeviceinterface/directgdi/test/tmultithread.cpp
changeset 0 5d03bc08d59c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graphicsdeviceinterface/directgdi/test/tmultithread.cpp	Tue Feb 02 01:47:50 2010 +0200
@@ -0,0 +1,527 @@
+// Copyright (c) 2008-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
+ @internalComponent 
+ @test
+*/
+
+#include "tmultithread.h"
+#include <graphics/directgdicontext.h>
+
+const TUint KMinTestThreadHeapSize = 0x00000100;
+const TUint KMaxTestThreadheapSize = 0x00100000;
+
+CTMultiThread::CTMultiThread()
+	{
+	SetTestStepName(KTMultiThreadStep);
+	}
+
+CTMultiThread::~CTMultiThread()
+	{
+	iThread1.Close();
+	iThread2.Close();
+	}
+
+/**
+Override of base class virtual
+@leave Gets system wide error code
+@return - TVerdict code
+*/
+TVerdict CTMultiThread::doTestStepPreambleL()
+	{			
+	CTDirectGdiStepBase::doTestStepPreambleL();	
+	return TestStepResult();
+	}
+
+/** 
+Override of base class pure virtual
+Our implementation only gets called if the base class doTestStepPreambleL() did
+not leave. That being the case, the current test result value will be EPass.
+@leave Gets system wide error code
+@return TVerdict code
+*/	
+TVerdict CTMultiThread::doTestStepL()
+	{
+	if (iUseDirectGdi)
+		{
+		RunTestsL();
+		// No framework OOM tests are run for the multithreaded tests as OOM testing only checks the 
+		// heap in the current thread and these tests use multiple threads. Some heap checking is
+		// performed within the tests themselves.
+		}
+	else
+		{
+		INFO_PRINTF1(_L("Test skipped under BitGDI.\n"));	
+		}	
+	CloseTMSGraphicsStep();
+	return TestStepResult();
+	}
+
+/**
+Override of base class pure virtual
+Lists the tests to be run
+*/
+void CTMultiThread::RunTestsL()
+	{
+	SetTestStepID(_L("GRAPHICS-DIRECTGDI-MULTITHREAD-0001"));
+	TestDirectGdiMultipleThreadIndependenceL();
+	RecordTestResultL();
+	SetTestStepID(_L("GRAPHICS-DIRECTGDI-MULTITHREAD-0002"));
+	TestShareEGLImageBetweenSources_MultithreadedL();
+	RecordTestResultL();
+	}
+
+/**
+@SYMTestCaseID  
+	GRAPHICS-DIRECTGDI-MULTITHREAD-0001
+	
+@SYMPREQ 
+	PREQ39
+
+@SYMREQ
+	REQ9195
+	REQ9201 
+	REQ9202 
+	REQ9222 
+	REQ9223 
+	REQ9236 
+	REQ9237
+	
+@SYMTestCaseDesc  
+	Ensure multi-threaded use of DirectGDI is truly independent.
+	
+@SYMTestPriority  
+	High
+	
+@SYMTestStatus 
+	Implemented
+	
+@SYMTestActions 
+	The following sequence should be legal:
+		1: (thread 1) initialise DirectGDI by calling ThreadOneStart()
+		2: (thread 2) initialise DirectGDI by calling ThreadTwoStart()
+		3: (thread 1) close DirectGDI
+		4: (thread 2) render using DirectGDI
+		
+@SYMTestExpectedResults 
+	There should be no panics.
+*/
+void CTMultiThread::TestDirectGdiMultipleThreadIndependenceL()
+	{
+	INFO_PRINTF1(_L("Multithread_MultipleThreadIndependence"));	
+	// Create a semaphore
+	RSemaphore sem;
+	TEST(KErrNone == sem.CreateGlobal(KMultiThreadSemaphore, 0));
+   	CleanupClosePushL(sem);	
+   	
+   	//create threads
+	User::LeaveIfError(iThread1.Create(KNameThreadOne, ThreadOneStart, KDefaultStackSize, KMinTestThreadHeapSize, KMaxTestThreadheapSize, NULL));
+	User::LeaveIfError(iThread2.Create(KNameThreadTwo, ThreadTwoStart, KDefaultStackSize, KMinTestThreadHeapSize, KMaxTestThreadheapSize, NULL));
+	
+	//launch thread1
+	TRequestStatus thread1Status;
+	iThread1.Logon(thread1Status);
+	iThread1.SetPriority(EPriorityLess);
+	iThread1.Resume();
+	sem.Wait();
+	iThread1.Suspend();
+	
+	//launch thread2
+	TRequestStatus thread2Status;
+	iThread2.Logon(thread2Status);
+	iThread2.SetPriority(EPriorityLess);
+	iThread2.Resume();
+	sem.Wait();
+	iThread2.Suspend();
+	
+	//resume thread1
+	iThread1.Resume();
+	User::WaitForRequest(thread1Status);
+	
+	//resume thread2
+	iThread2.Resume();
+	User::WaitForRequest(thread2Status);	
+	
+	TESTNOERROR(iThread1.ExitReason());
+	TESTNOERROR(iThread2.ExitReason());
+			
+	iThread1.Close();
+	iThread2.Close();
+	CleanupStack::PopAndDestroy(&sem);
+	}
+
+/**
+Function for initializing DirectGdi, used by TestDirectGdiMultipleThreadIndependenceL().
+@see TestDirectGdiMultipleThreadIndependenceL() 
+@param aInfo Not used
+@return KErrNone if successful, one of the system wide error codes otherwise
+ */
+TInt CTMultiThread::ThreadOneStart(TAny* /*aInfo*/)
+	{	
+	TInt procHandles1  =0;
+	TInt threadHandles1=0;
+	RThread().HandleCount(procHandles1, threadHandles1);
+	__UHEAP_MARK;
+	
+	RSemaphore sem;
+	TInt ret = sem.OpenGlobal(KMultiThreadSemaphore);
+	if (ret!=KErrNone)
+		{
+		return ret;
+		}		
+	
+	//initialize graphics resource driver
+	ret = SgDriver::Open();
+	if (ret!=KErrNone)
+		{
+		return ret;
+		}		
+	
+	//initialise DirectGDI
+	ret = CDirectGdiDriver::Open();
+	if (ret!=KErrNone)
+		{
+		return ret;
+		}		
+
+	CDirectGdiDriver* dgdiDriver = CDirectGdiDriver::Static();
+	if(dgdiDriver == NULL)
+		{
+		return KErrGeneral;	
+		}
+	
+	sem.Signal();
+
+	//close DirectGDI
+	dgdiDriver->Close();
+	SgDriver::Close();	
+	sem.Close();
+	__UHEAP_MARKEND;
+	TInt procHandles2  =0;
+	TInt threadHandles2=0;
+	RThread().HandleCount(procHandles2,threadHandles2);
+	if (threadHandles1 != threadHandles2)
+		{
+		ret = KErrGeneral;  // Thread-owned handles not closed
+		}
+	return ret;
+	}
+
+/**
+Function for initializing DirectGdi then activating a target and drawing on it,
+used by TestDirectGdiMultipleThreadIndependenceL().
+@see TestDirectGdiMultipleThreadIndependenceL()
+@param aInfo Not used
+@return KErrNone if successful, one of the system wide error codes otherwise 
+ */
+TInt CTMultiThread::ThreadTwoStart(TAny* /*aInfo*/)
+	{
+	TInt procHandles1  =0;
+	TInt threadHandles1=0;
+	RThread().HandleCount(procHandles1, threadHandles1);
+	__UHEAP_MARK;
+	CTrapCleanup* cleanupStack=CTrapCleanup::New();
+	if (cleanupStack==NULL)
+		{
+		return KErrNoMemory;
+		}
+	
+	RSemaphore sem;
+	TInt ret = sem.OpenGlobal(KMultiThreadSemaphore);
+	if (ret!=KErrNone)
+		{
+		return ret;
+		}		
+	
+	//initialize graphics resource driver
+	ret = SgDriver::Open();
+	if (ret!=KErrNone)
+		{
+		return ret;
+		}		
+	
+	//initialise DirectGDI
+	ret = CDirectGdiDriver::Open();
+	if (ret!=KErrNone)
+		{
+		return ret;
+		}		
+
+	CDirectGdiDriver* dgdiDriver = CDirectGdiDriver::Static();
+	if(dgdiDriver == NULL)
+		{
+		return KErrGeneral;	
+		}
+	
+	sem.Signal();
+	
+	//render using DirectGDI
+	CDirectGdiContext* gc = NULL;
+	TRAPD(err, gc=CDirectGdiContext::NewL(*dgdiDriver));
+	if(err != KErrNone)
+		{
+		return err;
+		}
+	
+	RSgImage rsgImage;	
+	TSgImageInfo imageInfo;
+	imageInfo.iSizeInPixels = TSize (320, 240);
+	imageInfo.iPixelFormat = EUidPixelFormatRGB_565;
+	imageInfo.iUsage = ESgUsageDirectGdiTarget;
+	ret = rsgImage.Create(imageInfo, NULL,0);
+	if(ret != KErrNone)
+		{
+		return ret;
+		}
+	RDirectGdiImageTarget dgdiImageTarget(*dgdiDriver);	
+	ret = dgdiImageTarget.Create(rsgImage);
+	if(ret != KErrNone)
+		{
+		return ret;
+		}
+	gc->Activate(dgdiImageTarget);
+	gc->SetPenColor(TRgb(100,100,100));
+	gc->DrawRect(TRect(0,0,30,30));
+	
+	rsgImage.Close();
+	dgdiImageTarget.Close();
+	delete gc;
+	dgdiDriver->Close();
+	SgDriver::Close();
+	delete cleanupStack;
+	__UHEAP_MARKEND;
+	sem.Close();	
+	TInt procHandles2  =0;
+	TInt threadHandles2=0;
+	RThread().HandleCount(procHandles2,threadHandles2);
+	if (threadHandles1 != threadHandles2)
+		{
+		ret = KErrGeneral;  // Thread-owned handles not closed
+		}
+	return ret;
+	}
+
+/**
+@SYMTestCaseID		
+	GRAPHICS-DIRECTGDI-MULTITHREAD-0002
+
+@SYMTestPriority
+	Critical
+
+@SYMPREQ
+	PREQ39
+
+@SYMREQ
+	REQ9195
+	REQ9201 
+	REQ9202 
+	REQ9222 
+	REQ9223 
+	REQ9236 
+	REQ9237
+
+@SYMTestStatus
+	Implemented
+
+@SYMTestCaseDesc
+	Create two CDirectGdiImageSource objects from the same RSgImage, but in different threads.
+
+@SYMTestActions	
+	Test the use case where we:
+	Create an RSgImage
+	Create two CDirectGdiImageSource objects, one in the current thread, and one in a new thread.
+	The CDirectGdiImageSource objects should share the EGL image created from the RSgImage in the 
+	current thread as only one EGL image can be created per RSgImage per process.
+	If the EGL image sharing is not working an error will occur when creating the
+	second CDirectGdiImageSource object in the new thread.
+*/
+void CTMultiThread::TestShareEGLImageBetweenSources_MultithreadedL()
+	{
+	INFO_PRINTF1(_L("Multithread_ShareEGLImageBetweenSources"));
+	
+	TUidPixelFormat pixelFormat = EUidPixelFormatXRGB_8888;
+	SetTargetL(pixelFormat);
+	
+	// Initialize graphics resource driver
+	TInt res = SgDriver::Open();
+	TESTNOERRORL(res);
+	
+	res = CDirectGdiDriver::Open();
+	TESTNOERRORL(res);		
+	
+	CDirectGdiDriver* dgdiDriver = CDirectGdiDriver::Static();
+	TESTL(dgdiDriver != NULL);	
+	CleanupClosePushL(*dgdiDriver);	
+	
+	// Create a context
+	CDirectGdiContext* gc = CDirectGdiContext::NewL(*dgdiDriver);
+	TESTL(gc != NULL);	
+	CleanupStack::PushL(gc);	
+	
+	// Create a CFbsBitmap	
+	TSize patternSize(90,50);
+	TRect rect(0,0,90,50);
+	CFbsBitmap* bitmap = CreateCheckedBoardBitmapL(pixelFormat, patternSize);
+	TESTL(NULL != bitmap);
+	CleanupStack::PushL(bitmap);	
+	
+	// Create an RSgImage from the CFbsBitmap
+	TSgImageInfo imageInfo;
+	imageInfo.iSizeInPixels = patternSize;
+	imageInfo.iPixelFormat = pixelFormat;
+	imageInfo.iUsage = ESgUsageDirectGdiSource;
+	RSgImage sgImage;	
+	res = sgImage.Create(imageInfo, bitmap->DataAddress(), bitmap->DataStride());	
+	TESTNOERRORL(res);	
+	CleanupClosePushL(sgImage);
+	
+	// Create a RDirectGdiDrawableSource from the RSgImage
+	RDirectGdiDrawableSource dgdiImageSource(*dgdiDriver);	
+	res = dgdiImageSource.Create(sgImage);		
+	TESTNOERRORL(res);
+	CleanupClosePushL(dgdiImageSource);	
+	
+	// Create a semaphore
+	RSemaphore sem;
+	TEST(KErrNone == sem.CreateGlobal(KMultiThreadSemaphore, 0));
+   	CleanupClosePushL(sem);	
+   	
+   	// Create the thread that will create a source from the RSgImage above   	
+   	TSgDrawableId sgImageId = sgImage.Id();
+	User::LeaveIfError(iThread1.Create(KNameThreadOne, ThreadEGLImageStart, KDefaultStackSize, KMinTestThreadHeapSize, KMaxTestThreadheapSize, &sgImageId));	
+	
+	// Launch the thread
+	TRequestStatus threadStatus;
+	iThread1.Logon(threadStatus);
+	iThread1.SetPriority(EPriorityLess);
+	iThread1.Resume();
+	sem.Wait();
+	iThread1.Suspend();
+		
+	// Resume the thread
+	iThread1.Resume();
+	User::WaitForRequest(threadStatus);
+	
+	TESTNOERROR(iThread1.ExitReason());	
+			
+	iThread1.Close();	
+	SgDriver::Close();
+	CleanupStack::PopAndDestroy(6, dgdiDriver);
+	}
+
+/**
+Function use by TestShareEGLImageBetweenSources_MultithreadedL() when testing
+creation of a target in a separate thread.
+@see TestShareEGLImageBetweenSources_MultithreadedL()
+@param aInfo Not used
+@return KErrNone if successful, one of the system wide error codes otherwise
+ */
+TInt CTMultiThread::ThreadEGLImageStart(TAny* aInfo)
+	{	
+	TInt procHandles1 = 0;
+	TInt threadHandles1 = 0;
+	RThread().HandleCount(procHandles1, threadHandles1);
+	__UHEAP_MARK;
+	CTrapCleanup* cleanupStack=CTrapCleanup::New();
+	if (cleanupStack==NULL)
+		{
+		return KErrNoMemory;
+		}		
+	
+	RSemaphore sem;
+	TInt ret = sem.OpenGlobal(KMultiThreadSemaphore);
+	if (ret!=KErrNone)
+		return ret;
+	
+	// Initialize graphics resource driver
+	ret = SgDriver::Open();
+	if (ret!=KErrNone)
+		return ret;
+	
+	// Initialise DirectGDI
+	ret = CDirectGdiDriver::Open();
+	if (ret!=KErrNone)
+		return ret;
+
+	CDirectGdiDriver* dgdiDriver = CDirectGdiDriver::Static();
+	if(dgdiDriver == NULL)
+		{
+		return KErrGeneral;	
+		}
+	
+	TSgDrawableId* sgImageId = reinterpret_cast<TSgDrawableId*>(aInfo);
+	RSgImage sgImageSource;
+	ret = sgImageSource.Open(*sgImageId);
+	if (ret!=KErrNone)
+		return ret;
+	
+	// Create a RDirectGdiDrawableSource from the RSgImage
+	RDirectGdiDrawableSource dgdiImageSource(*dgdiDriver);	
+	ret = dgdiImageSource.Create(sgImageSource);		
+	if (ret!=KErrNone)
+		return ret;
+	
+	sem.Signal();
+	
+	// Render using DirectGDI
+	CDirectGdiContext* gc = NULL;
+	TRAPD(err, gc=CDirectGdiContext::NewL(*dgdiDriver));
+	if(err != KErrNone)
+		{
+		return err;
+		}
+	
+	RSgImage rsgImage;	
+	TSgImageInfo imageInfo;
+	imageInfo.iSizeInPixels = TSize (320, 240);
+	imageInfo.iPixelFormat = EUidPixelFormatRGB_565;
+	imageInfo.iUsage = ESgUsageDirectGdiTarget;
+	ret = rsgImage.Create(imageInfo, NULL,0);
+	if(ret != KErrNone)
+		{
+		return ret;
+		}
+	RDirectGdiImageTarget dgdiImageTarget(*dgdiDriver);	
+	ret = dgdiImageTarget.Create(rsgImage);
+	if(ret != KErrNone)
+		{
+		return ret;
+		}
+	gc->Activate(dgdiImageTarget);
+	gc->SetPenColor(TRgb(100,100,100));
+	gc->DrawRect(TRect(0,0,30,30));
+	
+	dgdiImageSource.Close();
+	sgImageSource.Close();
+	rsgImage.Close();
+	dgdiImageTarget.Close();
+	delete gc;
+	dgdiDriver->Close();
+	SgDriver::Close();
+	delete cleanupStack;
+	__UHEAP_MARKEND;
+	sem.Close();	
+	TInt procHandles2  =0;
+	TInt threadHandles2=0;
+	RThread().HandleCount(procHandles2,threadHandles2);
+	if (threadHandles1 != threadHandles2)
+		{
+		ret = KErrGeneral;  // Thread-owned handles not closed
+		}
+	return ret;
+	}
+