os/graphics/egl/egltest/endpointtestsuite/automated/tsrc/egltest_endpoint_engine_local.cpp
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/graphics/egl/egltest/endpointtestsuite/automated/tsrc/egltest_endpoint_engine_local.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,515 @@
1.4 +// Copyright (c) 2009-2010 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +//
1.18 +
1.19 +/**
1.20 + @file
1.21 + @test
1.22 + @internalComponent - Internal Symbian test code
1.23 +*/
1.24 +
1.25 +#include <e32std.h>
1.26 +#include <e32math.h>
1.27 +#include "egltest_endpoint_engine.h"
1.28 +#include "egltest_endpoint_engine_execthread.h"
1.29 +
1.30 +
1.31 +TExecResult::TExecResult(void)
1.32 + {
1.33 + iVerdict = EInconclusive;
1.34 + Mem::FillZ(&iSurfaceParams, sizeof(iSurfaceParams));
1.35 + }
1.36 +
1.37 +TExecResult::TExecResult(TVerdict aVerdict, TEngineCases aCase)
1.38 + {
1.39 + iCase = aCase;
1.40 + iVerdict = aVerdict;
1.41 + }
1.42 +
1.43 +TExecResult::TExecResult(TVerdict aBufferCountVerdict, TVerdict aVerdict, TEngineCases aCase)
1.44 + {
1.45 + iCase = aCase;
1.46 + iBufferCountVerdict = aBufferCountVerdict;
1.47 + iVerdict = aVerdict;
1.48 + }
1.49 +
1.50 +CEgltest_Local_Engine::CEgltest_Local_Engine(const TTestCases *aTestCases, TInt aNumCases) :
1.51 + CLocalTestStepBase(ETestUidEndpointEngine),
1.52 + iTestCases(aTestCases),
1.53 + iNumCases(aNumCases)
1.54 + {
1.55 + }
1.56 +
1.57 +CEgltest_Local_Engine::CEgltest_Local_Engine() :
1.58 + CLocalTestStepBase(ETestUidEndpointEngine),
1.59 + iTestCases(NULL),
1.60 + iNumCases(0)
1.61 + {
1.62 + }
1.63 +
1.64 +
1.65 +CEgltest_Local_Engine::~CEgltest_Local_Engine()
1.66 + {
1.67 + }
1.68 +
1.69 +void CEgltest_Local_Engine::DoPreambleL()
1.70 + {
1.71 + //Register all of the test ids. Do this first so
1.72 + //that they get logged even if a panic occurs.
1.73 + const TTestCases* outerCases = iTestCases;
1.74 + TInt numOuterCases = iNumCases;
1.75 + for(TInt curOuterCase = 0; curOuterCase < numOuterCases; curOuterCase++)
1.76 + {
1.77 + const TTestCase* innerCases = outerCases[curOuterCase].iCase;
1.78 + TInt numInnerCases = outerCases[curOuterCase].iCount;
1.79 + for(TInt curInnerCase = 0; curInnerCase < numInnerCases; curInnerCase++)
1.80 + {
1.81 + TPtrC testIds(innerCases[curInnerCase].iBase.iRelatedTestIds);
1.82 + RegisterTestIdsL(testIds);
1.83 + }
1.84 + }
1.85 + CommonPreambleL();
1.86 + }
1.87 +
1.88 +void CEgltest_Local_Engine::CommonPreambleL()
1.89 + {
1.90 + // For details about the threads, see comment in the egltest_local_engine_exec.cpp
1.91 +
1.92 + // Amount of stack-space we allow for the execution thread.
1.93 + const TInt KStackSize = 12000;
1.94 + // Min/Max Heap Sizes
1.95 + const TInt KHeapMinSize = 16000;
1.96 + const TInt KHeapMaxSize = 1000000;
1.97 +
1.98 + // We don't need a very long queue length here. But it needs to be long enough
1.99 + // to handle a few outstanding requests. 10 seems like a good number.
1.100 + const TInt KMaxQueueLen = 10;
1.101 +
1.102 + TInt err = iExecParamsInQueue.CreateGlobal(KExecParamsQueueName, KMaxQueueLen, EOwnerThread);
1.103 + if (err != KErrNone)
1.104 + {
1.105 + INFO_PRINTF1(_L("Could not create message queue for Exec Thread parameters"));
1.106 + User::Leave(err);
1.107 + }
1.108 +
1.109 + err = iExecResultOutQueue.CreateGlobal(KExecResultQueueName, KMaxQueueLen, EOwnerThread);
1.110 + if (err != KErrNone)
1.111 + {
1.112 + INFO_PRINTF1(_L("Could not create message queue for Exec Thread results"));
1.113 + User::Leave(err);
1.114 + }
1.115 +
1.116 + // Copy the current thread so that we can use it in another thread.
1.117 + iControllerThread.Duplicate(RThread(), EOwnerProcess);
1.118 +
1.119 + //Set up for creating unique thread names.
1.120 + TUint32 random = Math::Random();
1.121 + TName threadName;
1.122 + _LIT(KThreadNameFormat, "%S-%u");
1.123 +
1.124 + // Creater a monitor thread. The monitor thread is used to keep track
1.125 + // of the controller (this) thread and the exec thread. If one panics
1.126 + // the monitor thread will ensure the other thread also panics.
1.127 + // The monitor thread shouldn't need much in the way of a heap, so
1.128 + // use min for both the min and max size of the heap.
1.129 + _LIT(KMonitorName, "EpTestLocalMonitor");
1.130 + threadName.Format(KThreadNameFormat, &KMonitorName, random);
1.131 + err = iMonitorThread.Create(threadName, CEgltest_Local_Engine::MonitorThreadEntry,
1.132 + KStackSize, KHeapMinSize, KHeapMinSize, this, EOwnerThread);
1.133 + if (err != KErrNone)
1.134 + {
1.135 + INFO_PRINTF1(_L("Could not create monitor thread"));
1.136 + User::Leave(err);
1.137 + }
1.138 + _LIT(KExecName, "EpTestLocalExec");
1.139 + threadName.Format(KThreadNameFormat, &KExecName, random);
1.140 + err = iExecThread.Create(threadName, CEgltest_Local_Engine_Exec::ThreadEntry,
1.141 + KStackSize, KHeapMinSize, KHeapMaxSize, NULL, EOwnerThread);
1.142 + if (err != KErrNone)
1.143 + {
1.144 + INFO_PRINTF1(_L("Could not create execution thread"));
1.145 + User::Leave(err);
1.146 + }
1.147 + TRequestStatus rendezvous;
1.148 + iMonitorThread.Rendezvous(rendezvous);
1.149 + iMonitorThread.Resume();
1.150 + // Make sure the monitor thread has logged onto the exec thread BEFORE
1.151 + // the exec thread gets to start. Otherwise, there is a small chance
1.152 + // the monitor thread will not have run by the time the exec (or this)
1.153 + // thread panics.
1.154 + User::WaitForRequest(rendezvous);
1.155 + iControllerThread.Close();
1.156 + iExecThread.Resume();
1.157 + }
1.158 +
1.159 +TInt CEgltest_Local_Engine::MonitorThreadEntry(TAny *aParam)
1.160 + {
1.161 + CEgltest_Local_Engine *self = reinterpret_cast<CEgltest_Local_Engine *>(aParam);
1.162 + self->DoMonitorThreadEntry();
1.163 + return 0;
1.164 + }
1.165 +
1.166 +// Forward a the panic from the controller to the exec thread or vice versa.
1.167 +void CEgltest_Local_Engine::DoMonitorThreadEntry()
1.168 + {
1.169 + //Duplicate the thread handles into this thread,
1.170 + //and keep them locally so they can't go out of scope.
1.171 + RThread execThread = iExecThread;
1.172 + execThread.Duplicate(iControllerThread, EOwnerThread);
1.173 + RThread controllerThread = iControllerThread;
1.174 + controllerThread.Duplicate(iControllerThread, EOwnerThread);
1.175 +
1.176 + //Logon to the two threads.
1.177 + TRequestStatus execStatus;
1.178 + TRequestStatus controllerStatus;
1.179 + execThread.Logon(execStatus);
1.180 + controllerThread.Logon(controllerStatus);
1.181 +
1.182 + //Rendevous with our parent then wait for either thread to exit.
1.183 + RThread().Rendezvous(KErrNone);
1.184 + User::WaitForRequest(execStatus, controllerStatus);
1.185 +
1.186 + //Forward the panic from the one thread to the other.
1.187 + //If a panic did occur, terminate EGL.
1.188 + if (execStatus != KRequestPending)
1.189 + {
1.190 + if(execThread.ExitType() == EExitPanic)
1.191 + {
1.192 + controllerThread.Panic(execThread.ExitCategory(), execThread.ExitReason());
1.193 + eglTerminate(eglGetDisplay(EGL_DEFAULT_DISPLAY));
1.194 + eglReleaseThread();
1.195 + }
1.196 + controllerThread.LogonCancel(controllerStatus);
1.197 + User::WaitForRequest(controllerStatus);
1.198 + }
1.199 + else if (controllerStatus != KRequestPending)
1.200 + {
1.201 + if(controllerThread.ExitType() == EExitPanic)
1.202 + {
1.203 + execThread.Panic(controllerThread.ExitCategory(), controllerThread.ExitReason());
1.204 + eglTerminate(eglGetDisplay(EGL_DEFAULT_DISPLAY));
1.205 + eglReleaseThread();
1.206 + }
1.207 + execThread.LogonCancel(execStatus);
1.208 + User::WaitForRequest(execStatus);
1.209 + }
1.210 +
1.211 + controllerThread.Close();
1.212 + execThread.Close();
1.213 + }
1.214 +
1.215 +// Tear down threads.
1.216 +void CEgltest_Local_Engine::DoPostambleL()
1.217 + {
1.218 + TRequestStatus status;
1.219 + iExecThread.Logon(status);
1.220 + RunLocalTestCase(ETerminateCase);
1.221 + User::WaitForRequest(status);
1.222 + iExecThread.Close();
1.223 + iMonitorThread.Close();
1.224 + iControllerThread.Close();
1.225 + iExecParamsInQueue.Close();
1.226 + iExecResultOutQueue.Close();
1.227 + }
1.228 +
1.229 +TVerdict CEgltest_Local_Engine::doTestStepL()
1.230 + {
1.231 + SetTestStepResult(EPass);
1.232 +
1.233 + INFO_PRINTF2(_L("Executing test with %d cases..."), iNumCases);
1.234 + for(TInt runCase = 0; runCase < iNumCases; runCase++)
1.235 + {
1.236 + RunTestCase(iTestCases[runCase]);
1.237 + }
1.238 + return TestStepResult();
1.239 + }
1.240 +
1.241 +void CEgltest_Local_Engine::RunTestCase(const TTestCases &aTestCases)
1.242 + {
1.243 + for(TInt testCase = 0; testCase < aTestCases.iCount; testCase++)
1.244 + {
1.245 + const TTestCase &thisCase = aTestCases.iCase[testCase];
1.246 +
1.247 + //Set the Ids of the test case as the current ones.
1.248 + TPtrC testIds(thisCase.iBase.iRelatedTestIds);
1.249 + SetCurrentTestIds(testIds);
1.250 +
1.251 + for(TInt surfIter= 0; surfIter < thisCase.iBase.iSurfaceTypeCount; surfIter++)
1.252 + {
1.253 + TSurfaceType surfType = thisCase.iBase.iSurfaceTypeList[surfIter];
1.254 +
1.255 + INFO_PRINTF3(_L("Running testcase GRAPHICS-EGL-%s: %s"),
1.256 + thisCase.iBase.iRelatedTestIds, thisCase.iBase.iName);
1.257 +
1.258 + RunOneTestCase(thisCase, surfType);
1.259 + }
1.260 + }
1.261 + }
1.262 +
1.263 +// Wait for a reply from the local execution thread.
1.264 +// All results have a verdict, and we check her to set it
1.265 +// if a "non-pass" result is returned.
1.266 +void CEgltest_Local_Engine::GetLocalResult(TExecResult &result, TEngineCases aCase)
1.267 + {
1.268 + iExecResultOutQueue.ReceiveBlocking(result);
1.269 + // Check verdict; but only change if it's the FIRST failure.
1.270 + if (result.iVerdict != EPass && TestStepResult() == EPass)
1.271 + {
1.272 + SetTestStepResult(result.iVerdict);
1.273 + }
1.274 + ENGINE_ASSERT(aCase == result.iCase);
1.275 + }
1.276 +
1.277 +TVerdict CEgltest_Local_Engine::RunRemoteTestCase(TInt aTestCase, const TRemoteTestParams& aMessageIn)
1.278 + {
1.279 + if (iExecState != EExecStateRemote)
1.280 + {
1.281 + DoSyncToLocal();
1.282 + iExecState = EExecStateRemote;
1.283 + }
1.284 + return CLocalTestStepBase::RunRemoteTestCase(aTestCase, aMessageIn);
1.285 + }
1.286 +
1.287 +// Send Sync command to Local execution thread, then
1.288 +// wait for the reply from that sync.
1.289 +void CEgltest_Local_Engine::DoSyncToLocal()
1.290 + {
1.291 + RunLocalTestCase(ESyncLocalCase);
1.292 + }
1.293 +
1.294 +
1.295 +// Send command to local exec thread.
1.296 +void CEgltest_Local_Engine::SendLocalTestCase(const TRemoteTestParams &aParams)
1.297 + {
1.298 + TRemoteTestParamsPacket message(iTestId, aParams.iEndpointEngine.iEngineTestCase.iCase, aParams);
1.299 +
1.300 + iExecParamsInQueue.SendBlocking(message);
1.301 + iExecState = EExecStateLocal;
1.302 + }
1.303 +
1.304 +// Send command to Local execution thread, then
1.305 +// wait for the reply from that command.
1.306 +void CEgltest_Local_Engine::RunLocalTestCase(const TRemoteTestParams& aMessageIn, TExecResult& aResult)
1.307 + {
1.308 + SendLocalTestCase(aMessageIn);
1.309 + GetLocalResult(aResult, aMessageIn.iEndpointEngine.iEngineTestCase.iCase);
1.310 + }
1.311 +
1.312 +// Wrapper for simple cases where we just want to send
1.313 +// the command with no arguments, and just get the
1.314 +// result for the purpose of syncing - so result
1.315 +// content is ignored.
1.316 +void CEgltest_Local_Engine::RunLocalTestCase(TEngineCases aCase)
1.317 + {
1.318 + TRemoteTestParams params = {};
1.319 + TExecResult result;
1.320 + params.iEndpointEngine.iEngineTestCase.iCase = aCase;
1.321 + RunLocalTestCase(params, result);
1.322 + }
1.323 +
1.324 +
1.325 +void CEgltest_Local_Engine::StartThreadL(TInt aThreadNumber)
1.326 + {
1.327 + INFO_PRINTF2(_L("Attempt to start thread %d using base-class StartThreadL"), aThreadNumber);
1.328 + User::Panic(_L("StartThreadL"), __LINE__);
1.329 + }
1.330 +
1.331 +
1.332 +void CEgltest_Local_Engine::EndThread(TInt aThreadNumber)
1.333 + {
1.334 + INFO_PRINTF2(_L("Attempt to end thread %d using base-class EndThread"), aThreadNumber);
1.335 + User::Panic(_L("EndThread"), __LINE__);
1.336 + }
1.337 +
1.338 +void CEgltest_Local_Engine::RunControllerLocalAndRemoteL(const TEngineTestCase& aCase, const TRemoteTestParams& aParams)
1.339 + {
1.340 + if (aCase.iFlags & EDebugController)
1.341 + {
1.342 + switch(aCase.iCase)
1.343 + {
1.344 + case EBreakPointCase:
1.345 + __BREAKPOINT();
1.346 + break;
1.347 + case ELogEnableCase:
1.348 + iLogging = ETrue;
1.349 + break;
1.350 + case EEndLoadThreadCase:
1.351 + EndThread(aCase.iEndpointIndex);
1.352 + break;
1.353 + case EStartLoadThreadCase:
1.354 + StartThreadL(aCase.iEndpointIndex);
1.355 + break;
1.356 + case EPanicCase:
1.357 + User::Panic(_L("EPanicCase"), -1);
1.358 + break;
1.359 + case ESetVerdictCase:
1.360 + SetTestStepResult(static_cast<TVerdict>(aCase.iEndpointIndex));
1.361 + break;
1.362 + default:
1.363 + ERR_PRINTF2(_L("Unrecognised case %d"), aCase.iCase);
1.364 + User::Panic(_L("BADCASE"), -2);
1.365 + break;
1.366 + }
1.367 + }
1.368 + if (aCase.iFlags & EDebugExecThread)
1.369 + {
1.370 + SendLocalTestCase(aParams);
1.371 + }
1.372 + if (aCase.iFlags & EDebugRemote)
1.373 + {
1.374 + RunRemoteTestCase(aCase.iCase, aParams);
1.375 + }
1.376 + }
1.377 +
1.378 +
1.379 +// This function runs one set of table entries for one surface type.
1.380 +void CEgltest_Local_Engine::RunSingleCaseL(const TTestCase& aTestCase, TSurfaceType aSurfType)
1.381 + {
1.382 + const TTestCase& cs = aTestCase;
1.383 +
1.384 + TRemoteTestParams params;
1.385 + TExecResult result;
1.386 +
1.387 + for(TInt j = 0; cs.iEngineTestCase[j].iCase != EFinishedCase; j++)
1.388 + {
1.389 + const TEngineTestCase& ec = cs.iEngineTestCase[j];
1.390 + params.iEndpointEngine.iEngineTestCase = ec;
1.391 + params.iEndpointEngine.iSurfaceParams.iSurfaceType = aSurfType;
1.392 +
1.393 + if (iLogging)
1.394 + {
1.395 + LogDump(Logger(), ec);
1.396 + }
1.397 +
1.398 + switch(ec.iCase)
1.399 + {
1.400 + // Work done locally.
1.401 + case ECreateSurfaceCase:
1.402 + case EDestroySurfaceCase:
1.403 + case EDrawContentCase:
1.404 + case ENotifyWhenCase:
1.405 + case EWaitForCase:
1.406 + case ETimeStampCase:
1.407 + SendLocalTestCase(params);
1.408 + break;
1.409 +
1.410 + // Special case:
1.411 + case EContentUpdateCase:
1.412 + if (ec.iFlags & ENoSync)
1.413 + {
1.414 + // We sync here to make sure local commands sent
1.415 + // BEFORE the ContentUpdate have completed!
1.416 + DoSyncToLocal();
1.417 + }
1.418 + SendLocalTestCase(params);
1.419 + if (ec.iFlags & ENoSync)
1.420 + {
1.421 + // Delay an arbitrary amount to allow SUS
1.422 + // to receive the update!
1.423 + User::After(300 * 1000); // 300 ms.
1.424 + iExecState = EExecStateRemote;
1.425 + }
1.426 + break;
1.427 +
1.428 + case EBufferCountCase:
1.429 + RunLocalTestCase(params, result);
1.430 + if (result.iBufferCountVerdict == EFail)
1.431 + {
1.432 + RunRemoteTestCase(ETerminateCase, params);
1.433 + }
1.434 + break;
1.435 +
1.436 + // These commands are all sent to the remote side.
1.437 + // By definition, they are synchronous, as the RunRemoteTestCase
1.438 + // waits for a reply from the remote side before returning.
1.439 + case EAcquireImageCase:
1.440 + case EEndStreamingCase:
1.441 + case EReleaseImageCase:
1.442 + case EDestroyEndpointCase:
1.443 + case EBeginStreamingCase:
1.444 + case ETerminateCase:
1.445 + case EGetAttribCase:
1.446 + case ESetAttribCase:
1.447 + case ECompareImageCase:
1.448 + case ECreateVgImageCase:
1.449 + case EDestroyVgImageCase:
1.450 + case EDestroyEglImageCase:
1.451 + case ETestVgImageValidCase:
1.452 + case ERequestNotificationCase:
1.453 + case ECancelNotificationCase:
1.454 + case EWaitForNotificationCase:
1.455 + case EGetEndpointDirtyAreaCase:
1.456 + case ECheckForMemoryLeaks:
1.457 + case ECheckForMemoryLeaksFinish:
1.458 + case ESpecialEglHeapCase:
1.459 + RunRemoteTestCase(ec.iCase, params);
1.460 + break;
1.461 +
1.462 + // Special case: Need surface parameters filled in first.
1.463 + case ECreateEndpointCase:
1.464 + {
1.465 + // Copy parameters.
1.466 + TRemoteTestParams tempParams = params;
1.467 + tempParams.iEndpointEngine.iEngineTestCase.iCase = EGetSurfaceParamsCase;
1.468 + RunLocalTestCase(tempParams, result);
1.469 + params.iEndpointEngine.iSurfaceParams = result.iSurfaceParams;
1.470 +
1.471 + // The above code syncs the execution so no need to sync again!
1.472 + iExecState = EExecStateRemote;
1.473 + RunRemoteTestCase(ec.iCase, params);
1.474 + }
1.475 + break;
1.476 +
1.477 + case EInitializeCase:
1.478 + SendLocalTestCase(params);
1.479 + RunRemoteTestCase(ec.iCase, params);
1.480 + break;
1.481 +
1.482 +
1.483 + // These commands are controlled by the EDebugXXX flags
1.484 + // They may go to this thread, the exectrhead or the remote RS.
1.485 + case EStartLoadThreadCase:
1.486 + case EEndLoadThreadCase:
1.487 + case ELogEnableCase:
1.488 + case EBreakPointCase:
1.489 + case EPanicCase:
1.490 + case ESetVerdictCase:
1.491 + RunControllerLocalAndRemoteL(ec, params);
1.492 + break;
1.493 +
1.494 + default:
1.495 + ERR_PRINTF2(_L("Unknown case: %d"), ec.iCase);
1.496 + SetTestStepResult(EFail);
1.497 + break;
1.498 + }
1.499 + }
1.500 + // Tell local execution thread we are finished.
1.501 + RunLocalTestCase(EFinishedCase);
1.502 + }
1.503 +
1.504 +void CEgltest_Local_Engine::RunOneTestCase(const TTestCase& aTestCase, TSurfaceType aSurfType)
1.505 + {
1.506 + TRemoteTestParams nullParams = {};
1.507 + nullParams.iEndpointEngineConfig.iLogErrors = ETrue;
1.508 +
1.509 + StartRemoteTestStep(nullParams);
1.510 +
1.511 + TRAPD(err, RunSingleCaseL(aTestCase, aSurfType));
1.512 + if (err != KErrNone)
1.513 + {
1.514 + INFO_PRINTF2(_L("RunSingleCaseL left with an error: %d"), err);
1.515 + }
1.516 +
1.517 + EndRemoteTestStep(nullParams);
1.518 + }