os/graphics/egl/egltest/endpointtestsuite/automated/tsrc/egltest_endpoint_engine_execthread.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_execthread.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,465 @@
1.4 +// Copyright (c) 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 +#include "egltest_endpoint_engine_execthread.h"
1.20 +#include <hal.h>
1.21 +
1.22 +/*
1.23 + * This class forms the execution thread for running EGL commands.
1.24 + * This is primarily so that we can perform EglSwapBuffer (EContentUdpateCase)
1.25 + * BEFORE calling EglReleaseImageNOK on the remote end. Since EglSwapBuffer
1.26 + * does not complete until the EglReleaseImageNOK is called, we must have a
1.27 + * separate thread from the thread performing the table reading/controlling.
1.28 + *
1.29 + * Here's a summary of the classes/threads, and what role they play:
1.30 + * class CEgltest_Local_Engine
1.31 + * Controller for the execution of "engine" tables.
1.32 + *
1.33 + * This runs in the thread created by the TestExecute Framework itself
1.34 + *
1.35 + * It coordinates the Local and Remote execution of commands from
1.36 + * the table.
1.37 + *
1.38 + * When the command sequence switches from local to remote a "command" of
1.39 + * ESyncLocalCase is automatically inserted into the local command stream,
1.40 + * and the controller waits for the reply from this Sync before continuing
1.41 + * with the remote command. There is one exception: when the
1.42 + * EContentUpdateCase command is issued with ENoSync flag set, a sync is
1.43 + * sent BEFORE the EContentUpdateCase, but no further Sync is performed
1.44 + * until the remote thread is complete.
1.45 + *
1.46 + * The controller also creates a thread to monitor the controller itself
1.47 + * and the CEgltest_Local_Engine_Exec thread. See further comemnts in the
1.48 + * source of that class.
1.49 + *
1.50 + * class CEgltest_Local_Engine_Exec
1.51 + * Runs in a thread created by the CEgltest_Local_Engine thread.
1.52 + *
1.53 + * Performs the Actual "client" commands for the test-sequence. The reason
1.54 + * for a separate execution thread is outlined above. The reason ALL commands
1.55 + * must be executed in this thread is that certain EGL commands (e.g.
1.56 + * SwapBuffer) must be executed by a single thread.
1.57 + *
1.58 + * class CEgltest_Remote_Engine
1.59 + * Runs in a thread created by the Test Renderstage code.
1.60 + *
1.61 + * This thread performs the EglEndpointNOK specific calls. It also does
1.62 + * various image comparisons. All commands sent to this thread will be
1.63 + * synchronous with the controller execution - meaning that a remote
1.64 + * command will be finished by the time the next command in the controller
1.65 + * is issued.
1.66 + */
1.67 +
1.68 +const TInt KTerminated = 0xAABBCCDD;
1.69 +
1.70 +CEgltest_Local_Engine_Exec::CEgltest_Local_Engine_Exec()
1.71 + : iLogging(EFalse), iVerdict(EPass), iSurfaceTypeDisplayed(EFalse)
1.72 + {
1.73 + HAL::Get(HALData::EFastCounterFrequency, iFastFreq);
1.74 + }
1.75 +
1.76 +
1.77 +CEgltest_Local_Engine_Exec::~CEgltest_Local_Engine_Exec()
1.78 + {
1.79 + iParamsInQueue.Close();
1.80 + iResultOutQueue.Close();
1.81 + }
1.82 +
1.83 +
1.84 +CEgltest_Local_Engine_Exec* CEgltest_Local_Engine_Exec::NewL()
1.85 + {
1.86 + CEgltest_Local_Engine_Exec *self = new (ELeave) CEgltest_Local_Engine_Exec();
1.87 + CleanupStack::PushL(self);
1.88 + self->ConstructL();
1.89 + CleanupStack::Pop(self);
1.90 + return self;
1.91 + }
1.92 +
1.93 +void CEgltest_Local_Engine_Exec::ConstructL()
1.94 + {
1.95 + TInt err = iResultOutQueue.OpenGlobal(KExecResultQueueName, EOwnerThread);
1.96 + ENGINE_ASSERT(err == KErrNone);
1.97 + User::LeaveIfError(err);
1.98 + err = iParamsInQueue.OpenGlobal(KExecParamsQueueName, EOwnerThread);
1.99 + ENGINE_ASSERT(err == KErrNone);
1.100 + User::LeaveIfError(err);
1.101 + }
1.102 +
1.103 +TInt CEgltest_Local_Engine_Exec::ThreadEntry(TAny */* aDummy */)
1.104 + {
1.105 + CTrapCleanup *cleanUpStack = CTrapCleanup::New();
1.106 + if (!cleanUpStack)
1.107 + {
1.108 + // Can't use INFO_PRINTF here, as we have not yet
1.109 + // created the logger object - nor can we until we have
1.110 + // a working cleanupstack, so we just do our best at a
1.111 + // reason able error message.
1.112 + RDebug::Printf("Could not allocate memory for cleanupStack!");
1.113 + User::Panic(_L("ExecThread"), __LINE__);
1.114 + return KErrNoMemory;
1.115 + }
1.116 +
1.117 + TRAPD(err, ThreadEntryL());
1.118 + delete cleanUpStack;
1.119 + if (err != KErrNone)
1.120 + {
1.121 + RDebug::Printf("Thread left with err=%d", err);
1.122 + User::Panic(_L("ExecThread"), __LINE__);
1.123 + }
1.124 + return err;
1.125 + }
1.126 +
1.127 +
1.128 +void CEgltest_Local_Engine_Exec::ThreadEntryL()
1.129 + {
1.130 + CEgltest_Local_Engine_Exec *self = CEgltest_Local_Engine_Exec::NewL();
1.131 + CleanupStack::PushL(self);
1.132 + TInt err = KErrNone;
1.133 + TInt ret = 0;
1.134 + do {
1.135 + TRAP(err, ret = self->ThreadLoopL());
1.136 + if (err != KErrNone)
1.137 + {
1.138 + self->SetTestStepResult(EFail);
1.139 + RDebug::Printf("%s:%d: Leaving with %d", __FILE__, __LINE__, err);
1.140 + User::Leave(err);
1.141 + }
1.142 + self->Logger().Close();
1.143 + } while(ret != KTerminated);
1.144 + self->TidyUp();
1.145 + CleanupStack::PopAndDestroy(self);
1.146 + }
1.147 +
1.148 +
1.149 +// Initialize EGL, etc.
1.150 +void CEgltest_Local_Engine_Exec::SetUpL()
1.151 + {
1.152 + iDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
1.153 + EGLint err;
1.154 + if (iDisplay == EGL_NO_DISPLAY)
1.155 + {
1.156 + err = eglGetError();
1.157 + INFO_PRINTF2(_L("eglGetDisplay failed: err = %x"), err);
1.158 + User::Leave(KErrNotSupported);
1.159 + }
1.160 +
1.161 + if (!eglInitialize(iDisplay, NULL, NULL))
1.162 + {
1.163 + err = eglGetError();
1.164 + INFO_PRINTF2(_L("EglInitialize failed: err = %x"), err);
1.165 + User::Leave(KErrNotSupported);
1.166 + }
1.167 + }
1.168 +
1.169 +void CEgltest_Local_Engine_Exec::TidyUp()
1.170 + {
1.171 + // Clean up.
1.172 + iSurfaceTypeDisplayed = EFalse;
1.173 + for(TInt i = 0; i < KMaxEndpoints; i++)
1.174 + {
1.175 + if(iSurfaces[i])
1.176 + {
1.177 + delete iSurfaces[i];
1.178 + iSurfaces[i] = NULL;
1.179 + }
1.180 + }
1.181 + eglTerminate(iDisplay);
1.182 + eglReleaseThread();
1.183 + }
1.184 +
1.185 +void CEgltest_Local_Engine_Exec::SetTestStepResult(TVerdict aVerdict)
1.186 + {
1.187 + iVerdict = aVerdict;
1.188 + }
1.189 +
1.190 +TVerdict CEgltest_Local_Engine_Exec::TestStepResult() const
1.191 + {
1.192 + return iVerdict;
1.193 + }
1.194 +
1.195 +void CEgltest_Local_Engine_Exec::SendResult(const TExecResult &aResult)
1.196 + {
1.197 + iResultOutQueue.SendBlocking(aResult);
1.198 + }
1.199 +
1.200 +TInt CEgltest_Local_Engine_Exec::ThreadLoopL()
1.201 + {
1.202 + TBool testFinished = EFalse;
1.203 + TRemoteTestResult result;
1.204 +
1.205 + TEndpointUtil::SetLoggerForProcessWrapperL(iLogger);
1.206 + do
1.207 + {
1.208 + TRemoteTestParamsPacket params;
1.209 + iParamsInQueue.ReceiveBlocking(params);
1.210 +
1.211 + const TEngineTestCase& ec = params.iParams.iEndpointEngine.iEngineTestCase;
1.212 +
1.213 + TInt index = ec.iImageIndex;
1.214 + TInt endpointIndex = ec.iEndpointIndex;
1.215 +
1.216 + if (iLogging)
1.217 + {
1.218 + LogDump(Logger(), ec);
1.219 + }
1.220 +
1.221 + switch(ec.iCase)
1.222 + {
1.223 + case EInitializeCase:
1.224 + TidyUp();
1.225 + SetUpL();
1.226 + break;
1.227 +
1.228 + case ECreateSurfaceCase:
1.229 + {
1.230 + ENGINE_ASSERT(endpointIndex < KMaxEndpoints);
1.231 + ENGINE_ASSERT(!iSurfaces[endpointIndex]);
1.232 + TSurfaceType surfType = params.iParams.iEndpointEngine.iSurfaceParams.iSurfaceType;
1.233 + iSurfaces[endpointIndex] = CSurface::SurfaceFactoryL(surfType);
1.234 + TRAPD(err, iSurfaces[endpointIndex]->CreateL(index));
1.235 + if (err == KErrNone)
1.236 + {
1.237 + if (!iSurfaceTypeDisplayed)
1.238 + {
1.239 + INFO_PRINTF4(_L("Using surfaces of type %s (%dx%d pixels)"),
1.240 + iSurfaces[endpointIndex]->GetSurfaceTypeStr(),
1.241 + iSurfaces[endpointIndex]->Size().iWidth,
1.242 + iSurfaces[endpointIndex]->Size().iHeight);
1.243 + iSurfaceTypeDisplayed = ETrue;
1.244 + }
1.245 + }
1.246 + else
1.247 + {
1.248 + INFO_PRINTF2(_L("Could not create surface, err=%d"), err);
1.249 + delete iSurfaces[endpointIndex];
1.250 + iSurfaces[endpointIndex] = NULL;
1.251 + SetTestStepResult(EFail);
1.252 + }
1.253 + }
1.254 + break;
1.255 +
1.256 + case EDestroySurfaceCase:
1.257 + {
1.258 + delete iSurfaces[endpointIndex];
1.259 + iSurfaces[endpointIndex] = NULL;
1.260 + }
1.261 + break;
1.262 +
1.263 + case EContentUpdateCase:
1.264 + {
1.265 + TInt err;
1.266 + if (!iSurfaces[endpointIndex])
1.267 + {
1.268 + err = KErrNotSupported;
1.269 + }
1.270 + else
1.271 + {
1.272 + err = iSurfaces[endpointIndex]->SubmitContent(!(ec.iFlags & ENoWait), index);
1.273 + }
1.274 +
1.275 + if (err != KErrNone)
1.276 + {
1.277 + ERR_PRINTF2(_L("ContentUpdate failed, err=%d"), err);
1.278 + SetTestStepResult(EFail);
1.279 + }
1.280 + }
1.281 + break;
1.282 +
1.283 + case EDrawContentCase:
1.284 + if (iSurfaces[endpointIndex])
1.285 + {
1.286 + TRAPD(err, iSurfaces[endpointIndex]->DrawContentL(index % CTestImage::KImageCount));
1.287 + if (err != KErrNone)
1.288 + {
1.289 + SetTestStepResult(EFail);
1.290 + }
1.291 + }
1.292 + else
1.293 + {
1.294 + SetTestStepResult(EFail);
1.295 + }
1.296 + break;
1.297 +
1.298 + case EBufferCountCase:
1.299 + {
1.300 + TBool pass = ETrue;
1.301 + TSurfaceParamsRemote surfParams;
1.302 + TInt buffers = 0;
1.303 + TInt min = ec.iArg1;
1.304 + TInt max = ec.iArg2;
1.305 +
1.306 + if (!iSurfaces[endpointIndex])
1.307 + {
1.308 + pass = EFalse;
1.309 + }
1.310 + else
1.311 + {
1.312 + iSurfaces[endpointIndex]->GetSurfaceParamsL(surfParams);
1.313 + buffers = surfParams.iCommonParams.iBuffers;
1.314 + if (min && buffers < min)
1.315 + {
1.316 + pass = EFalse;
1.317 + }
1.318 + if (max && buffers > max)
1.319 + {
1.320 + pass = EFalse;
1.321 + }
1.322 + }
1.323 + if (!pass)
1.324 + {
1.325 + INFO_PRINTF4(_L("Surface has %d buffers, test expect [%d..%d] buffers (0 = 'any number') - Test ignored (pass)"),
1.326 + buffers, min, max);
1.327 + SendResult(TExecResult(EFail, EPass, ec.iCase));
1.328 + testFinished = ETrue;
1.329 + }
1.330 + else
1.331 + {
1.332 + SendResult(TExecResult(EPass, EPass, ec.iCase));
1.333 + }
1.334 + }
1.335 + break;
1.336 +
1.337 + case ENotifyWhenCase:
1.338 + {
1.339 + if (!iSurfaces[endpointIndex])
1.340 + {
1.341 + SetTestStepResult(EFail);
1.342 + }
1.343 + else
1.344 + {
1.345 + TInt err = iSurfaces[endpointIndex]->Notify((TNotification)index, iStatus[endpointIndex], ec.iArg1);
1.346 + if (err != ec.iErrorExpected)
1.347 + {
1.348 + ERR_PRINTF4(_L("Wrong error code from 'NotifyWhen' for notifiction %d - error %d, expected %d"),
1.349 + index, err, ec.iErrorExpected);
1.350 + SetTestStepResult(EFail);
1.351 + }
1.352 + }
1.353 + }
1.354 + break;
1.355 +
1.356 + case EWaitForCase:
1.357 + {
1.358 +#if defined (__WINS__)
1.359 + const TInt KDiffAllowed = 2500000; // Max 2500ms difference. Not realy testing anything.
1.360 +#else
1.361 + const TInt KDiffAllowed = 25000; // Max 25ms difference.
1.362 +#endif
1.363 + TUint32 beginTimeStamp = iTimeStamp[endpointIndex];
1.364 + TUint32 endTimeStamp = User::FastCounter();
1.365 + ENGINE_ASSERT(endpointIndex < KMaxEndpoints);
1.366 + if (!iSurfaces[endpointIndex])
1.367 + {
1.368 + SetTestStepResult(EFail);
1.369 + }
1.370 + else
1.371 + {
1.372 + TInt err = iSurfaces[endpointIndex]->WaitFor((TNotification)index,
1.373 + iStatus[endpointIndex], ec.iArg1, endTimeStamp);
1.374 +
1.375 + //Now, figure out the delta in microseconds.
1.376 + TUint32 deltaTime = endTimeStamp - beginTimeStamp;
1.377 + deltaTime *= 1000;
1.378 + deltaTime /= (iFastFreq / 1000);
1.379 +
1.380 + if (err != ec.iErrorExpected)
1.381 + {
1.382 + ERR_PRINTF4(_L("Wrong error code from 'WaitFor' for notifiction %d - error %d, expected %d"),
1.383 + index, err, ec.iErrorExpected);
1.384 + INFO_PRINTF5(_L("Timeout: %d, beginTimeStamp = %u, endTimeStamp = %u, deltaTime = %u"),
1.385 + ec.iArg1, beginTimeStamp, endTimeStamp, deltaTime);
1.386 + SetTestStepResult(EFail);
1.387 + }
1.388 + // If iArg2 is non-zero, and we waited for "displayed" and no error, check the timestamp.
1.389 + if (index == ENotifyWhenDisplayed && err == KErrNone && ec.iArg2)
1.390 + {
1.391 + if (Abs((TInt)deltaTime - ec.iArg2) > KDiffAllowed)
1.392 + {
1.393 + ERR_PRINTF3(_L("TimeStamp is incorrect - expected %d microseconds, got %d microseconds"),
1.394 + ec.iArg2, deltaTime);
1.395 + INFO_PRINTF4(_L("original timestamp: %u, endpoint ts=%u, iFastFreq=%u"),
1.396 + endTimeStamp, iTimeStamp[endpointIndex], iFastFreq);
1.397 + SetTestStepResult(EFail);
1.398 + }
1.399 + }
1.400 + }
1.401 + }
1.402 + break;
1.403 +
1.404 + case ETimeStampCase:
1.405 + iTimeStamp[endpointIndex] = User::FastCounter();
1.406 + break;
1.407 +
1.408 + case EFinishedCase:
1.409 + SendResult(TExecResult(TestStepResult(), ec.iCase));
1.410 + testFinished = ETrue;
1.411 + break;
1.412 +
1.413 + case EBreakPointCase:
1.414 + __BREAKPOINT();
1.415 + break;
1.416 +
1.417 + case ELogEnableCase:
1.418 + iLogging = ETrue;
1.419 + break;
1.420 +
1.421 + case ESyncLocalCase:
1.422 + {
1.423 + SendResult(TExecResult(TestStepResult(), ec.iCase));
1.424 + }
1.425 + break;
1.426 +
1.427 + case EGetSurfaceParamsCase:
1.428 + {
1.429 + TExecResult result(TestStepResult(), ec.iCase);
1.430 + if (iSurfaces[endpointIndex])
1.431 + {
1.432 + iSurfaces[endpointIndex]->GetSurfaceParamsL(result.iSurfaceParams);
1.433 + }
1.434 + SendResult(result);
1.435 + }
1.436 + break;
1.437 +
1.438 + case ETerminateCase:
1.439 + SendResult(TExecResult(TestStepResult(), ec.iCase));
1.440 + return KTerminated;
1.441 +
1.442 + case ESetVerdictCase:
1.443 + {
1.444 + SetTestStepResult(static_cast<TVerdict>(endpointIndex));
1.445 + TExecResult result(TestStepResult(), ec.iCase);
1.446 + SendResult(result);
1.447 + }
1.448 + break;
1.449 +
1.450 + case EPanicCase:
1.451 + // This part is intended to be used to test the implementation.
1.452 + // In normal tests, this functionality should not be used.
1.453 + // If anyone decides to use this for some purpose in normal
1.454 + // code, then please change the above comment to reflect
1.455 + // that it IS used, and explain why it makes sense.
1.456 + INFO_PRINTF1(_L("Performing intentional panic!"));
1.457 + User::Panic(_L("EPanicCase"), -1);
1.458 + break;
1.459 +
1.460 + default:
1.461 + ERR_PRINTF2(_L("Unknown case: %d"), ec.iCase);
1.462 + ENGINE_ASSERT(0);
1.463 + break;
1.464 + }
1.465 + }
1.466 + while(!testFinished);
1.467 + return KErrNone;
1.468 + }