graphicstest/graphicstestharness/src/TGraphicsHarness.cpp
author Matt Plumtree <matt.plumtree@nokia.com>
Fri, 23 Apr 2010 17:57:02 +0100
branchNewGraphicsArchitecture
changeset 39 a4b63488e0b0
parent 0 5d03bc08d59c
child 103 2717213c588a
permissions -rw-r--r--
Revise some of the compositor performance improvements to improve correctness. Implement pixel blending using a variation of Jim Blinn's no-division blending algorithm. Move transparency type simplification further up the composition code. Remove some unnecessary fields. Output to YUV implementation needs revision as it is actually converting from YUV (copy of source conversion code).

// Copyright (c) 2005-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:
//

#include <apgtask.h>
#include <hal.h>
#include <w32debug.h>
#include <e32std.h> 
#include <graphics/fbsdefs.h>

#include "TGraphicsHarness.h"
#include "GraphicsTestUtilsServer.h"

_LIT(KGraphicsTestFrameworkPanic, "Graphics Test Framework");
const TInt KTestCleanupStack = 0x40;

const TDisplayMode testDisplayModes[] =	
	{
	EGray2,
	EGray4,
	EGray16,
	EGray256,
	EColor16,
	EColor256,
	EColor64K,
	EColor16M,
	EColor4K,
	EColor16MU,
	EColor16MA,
	EColor16MAP,
	};

/**
  The test code manager, provides functions to set active object 
  with lowest priority for running tests in auto mode.
 */
class CTestManager : public CActive
	{
friend class CTGraphicsBase;
protected:
	static CTestManager* NewL(MTestCases* aAutoTestApp);
	~CTestManager();
	void FinishAllTestCases();
	void StartTest(); //initialize an active object and set it status as active
	void SetSelfDrive(TBool aSelfDrive);
	void CaseComplete();
private:
	CTestManager(MTestCases* aAutoTestApp);
	void NextTest();
	// from CActive
	void RunL();
	void DoCancel();
	TInt RunError(TInt aError);
private:
	MTestCases* iTestCase;
	TInt iCurTestCaseNumber; //a current test case, every time when function RunTestCaseL is called this member inc by one
	TBool iTestCompleted;
	TBool iSelfDrive;
	};

/** Construct an active object with the lowest priority */
CTestManager::CTestManager(MTestCases* aTestCases) :
		CActive(EPriorityIdle), iTestCase(aTestCases), iSelfDrive(EFalse)
	{}

CTestManager::~CTestManager()
	{
	Cancel();
	}

CTestManager* CTestManager::NewL(MTestCases* aTestCases)
	{
     CTestManager *theTestManager=new (ELeave) CTestManager(aTestCases);
     CActiveScheduler::Add(theTestManager);
	 return theTestManager;
	}

void CTestManager::RunL()
	{
	__ASSERT_ALWAYS(iTestCase, User::Panic(KGraphicsTestFrameworkPanic, KErrBadHandle));
	if(	iTestCompleted)
		{
		return;
		}
	
	// debug statement to indicate progress of test suite by
	// printing the sub-test that is currently active
	TTime timeStamp;
	timeStamp.HomeTime();
	TBuf<50> dateStr;
	_LIT(KDateString3,"%-B%:0%J%:1%T%:2%S%:3.%Cms");
	timeStamp.FormatL(dateStr, KDateString3);
	++iCurTestCaseNumber;
	RDebug::Print(_L("%S - Test Case Number: %d"), &dateStr, iCurTestCaseNumber);

	iTestCase->RunTestCaseL(iCurTestCaseNumber);
	if (iTestCompleted)
		{
		_LIT(KFinished,"Finished test case %d and test completed");
		RDebug::Print(KFinished,iCurTestCaseNumber);
		}
	else
		{
		if (iSelfDrive)
			{
			_LIT(KStarted,"Started test case %d");
			RDebug::Print(KStarted,iCurTestCaseNumber);
			}
		else
			{
			NextTest();
			}
		}
	}

void CTestManager::DoCancel()
	{
	if (!iSelfDrive)
		iTestCompleted = ETrue;
	}

TInt CTestManager::RunError(TInt aError)
	{
	TTime timeStamp;
	timeStamp.HomeTime();
	TBuf<50> dateStr;
	_LIT(KDateString3,"%-B%:0%J%:1%T%:2%S%:3 %Cms");
	timeStamp.FormatL(dateStr, KDateString3);
	_LIT(KTestLeft,"RunTestCaseL left of %S - Test Case Number: %d");
	RDebug::Print(KTestLeft, &dateStr, iCurTestCaseNumber);
	
	aError = iTestCase->RunTestCaseLeft(aError);
	FinishAllTestCases();
	return aError;
	}

/**
 	Initialize an active object and set it as active
 */
void CTestManager::StartTest()
	{
	TRequestStatus *pS= (&iStatus);
	User::RequestComplete(pS, 0);
	SetActive();
	}

/**
 Time to move on to the next test step
 */
void CTestManager::NextTest()
	{
	_LIT(KFinished,"Finished test case %d");
	RDebug::Print(KFinished,iCurTestCaseNumber);
	StartTest();
	}

/**
 Stop active scheduler, and quit a test step
 */
void CTestManager::FinishAllTestCases()
	{
	iTestCompleted = ETrue;
	CActiveScheduler::Stop();
	}

/**
 Controls wether the manager calls RunTestCaseL whenever the system is otherwise idol
 */
void CTestManager::SetSelfDrive(TBool aSelfDrive)
	{
	if (iSelfDrive!=aSelfDrive)
		{
		iSelfDrive = aSelfDrive;
		if (aSelfDrive)
			{
			if (IsActive())
				Cancel();
			}
		else
			{
			if (!IsActive() && !iTestCompleted)
				NextTest();
			}
		}
	}

/**
 Tells the manager this case is finished so you can call RunTestCaseL again
 */
void CTestManager::CaseComplete()
	{
	__ASSERT_DEBUG(!IsActive(), User::Panic(KGraphicsTestFrameworkPanic, ETestPanicAlreadyActive));
	if (iSelfDrive && !iTestCompleted)
		NextTest();
	}


//-------------

EXPORT_C const TDesC& CTGraphicsBase::ColorModeName(TDisplayMode aMode)
	{
	_LIT(KNone,"None");
	_LIT(KGray2,"Grey2");
	_LIT(KGray4,"Grey4");
	_LIT(KGray16,"Grey16");
	_LIT(KGray256,"Grey256");
	_LIT(KColor16,"Color16");
	_LIT(KColor256,"Color256");
	_LIT(KColor4K,"Color4K");
	_LIT(KColor64K,"Color64K");
	_LIT(KColor16M,"Color16M");
	_LIT(KColor16MU,"Color16MU");
	_LIT(KColor16MA,"Color16MA");
	_LIT(KColor16MAP,"Color16MAP");
	_LIT(KRgb,"RGB");
	_LIT(KUnknown,"Unknown");
	switch(aMode)
		{
	case ENone:
		return KNone;
	case EGray2:
		return KGray2;
	case EGray4:
		return KGray4;
	case EGray16:
		return KGray16;
	case EGray256:
		return KGray256;
	case EColor16:
		return KColor16;
	case EColor256:
		return KColor256;
	case EColor64K:
		return KColor64K;
	case EColor16M:
		return KColor16M;
	case ERgb:
		return KRgb;
	case EColor4K:
		return KColor4K;
	case EColor16MU:
		return KColor16MU;
	case EColor16MA:
		return KColor16MA;
	case EColor16MAP:
		return KColor16MAP;
	default:
		return KUnknown;
		}
	}

EXPORT_C const TDesC& CTGraphicsBase::RotationName(CFbsBitGc::TGraphicsOrientation aOrientation)
	{
	_LIT(K0,"Normal");
	_LIT(K90,"Rotated90");
	_LIT(K180,"Rotated180");
	_LIT(K270,"Rotated270");
	_LIT(KUnknown,"Unknown");
	switch(aOrientation)
		{
	case CFbsBitGc::EGraphicsOrientationNormal:
		return K0;
	case CFbsBitGc::EGraphicsOrientationRotated90:
		return K90;
	case CFbsBitGc::EGraphicsOrientationRotated180:
		return K180;
	case CFbsBitGc::EGraphicsOrientationRotated270:
		return K270;
	default:
		return KUnknown;
		}
	}

EXPORT_C void CTGraphicsBase::SaveScreenShotL(CFbsScreenDevice* aScdv)
	{
#ifdef __WINS__
	_LIT(KBitmapDrive, "c:");
#else
	_LIT(KBitmapDrive, "e:");
#endif
	_LIT(KBitmapPath, "\\screenshot.mbm");
	TDisplayMode dispMode = aScdv->DisplayMode();
	TSize scrSize = aScdv->SizeInPixels();
	CFbsBitmap* dstBmp = new(ELeave) CFbsBitmap;
	CleanupStack::PushL(dstBmp);
	User::LeaveIfError(dstBmp->Create(scrSize, dispMode));
	HBufC8* row = HBufC8::NewLC(scrSize.iWidth*4);
	TPtr8 prow = row->Des();
	for (TInt ii = 0; ii < scrSize.iHeight; ++ii)
		{
		aScdv->GetScanLine(prow, TPoint(0, ii), scrSize.iWidth, dispMode);
		dstBmp->SetScanLine(prow,ii);
		}
	CleanupStack::PopAndDestroy(row);
	TFileName mbmFile;
	mbmFile.Append(KBitmapDrive);
	mbmFile.Append(KBitmapPath);	
	User::LeaveIfError(dstBmp->Save(mbmFile));
	CleanupStack::PopAndDestroy(dstBmp);
	}

EXPORT_C CTGraphicsBase::CTGraphicsBase(CTestStep* aStep) :
			iStep(aStep)
	{}

EXPORT_C CTGraphicsBase::~CTGraphicsBase()
	{
	if(iTestManager)
		{
		iTestManager -> Cancel();
		}
	delete iTestManager;
	}

void CTGraphicsBase::InitializeL()
	{
	__ASSERT_DEBUG(iStep, User::Panic(KGraphicsTestFrameworkPanic, KErrBadHandle));
	iTestManager = CTestManager::NewL(this);
	}
	
/**
 	The function must be called after all test cases completed 
 */	
EXPORT_C void CTGraphicsBase::TestComplete()
	{
	if(iTestManager)
		{
		iTestManager -> FinishAllTestCases();
		}
	}

EXPORT_C void CTGraphicsBase::SetSelfDrive(TBool aSelfDrive)
	{
	if (iTestManager)
		iTestManager->SetSelfDrive(aSelfDrive);
	}

EXPORT_C void CTGraphicsBase::CaseComplete()
	{
	if (iTestManager)
		iTestManager->CaseComplete();
	}

EXPORT_C TInt CTGraphicsBase::RunTestCaseLeft(TInt aError)
	{
	_LIT(KRunTestCaseLLeft,"The RunTestCaseL left with %d");
	ERR_PRINTF2(KRunTestCaseLLeft,aError);
	iStep->SetTestStepResult(EFail);
	return KErrNone;
	}

/** Start a test cases loop */
void CTGraphicsBase::Execute()
	{
	__ASSERT_DEBUG(iTestManager, User::Panic(KGraphicsTestFrameworkPanic, KErrBadHandle));
	__ASSERT_DEBUG(CActiveScheduler::Current(), User::Panic(KGraphicsTestFrameworkPanic, KErrBadHandle));

	iTestManager -> StartTest();
	CActiveScheduler::Start();
	}
/**
	Reset test cases counter to a new value. Can be used for running the same consequence of test 
	cases with different initial parameters.
	aNewCurrentTestCase cannot be negative.
*/
EXPORT_C void CTGraphicsBase::ResetCounter(TInt aNewCurrentTestCase )
	{
	__ASSERT_DEBUG(aNewCurrentTestCase >= 0, User::Panic(KGraphicsTestFrameworkPanic, KErrArgument));
	iTestManager->iCurTestCaseNumber = aNewCurrentTestCase;
	}

//---------------------
/**
 Initialise the cleanup stack.
*/
void CTGraphicsStep::SetupCleanup(CTrapCleanup*& tc)
    {
	tc = CTrapCleanup::New();
	if (!tc)
		{
		User::Panic(_L("Out of memory"), KErrNoMemory);
		}

	TRAPD(r, 
		{
		for ( TInt ii = KTestCleanupStack; ii > 0; ii-- )
			CleanupStack::PushL( (TAny*)1 );
		TEST( r == KErrNone );
		CleanupStack::Pop( KTestCleanupStack );
		} );
	}

void CTGraphicsStep::LogHeapInfo(RWsSession& aWs, TBool aStart)
	{
	_LIT(KInfoStart,"Start");
	_LIT(KInfoEnd,"End");
	_LIT(KInfoCheckPassed,"WsHeap leak check passed");
	_LIT(KInfoCheckFailed,"Memory leak detected. Number of orphaned cells=%d.");
	_LIT(KInfoCheckFailed2,"See epocwindout for the address of the first orphaned cell.");
	_LIT(KInfoHeapSummary," WsHeap - Count=%d,Total=%d,Free=%d,Max free=%d");
	_LIT(KInfoDisabled,"Memory leak testing has not been enabled.");

	TPckgBuf<TWsDebugHeapInfo> heapInfo;
	aWs.DebugInfo(EWsDebugInfoHeap,heapInfo);
	TBuf<256> infoBuf;
	if (aStart)
		{
		infoBuf.Append(KInfoStart);
		}
	else
		{
		infoBuf.Append(KInfoEnd);
		TInt heapFailCount=aWs.DebugInfo(EWsDebugFetchCheckHeapResult);
		if (heapFailCount==KErrNone)
			{
			INFO_PRINTF1(KInfoCheckPassed);
			}
		else if (heapFailCount>0) // Negative error should be ignored as it means the check has not been enabled
			{
			TEST(0);
			ERR_PRINTF2(KInfoCheckFailed,heapFailCount);
			ERR_PRINTF1(KInfoCheckFailed2);
			}
		else
		    {
		    WARN_PRINTF1(KInfoDisabled);
		    }
		}
	infoBuf.AppendFormat(KInfoHeapSummary,heapInfo().iCount,heapInfo().iTotal,heapInfo().iAvailable,heapInfo().iLargestAvailable);
	INFO_PRINTF1(infoBuf);
	}

/**
 Main entry point from CTestStep class. 
 Creates cleanup stack, background window and launches a test
*/
EXPORT_C TVerdict CTGraphicsStep::doTestStepL()
	{
	TInt memFree;
	HAL::Get(HALData::EMemoryRAMFree, memFree);
	INFO_PRINTF2(_L("Test started - RAM free: %d"), memFree);	
	
	__UHEAP_MARK;
	CTrapCleanup* tc = NULL;
	SetupCleanup(tc);
	
	TInt err = RFbsSession::Connect();
	if(err != KErrNone)
		{
		FbsStartup();
		err = RFbsSession::Connect();

		if(err != KErrNone) 
			{
			User::Panic(_L("Font bitmap session connect"), err);
			}
		}
	RWsSession ws;
	err = ws.Connect();
	if (iLogHeapInfo && err==KErrNone)
		{
		ws.DebugInfo(EWsDebugSetCheckHeapOnDisconnectClient);
		LogHeapInfo(ws,ETrue);
		}
	TInt theId1 = NULL;
#ifdef __WINS__
	RWindowGroup winGroup = RWindowGroup(ws);
	RWindow theWindow(ws);
	if (err==KErrNone)
		{
		const TUint32 ENullWsHandle = 0xFFFFFFFF;	// Events delivered to this handle are thrown away
	//creat background window with the size of the screen
	//it is particulary important for tests which draw on the screen, read screen buffer
	//and compare result. By default top TEF window is concole and blinking cursor can interfere
	//with the work of the tests
		TSize size(640, 240); //some default value
	//retrieve screen size
		err = GetScreenSize(size);
		if(err)
			{
			WARN_PRINTF2(_L("Can't retrieve size from screen driver err = %d"), err);
			}

		winGroup.Construct(ENullWsHandle);
		winGroup.AutoForeground(ETrue);
		theId1 = winGroup.Identifier();
	
		theWindow.Construct(winGroup, ENullWsHandle);
		theWindow.SetExtent(TPoint(0, 0), size);
		theWindow.SetVisible(ETrue);
		theWindow.Activate();
	
	//the following trick we need to put the window on the top
		TApaTaskList taskList(ws);
		TApaTask task = taskList.FindByPos(1);
		task.BringToForeground();
		TApaTask task1(ws);	
		task1.SetWgId(theId1);
		task1.BringToForeground();
		}
#endif
	if (err==KErrNone)
		{
		CloseAllPanicWindows(theId1, ws);
		}

	// initialize the test and kick off the test cases loop
	TRAP(err, TestSetupL();  // initialize a test step
				ExecuteL()); // run active scheduler, in order to complete test execution 
							 // CTGraphicsStep::TestComplete function needs to be called

	if (err)
		{
		SetTestStepResult(EFail);
		}
		
	TestClose(); // free all allocated resources here
	
	if (ws.Handle())
		{
		CloseAllPanicWindows(theId1, ws);
#ifdef __WINS__	
		theWindow.Close();
		winGroup.Close();
#endif
		ws.Close();
		User::After(50000);	
		// Prev close will trigger Wserv dummy shutdown and heap check
		// We then re-connect to get the result of the shutdown.
		RWsSession ws2;
		TInt errConnection;
		TInt MaxNumberOfAttempt=10;
		TInt currentAttempt=0;		
		do
			{
			errConnection=ws2.Connect();		
			if (errConnection==KErrNone)
				{
				LogHeapInfo(ws2,EFalse);
				ws2.Close();
				}
			else
				{
				RDebug::Printf("Connection Error with Wserv... %i",errConnection);
				User::After(50000);		
				}
			currentAttempt++;
			}while( (errConnection!=KErrNone) && (currentAttempt<MaxNumberOfAttempt) );
		}
	RFbsSession::Disconnect();	

	delete tc;

	__UHEAP_MARKEND;
	
	return TestStepResult();
	}

void CTGraphicsStep::CloseAllPanicWindows(TInt aId, RWsSession& ws) const
	{
	TInt idFocus = ws.GetFocusWindowGroup();
	TWsEvent event;
	event.SetType(EEventKey); //EEventKeyDown
	TKeyEvent *keyEvent = event.Key();
	keyEvent->iCode = EKeyEscape;
	keyEvent->iScanCode = EStdKeyEscape;
	keyEvent->iModifiers = 0;
	TInt theLimit = 50;
	while(idFocus != aId && (theLimit-- > 0))
		{
		ws.SendEventToAllWindowGroups(event);
		idFocus = ws.GetFocusWindowGroup();
		}
	}
	
TInt CTGraphicsStep::GetScreenSize(TSize& aSize) const
	{
	CFbsScreenDevice* dev = NULL;
	
	TInt err = KErrNone;
	TInt sizeOfDisplayMode = sizeof (testDisplayModes) / sizeof(testDisplayModes[0]);
	 
	for(TInt theScreenModeIndex = sizeOfDisplayMode - 1; theScreenModeIndex ; theScreenModeIndex--)
		{
		TDisplayMode disp = testDisplayModes[theScreenModeIndex];
		TRAP(err, dev = CFbsScreenDevice::NewL(_L(""), disp)); //scdv
		if(err == KErrNone)
			{
			aSize = dev->SizeInPixels();
			delete dev;
			return KErrNone;
			}
		delete dev;
		dev = NULL;		
		}
	
	return err;		
	}

/** Installs an active scheduler and launches a test*/
void CTGraphicsStep::ExecuteL()
	{
	CActiveScheduler* theAs = new (ELeave) CActiveScheduler;
	CleanupStack::PushL(theAs);
	CActiveScheduler::Install(theAs);

	CTGraphicsBase*	autoTest = CreateTestL();
	User::LeaveIfNull(autoTest);
	CleanupStack::PushL(autoTest);

	autoTest -> InitializeL();
	autoTest -> ConstructL();
	autoTest -> Execute();

	CleanupStack::PopAndDestroy(2, theAs);
	}

TInt  E32Dll( )
	{
	return 0;
	}