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) 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
@test
@internalComponent - Internal Symbian test code
*/
#include "tmultiptreventhandlingperf.h"
#include <hal.h>
_LIT(KPerformanceTimingChunk, "PerformanceTimingChunk");
// Number of iterations for eventset
const TInt KNumOfIterations = 100;
// Maximum descriptor length for results
const TInt KMaxDescLength = 528;
// Static variables used for synchronisation between threads
GLDEF_D TInt NumOfEventsAdded = 0;
GLDEF_D RMutex Mutex;
GLDEF_D RCondVar ConVar;
void MultiPtrPerfPanic(TInt aPanic)
{
User::Panic(_L("MultiPterEventHanldingPerformancePanic"), aPanic);
}
// This function opens the chunk and adds the failure description followed by '*'
TInt CMultiPtrPerfTestControl::Failed(TPoint3D aExp3DPoint, TPoint3D aActual3DPoint, TInt aErrorCode, TInt aExpPtrNum, TInt aActPtrNum)
{
TInt ret = iChunk.OpenGlobal(KPerformanceTimingChunk, ETrue);
if (ret != KErrNone)
{
return ret;
}
TUint8* desPtr = iChunk.Base() + iChunkOffset;
TPtr8 ptrDes(desPtr, 0, KMaxDescLength);
TBuf<80> buf;
if (aExpPtrNum != aActPtrNum)
{
_LIT(KFailedPointerNum, "Failed Expected Pointer Num = %d Actual Pointer Num = %d*");
buf.AppendFormat(KFailedPointerNum, aExpPtrNum, aActPtrNum);
ptrDes.Append(buf);
}
else if (aErrorCode != KErrNone)
{
_LIT(KFailedErrorCode, "Failed Errorcode = %d*");
buf.AppendFormat(KFailedErrorCode, aErrorCode);
ptrDes.Append(buf);
}
else
{
_LIT(KFailedWrongCoord, "Failed Coordinates Expected = [%d, %d, %d] Actual = [%d, %d, %d]*");
buf.AppendFormat(KFailedWrongCoord, aExp3DPoint.iX, aExp3DPoint.iY, aExp3DPoint.iZ, aActual3DPoint.iX, aActual3DPoint.iY, aActual3DPoint.iZ);
ptrDes.Append(buf);
}
iChunk.Close();
return ret;
}
// This function opens the chunk and adds a pointer event not supported message followed by '#'
TInt CMultiPtrPerfTestControl::PointerEventsNotSupported()
{
iPointerEventNotSupported = ETrue;
TInt ret = iChunk.OpenGlobal(KPerformanceTimingChunk, ETrue);
if (ret != KErrNone)
{
return ret;
}
TUint8* desPtr = iChunk.Base() + iChunkOffset;
TPtr8 ptrDes(desPtr, 0, KMaxDescLength);
TBuf<80> buf;
_LIT(KPointerEventsNotSupported, "Test Skipped As Pointer Events Are Not Supported By This Configuration#");
buf.AppendFormat(KPointerEventsNotSupported);
ptrDes.Append(buf);
iChunk.Close();
return ret;
}
// This function calulates the average latency, opens the chunk and appends
// the same in descriptor form. Then close the child thread and calls function
// for creating new thread for events.
// If all the events have been tested then stops the tests
// by calling active CActiveScheduler::Stop.
TInt CMultiPtrPerfTestControl::CalculateLatencyAndStartThread()
{
TInt ret = KErrNone;
switch (iPtrAppUi->TestCaseNum())
{
case 1:
case 5:
case 9:
case 13:
iAverageLatency = iLatency/(4*KNumOfIterations);
break;
case 2:
case 6:
case 10:
case 14:
iAverageLatency = iLatency/(8*KNumOfIterations);
break;
case 3:
case 7:
case 11:
case 15:
iAverageLatency = iLatency/(16*KNumOfIterations);
break;
case 4:
case 8:
case 12:
case 16:
iAverageLatency = iLatency/(32*KNumOfIterations);
break;
default:
MultiPtrPerfPanic(EMultiPtrPerfPanicWrongTest);
}
ret = iChunk.OpenGlobal(KPerformanceTimingChunk, ETrue);
if (ret != KErrNone)
{
return ret;
}
TUint8* desPtr = iChunk.Base() + iChunkOffset;
TPtr8 ptrDes(desPtr, iLatLenInLetters, KMaxDescLength);
TBuf<66> buf;
buf.Num(iAverageLatency);
buf.Append(',');
ptrDes.Append(buf);
// reset the iLatency for next set of test
iLatency = 0;
// For writing the next latency in chunk memory
iLatLenInLetters = ptrDes.Length();
iChunk.Close();
// Before calling the thread Function close the current thread and then call the function
// here when we kill the child thread it releases both mutex and condvar that it holds
iPtrAppUi->ChildThread().Kill(KErrNone);
iPtrAppUi->ChildThread().Close();
if (iPtrAppUi->TestCaseNum() == 16)
{
// It it is the last test case then stop the active scheduler
CActiveScheduler::Stop();
return ret;
}
else
{
return iPtrAppUi->CreateEventSimulatingThreads();
}
}
// This function is called by Cone whenever a event is outstanding
// Here we check if the sent event is same as the expected event in array.
// Then resumes the thread for next set of events. When all the events are completed
// calls CalculateLatencyAndStartThread
void CMultiPtrPerfTestControl::HandlePointerEventL(const TPointerEvent& aPointerEvent)
{
ASSERT(!iPointerEventNotSupported);
// The event that is received is (0,0,0) then it is the first event that the test code is sending
const TAdvancedPointerEvent* advancedPointerEvent = aPointerEvent.AdvancedPointerEvent();
if (iPtrAppUi->TestCaseNum() == 0)
{
if (advancedPointerEvent->PointerNumber() == 0 && advancedPointerEvent->Position3D() == TPoint3D())
{
iPtrAppUi->CreateEventSimulatingThreads();
return;
}
else
{
return; // ignore other events before starting the tests
}
}
// Get the current time.
// Subtract from the test start time.
TTime currentTime;
currentTime.UniversalTime();
TInt64 curTime64 = currentTime.Int64();
TInt timeSinceTestStart = curTime64 - iPtrAppUi->TestStartTime();
// Get the event, get the time stored in Z corodinate
// Then subtract the calculated time from Z coordinate
iLatency += timeSinceTestStart - advancedPointerEvent->ProximityAndPressure();
// Get the current event from buffer and compare it with got event
TAdvancedPointerEvent expectedPtrEvent;
if(0 == iEventBuffer.Remove(&expectedPtrEvent))
{
iPtrAppUi->Failed(TPoint3D(), TPoint3D(), KErrNotFound);
return;
}
// Here Z corodinate is not checked.
if (expectedPtrEvent.iPosition != advancedPointerEvent->iPosition)
{
iPtrAppUi->Failed(expectedPtrEvent.Position3D(), advancedPointerEvent->Position3D(), KErrNone);
return;
}
if (expectedPtrEvent.PointerNumber() != advancedPointerEvent->PointerNumber())
{
iPtrAppUi->Failed(TPoint3D(), TPoint3D(), KErrNone, expectedPtrEvent.PointerNumber(), advancedPointerEvent->PointerNumber());
return;
}
iPtrAppUi->DecrementEventCount();
NumOfEventsAdded--;
// Event count is zero when all the events have been tested
if (iPtrAppUi->EventCount() == 0)
{
TInt ret = CalculateLatencyAndStartThread();
if (ret != KErrNone)
{
iPtrAppUi->Failed(TPoint3D(), TPoint3D(), ret);
return;
}
}
else if (NumOfEventsAdded == 0)
{
ConVar.Signal();
}
}
void CMultiPtrPerfTestControl::AddExpectedEvent(TAdvancedPointerEvent& aExpEvent)
{
iEventBuffer.Add(&aExpEvent);
}
CMultiPtrPerfTestControl::~CMultiPtrPerfTestControl()
{
iChunk.Close();
}
void CMultiPtrPerfTestControl::ConstructL()
{
iPointerEventNotSupported = EFalse;
ConstructL(TPoint(), ControlEnv()->ScreenDevice()->SizeInPixels());
}
void CMultiPtrPerfTestControl::ConstructL(TPoint aOrigin, TSize aSize)
{
iEventBuffer.SetLengthL(EEventBufferSize);
iPtrAppUi = static_cast<CMultiPtrPerfTestAppUi*>(ControlEnv()->AppUi());
CreateWindowL();
Window().EnableAdvancedPointers();
EnableDragEvents();
SetExtent(aOrigin, aSize);
ActivateL();
// Get the cmdline argument of this process in descriptor
// convert the descriptor to number and store it in iChunkOffset
TBuf<128> buf;
User::CommandLine(buf);
TLex lex(buf);
User::LeaveIfError(lex.Val(iChunkOffset));
}
// This function gets the current time and subtracts it from the time when the whole test was started.
// Simulates the event and suspends the thread if aWaitAfterEachEvent is ETrue
// If aWaitAfterEachEvent is EFalse then it suspends the thread after each set of event i,e after 4, 8, 16 and 32 events
void SimulatePointerEvents(TInt aCount, CMultiPtrPerfTestAppUi* appUi, TBool aMultiPtrEvent = EFalse, TBool aWaitAfterEachEvent = ETrue)
{
TRawEvent rawEvent;
TPoint ptrPos;
TTime currentTime;
TInt64 testStartTime = appUi->TestStartTime();
TInt ptrNum = 0;
TInt ptrMax = 0;
// HAL as already been tested at the start of these tests. So no need to test once again
HAL::Get(HALData::EPointerNumberOfPointers, ptrMax);
appUi->SetNumberOfEvents((KNumOfIterations*aCount)-1);
// For testing time taken for each event and for each set of events we make use of RMutex and RConvar.
// RMutex is used not to preempt this thread until events has been added
// RConVar is used to hold this thread until the events have been tested
for (TInt loop = 0; loop < KNumOfIterations; loop++)
{
ptrNum = 0;
ptrPos.iX = ptrPos.iY = 0;
Mutex.Wait();
for (TInt count = 0; count < aCount/2; count++, ptrNum++)
{
if (ptrNum >= ptrMax)
{
ptrNum = 0;
}
ptrPos.iX += 2;
ptrPos.iY += 1;
TWsEvent event;
event.InitAdvancedPointerEvent(TPointerEvent::EButton1Down, 0, TPoint3D(ptrPos.iX, ptrPos.iY, 0), (aMultiPtrEvent ? ptrNum : 0));
appUi->AddExpectedEvent(*event.Pointer());
currentTime.UniversalTime();
TInt64 curTime64 = currentTime.Int64();
TInt timeSinceTestStart = curTime64 - testStartTime;
rawEvent.Set(TRawEvent::EButton1Down, ptrPos.iX, ptrPos.iY, timeSinceTestStart, (aMultiPtrEvent ? ptrNum : 0));
UserSvr::AddEvent(rawEvent);
NumOfEventsAdded++;
if (aWaitAfterEachEvent)
{
while(NumOfEventsAdded)
ConVar.Wait(Mutex);
}
event.InitAdvancedPointerEvent(TPointerEvent::EButton1Up, 0, TPoint3D(ptrPos.iX, ptrPos.iY, 0), (aMultiPtrEvent ? ptrNum : 0));
appUi->AddExpectedEvent(*event.Pointer());
currentTime.UniversalTime();
curTime64 = currentTime.Int64();
timeSinceTestStart = curTime64 - testStartTime;
rawEvent.Set(TRawEvent::EButton1Up, ptrPos.iX, ptrPos.iY, timeSinceTestStart, (aMultiPtrEvent ? ptrNum : 0));
UserSvr::AddEvent(rawEvent);
NumOfEventsAdded++;
if (aWaitAfterEachEvent)
{
while(NumOfEventsAdded)
ConVar.Wait(Mutex);
}
}
if (!aWaitAfterEachEvent)
{
while(NumOfEventsAdded)
ConVar.Wait(Mutex);
}
Mutex.Signal();
}
}
TInt EventSimulatingThreadStartFunc(TAny* aAny)
{
CMultiPtrPerfTestAppUi* appUi = static_cast<CMultiPtrPerfTestAppUi*>(aAny);
switch(appUi->TestCaseNum()++)
{
case 0:
SimulatePointerEvents(4, appUi);
break;
case 1:
SimulatePointerEvents(8, appUi);
break;
case 2:
SimulatePointerEvents(16, appUi);
break;
case 3:
SimulatePointerEvents(32, appUi);
break;
case 4:
SimulatePointerEvents(4, appUi, ETrue);
break;
case 5:
SimulatePointerEvents(8, appUi, ETrue);
break;
case 6:
SimulatePointerEvents(16, appUi, ETrue);
break;
case 7:
SimulatePointerEvents(32, appUi, ETrue);
break;
case 8:
SimulatePointerEvents(4, appUi, EFalse, EFalse);
break;
case 9:
SimulatePointerEvents(8, appUi, EFalse, EFalse);
break;
case 10:
SimulatePointerEvents(16, appUi, EFalse, EFalse);
break;
case 11:
SimulatePointerEvents(32, appUi, EFalse, EFalse);
break;
case 12:
SimulatePointerEvents(4, appUi, ETrue, EFalse);
break;
case 13:
SimulatePointerEvents(8, appUi, ETrue, EFalse);
break;
case 14:
SimulatePointerEvents(16, appUi, ETrue, EFalse);
break;
case 15:
SimulatePointerEvents(32, appUi, ETrue, EFalse);
break;
default:
break;
}
return KErrNone;
}
TInt CMultiPtrPerfTestAppUi::CreateEventSimulatingThreads()
{
// Depending upon the iTestCase number create thread and simulate events in that thread function
TInt ret = KErrNone;
_LIT(KSimulateEventsThread, "Events simulating thread");
ret = iThread.Create(KSimulateEventsThread, EventSimulatingThreadStartFunc, KDefaultStackSize, 0x4000, 0x4000, this, EOwnerThread);
if (ret == KErrNone)
{
iThread.Resume();
}
return ret;
}
void CMultiPtrPerfTestAppUi::AddExpectedEvent(TAdvancedPointerEvent& aExpEvent)
{
iControl->AddExpectedEvent(aExpEvent);
}
void CMultiPtrPerfTestAppUi::Failed(TPoint3D aExp3DPoint, TPoint3D aActual3DPoint, TInt aErrorCode, TInt aExpPtrNum, TInt aActPtrNum)
{
// Write error description in the memory of shared chunk
// so that the main performance test just stops by saying that it failed
// and then stop the active scheduler.
iControl->Failed(aExp3DPoint, aActual3DPoint, aErrorCode, aExpPtrNum, aActPtrNum);
CActiveScheduler::Stop();
}
void CMultiPtrPerfTestAppUi::PointerEventsNotSupported()
{
// Write a pointer events not supported message in the memory of shared chunk
// so that the main performance test just skips the pointer test
iControl->PointerEventsNotSupported();
}
CMultiPtrPerfTestAppUi::CMultiPtrPerfTestAppUi()
{
}
CMultiPtrPerfTestAppUi::~CMultiPtrPerfTestAppUi()
{
RemoveFromStack(iControl);
delete iControl;
}
void CMultiPtrPerfTestAppUi::ConstructL()
{
CCoeAppUi::ConstructL();
TTime testStartTime;
testStartTime.UniversalTime();
iTestStartTime = testStartTime.Int64();
iControl = new (ELeave) CMultiPtrPerfTestControl();
iControl->ConstructL();
AddToStackL(iControl);
}
void ConstructControlEnvironmentL(CCoeEnv* aCoe)
{
aCoe->ConstructL();
CMultiPtrPerfTestAppUi* appUi=new(ELeave) CMultiPtrPerfTestAppUi();
CleanupStack::PushL(appUi); // If it leaves after this then there is no way of deleting the appui
aCoe->SetAppUi(appUi); // So pushed it on to cleanup stack
aCoe->WsSession().SetAutoFlush(ETrue);
appUi->ConstructL();
User::LeaveIfError(Mutex.CreateLocal(EOwnerProcess));
User::LeaveIfError(ConVar.CreateLocal(EOwnerProcess));
CleanupStack::Pop(appUi);
}
GLDEF_C TInt E32Main()
{
__UHEAP_MARK;
CCoeEnv* coe = new CCoeEnv;
if (!coe)
{
return KErrNoMemory;
}
TRAPD(err, ConstructControlEnvironmentL(coe));
if (err != KErrNone)
{
delete coe;
}
else // If KErrNone then no need to delte coe as it is taken care by ConEnv
{
// Check whether the configuration supports pointer events.
// If it dosn't support pointer events then the pointer cursor area will be empty,
// in this case skip the test and inform the test framework that the test has been skipped
TRect pointerCursorArea = coe->WsSession().PointerCursorArea();
if(pointerCursorArea.IsEmpty())
{
RDebug::Printf("PointerCursorArea is Empty");
CMultiPtrPerfTestAppUi* appUi = static_cast<CMultiPtrPerfTestAppUi*>(coe->AppUi());
appUi->PointerEventsNotSupported();
}
else
{
// First event which starts the test from HandlePointerEventL
TRawEvent rawEvent;
rawEvent.Set(TRawEvent::EButton1Down, 0, 0, 0, 0);
UserSvr::AddEvent(rawEvent);
coe->ExecuteD();
}
Mutex.Close();
ConVar.Close();
}
__UHEAP_MARKEND;
return err;
}