egl/egltest/endpointtestsuite/automated/tsrc/egltest_threadedstress_remote.cpp
changeset 136 62bb7c97884c
equal deleted inserted replaced
121:d72fc2aace31 136:62bb7c97884c
       
     1 // Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 
       
    13 
       
    14 /**
       
    15  @file
       
    16  @test
       
    17  @internalComponent - Internal Symbian test code
       
    18 */
       
    19 
       
    20 
       
    21 #include "egltest_threadedstress.h"
       
    22 #include "eglendpointwrap.h"
       
    23 #include "egltest_endpoint_images.h"
       
    24 #include "egltest_threadmonitor.h"
       
    25 #include <e32atomics.h>
       
    26 #include "egltest_endpoint_images.h"
       
    27 #include <e32math.h>
       
    28 
       
    29 
       
    30 //Private Helper Class Declarations-----------------------------------------------
       
    31 
       
    32 class CTightLoopThread : public CBase, public MLog
       
    33     {
       
    34 public:
       
    35     ~CTightLoopThread();
       
    36     
       
    37     //Control the loop from the controlling thread. 
       
    38     //Calling Start() more than once causes panic.
       
    39     void Start();
       
    40     TRemoteTestVerdict Stop();
       
    41     TThreadId ThreadId() const;
       
    42     
       
    43 protected:
       
    44     CTightLoopThread();
       
    45     void ConstructL(TBool aSharedHeap);
       
    46     MLog& Logger() const;
       
    47     void Log(const TText8* aFile, TInt aLine, TInt aSeverity, TRefByValue<const TDesC> aFmt, ...);
       
    48     
       
    49     //To be implemented by derived class.
       
    50     virtual void SetupInThreadContextL() = 0;
       
    51     virtual void TeardownInThreadContextL() = 0;
       
    52     virtual TBool ExecuteInnerLoopBody() = 0;
       
    53     
       
    54 private:
       
    55     static TInt ThreadEntryPoint(TAny* aSelf);
       
    56     void EnterThreadLoopL();
       
    57 
       
    58 private:
       
    59     RThread iThread;
       
    60     TRequestStatus iNotifyStart;
       
    61     volatile TBool iNotifyStop;
       
    62     TBool iHasBeenStarted;
       
    63     TBool iHasBeenStopped;
       
    64     };
       
    65 
       
    66 
       
    67 class CEndpointExercise : public CTightLoopThread
       
    68     {
       
    69 public:
       
    70     static CEndpointExercise* NewL(TBool aSharedHeap);
       
    71     ~CEndpointExercise();
       
    72     
       
    73     void SetupInThreadContextL();
       
    74     void TeardownInThreadContextL();
       
    75     TBool ExecuteInnerLoopBody();
       
    76     
       
    77 private:
       
    78     CEndpointExercise();
       
    79     void ConstructL(TBool aSharedHeap);
       
    80     void ExecuteInnerLoopBodyL();
       
    81     TInt CheckImage(EGLImageKHR aEglImage);
       
    82     
       
    83     //Logging helpers.
       
    84     void PanicIfError(TInt aError, const TText8* aFile, TInt aLine) const;
       
    85     void PanicIfFalse(TBool aBool, const TText8* aFile, TInt aLine) const;
       
    86     void LogAndLeaveIfErrorL(TInt aError, const TText8* aFile, TInt aLine) const;
       
    87     void LogAndLeaveIfFalseL(TBool aBool, const TText8* aFile, TInt aLine) const;
       
    88     #define PANIC_IF_ERROR(ERROR)           PanicIfError((ERROR), (TText8*)__FILE__, __LINE__)
       
    89     #define PANIC_IF_FALSE(BOOL)            PanicIfFalse((BOOL), (TText8*)__FILE__, __LINE__)
       
    90     #define LOG_AND_LEAVE_IF_ERROR_L(ERROR) LogAndLeaveIfErrorL((ERROR), (TText8*)__FILE__, __LINE__)
       
    91     #define LOG_AND_LEAVE_IF_FALSE_L(BOOL)  LogAndLeaveIfFalseL((BOOL), (TText8*)__FILE__, __LINE__)
       
    92 
       
    93 private:
       
    94     TInt iIteration;
       
    95     TInt iCurrentColour;
       
    96     RSurfaceManager iSurfaceManager;
       
    97     RSurfaceUpdateSession iSurfaceUpdate;
       
    98     RSurfaceManager::TSurfaceCreationAttributesBuf iSurfaceAttribs;
       
    99     EGLDisplay iDisplay;
       
   100     TEglEndpointWrap iEglEp;
       
   101     CEglWindowSurface* iDummyWindowSurface;
       
   102     };
       
   103 
       
   104 //--------------------------------------------------------------------------------
       
   105 
       
   106 
       
   107 //Cleanup Items used through out tests--------------------------------------------
       
   108 
       
   109 struct TCleanupSurface
       
   110     {
       
   111     RSurfaceManager* iSurfaceManager;
       
   112     TSurfaceId iSurfaceId;
       
   113     };
       
   114 static void CleanupSurface(TAny* aCleanupSurface)
       
   115     {
       
   116     TCleanupSurface* surface = static_cast<TCleanupSurface*>(aCleanupSurface);
       
   117     TInt err = surface->iSurfaceManager->CloseSurface(surface->iSurfaceId);
       
   118     ASSERT(err == KErrNone);
       
   119     }
       
   120 
       
   121 
       
   122 struct TCleanupEndpoint
       
   123     {
       
   124     EGLDisplay iDisplay;
       
   125     EGLEndpointNOK iEndpoint;
       
   126     };
       
   127 static void CleanupEndpoint(TAny* aCleanupEndpoint)
       
   128     {
       
   129     TCleanupEndpoint* endpoint = static_cast<TCleanupEndpoint*>(aCleanupEndpoint);
       
   130     TEglEndpointWrap ep;
       
   131     ASSERT(ep.Error() == KErrNone);
       
   132     EGLBoolean err = ep.DestroyEndpoint(endpoint->iDisplay, endpoint->iEndpoint);
       
   133     ASSERT(err);
       
   134     }
       
   135 
       
   136 
       
   137 struct TCleanupImage
       
   138     {
       
   139     EGLDisplay iDisplay;
       
   140     EGLEndpointNOK iEndpoint;
       
   141     EGLImageKHR iImage;
       
   142     };
       
   143 static void CleanupImage(TAny* aCleanupImage)
       
   144     {
       
   145     TCleanupImage* image = static_cast<TCleanupImage*>(aCleanupImage);
       
   146     TEglEndpointWrap ep;
       
   147     ASSERT(ep.Error() == KErrNone);
       
   148     EGLBoolean err = ep.ReleaseImage(image->iDisplay, image->iEndpoint, image->iImage, EGL_NONE);
       
   149     ASSERT(err);
       
   150     }
       
   151 
       
   152 
       
   153 static void CleanupPointerArray(TAny* aPointerArray)
       
   154     {
       
   155     RPointerArray<CEndpointExercise>* array = static_cast<RPointerArray<CEndpointExercise>*>(aPointerArray);
       
   156     array->ResetAndDestroy();
       
   157     }
       
   158 
       
   159 //--------------------------------------------------------------------------------
       
   160 
       
   161 
       
   162 //Utility Functions---------------------------------------------------------------
       
   163 
       
   164 inline TInt RandomNumberInRange(TInt aMin, TInt aMax)
       
   165     {
       
   166     if(aMin > aMax)
       
   167         {
       
   168         TInt temp = aMin;
       
   169         aMin = aMax;
       
   170         aMax = temp;
       
   171         }
       
   172     
       
   173     //Scale and offset to put random into the range inclusively.
       
   174     TUint range = aMax - aMin;
       
   175     TUint random  = Math::Random() % (range + 1);
       
   176     return (TInt)random + aMin;
       
   177     }
       
   178 
       
   179 
       
   180 inline TReal Square(TReal aNumber)
       
   181     {
       
   182     return aNumber * aNumber;
       
   183     }
       
   184 
       
   185 
       
   186 static TBool SamplesAreIncreasing(TInt* aSampledData, TInt aNumSamples)
       
   187     {
       
   188     //Naive linear least squares to get gradient of fit line and correlation coefficient.
       
   189     //Using TReal to avoid worrying about wrap.
       
   190     
       
   191     TReal n = aNumSamples;
       
   192     TReal sumX = 0.0;
       
   193     TReal sumXSq = 0.0;
       
   194     TReal sumY = 0.0;
       
   195     TReal sumYSq = 0.0;
       
   196     TReal sumXTimesY = 0.0;
       
   197     
       
   198     for(TInt i=0; i < aNumSamples; i++)
       
   199         {
       
   200         TReal x = (TReal)(i + 1);
       
   201         TReal y = (TReal)aSampledData[i];
       
   202         sumX += x;
       
   203         sumXSq += Square(x);
       
   204         sumY += y;
       
   205         sumYSq += Square(y);
       
   206         sumXTimesY += x * y;
       
   207         }
       
   208     
       
   209     TReal xBar = sumX / n;
       
   210     TReal yBar = sumY / n;
       
   211     
       
   212     TReal gradient = (sumXTimesY - (n * xBar * yBar)) / (sumXSq - (n * Square(xBar)));
       
   213     TReal correlation = Square(sumXTimesY - (n * xBar * yBar)) / ((sumXSq - (n * Square(xBar))) * (sumYSq - (n * Square(yBar))));
       
   214     
       
   215     //If the gradient is positive and the correlation coefficient is high, the samples are increasing.
       
   216     return (correlation > 0.8) && (gradient > 0.0);
       
   217     }
       
   218 
       
   219 //--------------------------------------------------------------------------------
       
   220 
       
   221 
       
   222 //CTightLoopThread----------------------------------------------------------------
       
   223 
       
   224 CTightLoopThread::CTightLoopThread() :
       
   225     iNotifyStop(EFalse),
       
   226     iHasBeenStarted(EFalse),
       
   227     iHasBeenStopped(EFalse)
       
   228     {
       
   229     }
       
   230 
       
   231 
       
   232 void CTightLoopThread::ConstructL(TBool aSharedHeap)
       
   233     {
       
   234     //Stack and heap sizes.
       
   235     static const TInt KStackSize =   0x2000;      //  8KB
       
   236     static const TInt KHeapMinSize = 0x1000;      //  4KB
       
   237     static const TInt KHeapMaxSize = 0x1000000;   // 16MB
       
   238     
       
   239     //The new thread either has its own heap or shares ours.
       
   240     if(aSharedHeap)
       
   241         {
       
   242         User::LeaveIfError(iThread.Create(KNullDesC, ThreadEntryPoint, KStackSize, NULL, this, EOwnerThread));
       
   243         }
       
   244     else
       
   245         {
       
   246         User::LeaveIfError(iThread.Create(KNullDesC, ThreadEntryPoint, KStackSize, KHeapMinSize, KHeapMaxSize, this, EOwnerThread));
       
   247         }
       
   248     
       
   249     //Resume and rendezvous.
       
   250     iThread.Resume();
       
   251     TRequestStatus rendezvous;
       
   252     iThread.Rendezvous(rendezvous);
       
   253     User::WaitForRequest(rendezvous);
       
   254     User::LeaveIfError(rendezvous.Int());
       
   255     }
       
   256 
       
   257 
       
   258 MLog& CTightLoopThread::Logger() const
       
   259     {
       
   260     return *const_cast<CTightLoopThread*>(this);
       
   261     }
       
   262 
       
   263 
       
   264 class TOverflowTruncate : public TDesOverflow
       
   265     {
       
   266 public:
       
   267     virtual void Overflow(TDes& /*aDes*/)
       
   268         {
       
   269         //Do nothing - just let it truncate.
       
   270         }
       
   271     };
       
   272 
       
   273 
       
   274 void CTightLoopThread::Log(const TText8* aFile, TInt aLine, TInt aSeverity, TRefByValue<const TDesC> aFmt, ...)
       
   275     {
       
   276     TOverflowTruncate overflow;
       
   277     VA_LIST list;
       
   278     VA_START(list, aFmt);
       
   279     TBuf<0x100> buf;
       
   280     buf.AppendFormatList(aFmt, list, &overflow);
       
   281     TPtrC8 file8(aFile);
       
   282     TBuf<0x100> file16;
       
   283     file16.Copy(file8);
       
   284     //Lots of effort is required to pump this into the TEF log file, so for now we just print to debug.
       
   285     RDebug::Print(_L("CTightLoopThread: %S:%d, Severity=%d, Message=\"%S\""), &file16, aLine, aSeverity, &buf);
       
   286     }
       
   287 
       
   288 
       
   289 CTightLoopThread::~CTightLoopThread()
       
   290     {
       
   291     //Shutdown the thread according to the state it is in.
       
   292     if(!iHasBeenStarted)
       
   293         {
       
   294         TRequestStatus* notifyStart = &iNotifyStart;
       
   295         iThread.RequestComplete(notifyStart, KErrAbort);
       
   296         }
       
   297     if(iHasBeenStarted && !iHasBeenStopped)
       
   298         {
       
   299         Stop();
       
   300         }
       
   301     iThread.Close();
       
   302     }
       
   303 
       
   304 
       
   305 void CTightLoopThread::Start()
       
   306     {
       
   307     ASSERT(!iHasBeenStarted);
       
   308     TRequestStatus* notifyStart = &iNotifyStart;
       
   309     iThread.RequestComplete(notifyStart, KErrNone);
       
   310     iHasBeenStarted = ETrue;
       
   311     }
       
   312 
       
   313 
       
   314 TRemoteTestVerdict CTightLoopThread::Stop()
       
   315     {
       
   316     ASSERT(iHasBeenStarted);
       
   317     ASSERT(!iHasBeenStopped);
       
   318     
       
   319     TRequestStatus logon;
       
   320     iThread.Logon(logon);
       
   321     __e32_atomic_store_rel32(&iNotifyStop, ETrue);
       
   322     User::WaitForRequest(logon);
       
   323     
       
   324     TExitType exitType = iThread.ExitType();
       
   325     iThread.Close();
       
   326     iHasBeenStopped = ETrue;
       
   327     
       
   328     switch(exitType)
       
   329         {
       
   330         case EExitKill:
       
   331             //Terminated normally (since we never call kill).
       
   332             return ERtvPass; 
       
   333         
       
   334         case EExitPanic:
       
   335             //Thread panicked.
       
   336             return ERtvPanic;
       
   337             
       
   338         default:
       
   339             //Any other option should be impossible in our use case.
       
   340             ASSERT(0);
       
   341         }
       
   342     return ERtvAbort;
       
   343     }
       
   344 
       
   345 
       
   346 TThreadId CTightLoopThread::ThreadId() const
       
   347     {
       
   348     return iThread.Id();
       
   349     }
       
   350 
       
   351 
       
   352 TInt CTightLoopThread::ThreadEntryPoint(TAny* aSelf)
       
   353     {
       
   354     CTightLoopThread* self = static_cast<CTightLoopThread*>(aSelf);
       
   355     CTrapCleanup* cleanup = CTrapCleanup::New();
       
   356     
       
   357     TRAPD(err,
       
   358         //Create active scheduler.
       
   359         CActiveScheduler* scheduler = new (ELeave) CActiveScheduler();
       
   360         CleanupStack::PushL(scheduler);
       
   361         CActiveScheduler::Install(scheduler);
       
   362 
       
   363         //Setup the draw loop.
       
   364         self->EnterThreadLoopL();
       
   365 
       
   366         //Clean up.
       
   367         CleanupStack::PopAndDestroy(scheduler);
       
   368         );
       
   369     
       
   370     __ASSERT_ALWAYS(err == KErrNone, User::PanicUnexpectedLeave());
       
   371     delete cleanup;
       
   372     
       
   373     return KErrNone;
       
   374     }
       
   375 
       
   376 
       
   377 void CTightLoopThread::EnterThreadLoopL()
       
   378     {
       
   379     //Setup the derived class in this thread context.
       
   380     TRAPD(err, SetupInThreadContextL());
       
   381     
       
   382     //Set the request to pending, rendezvous with parent and wait for start signal.
       
   383     iNotifyStart = KRequestPending;
       
   384     RThread().Rendezvous(err);
       
   385     User::WaitForRequest(iNotifyStart);
       
   386     
       
   387     //Exit immediately if the KErrAbort signal was received.
       
   388     TBool keepGoing = ETrue;
       
   389     if(iNotifyStart == KErrAbort)
       
   390         {
       
   391         keepGoing = EFalse;
       
   392         }
       
   393     else
       
   394         {
       
   395         ASSERT(iNotifyStart == KErrNone);
       
   396         }
       
   397     
       
   398     //Loop until we are told to stop.
       
   399     while(!__e32_atomic_load_acq32(&iNotifyStop) && keepGoing)
       
   400         {
       
   401         keepGoing = ExecuteInnerLoopBody();
       
   402         }
       
   403     
       
   404     //Teardown the derived class in this thread context.
       
   405     TeardownInThreadContextL();
       
   406     }
       
   407 
       
   408 //--------------------------------------------------------------------------------
       
   409 
       
   410 
       
   411 //CEndpointExercise---------------------------------------------------------------
       
   412 
       
   413 CEndpointExercise* CEndpointExercise::NewL(TBool aSharedHeap)
       
   414     {
       
   415     CEndpointExercise* self = new (ELeave) CEndpointExercise();
       
   416     CleanupStack::PushL(self);
       
   417     self->ConstructL(aSharedHeap);
       
   418     CleanupStack::Pop(self);
       
   419     return self;
       
   420     }
       
   421 
       
   422 
       
   423 CEndpointExercise::CEndpointExercise()
       
   424     {
       
   425     }
       
   426 
       
   427 
       
   428 void CEndpointExercise::ConstructL(TBool aSharedHeap)
       
   429     {
       
   430     CTightLoopThread::ConstructL(aSharedHeap);
       
   431     User::LeaveIfError(iEglEp.Error());
       
   432     }
       
   433 
       
   434 
       
   435 CEndpointExercise::~CEndpointExercise()
       
   436     {
       
   437     }
       
   438 
       
   439 
       
   440 void CEndpointExercise::PanicIfError(TInt aError, const TText8* aFile, TInt aLine) const
       
   441     {
       
   442     if(aError != KErrNone)
       
   443         {
       
   444         Logger().Log(aFile, aLine, ESevrErr, _L("Panicking due to error %d"), aError);
       
   445         User::Panic(_L("EPTHREADEDSTRESS"), aLine);
       
   446         }
       
   447     }
       
   448 
       
   449 
       
   450 void CEndpointExercise::PanicIfFalse(TBool aBool, const TText8* aFile, TInt aLine) const
       
   451     {
       
   452     if(!aBool)
       
   453         {
       
   454         Logger().Log(aFile, aLine, ESevrErr, _L("Panicking due to failing invariant test"));
       
   455         User::Panic(_L("EPTHREADEDSTRESS"), aLine);
       
   456         }
       
   457     }
       
   458 
       
   459 
       
   460 void CEndpointExercise::LogAndLeaveIfErrorL(TInt aError, const TText8* aFile, TInt aLine) const
       
   461     {
       
   462     if(aError != KErrNone)
       
   463         {
       
   464         Logger().Log(aFile, aLine, ESevrWarn, _L("Abandoning iteration due to error %d"), aError);
       
   465         User::Leave(aError);
       
   466         }
       
   467     }
       
   468 
       
   469 
       
   470 void CEndpointExercise::LogAndLeaveIfFalseL(TBool aBool, const TText8* aFile, TInt aLine) const
       
   471     {
       
   472     if(!aBool)
       
   473         {
       
   474         Logger().Log(aFile, aLine, ESevrWarn, _L("Abandoning iteration due to failing invariant test"));
       
   475         User::Leave(KErrUnknown);
       
   476         }
       
   477     }
       
   478 
       
   479 
       
   480 TInt CEndpointExercise::CheckImage(EGLImageKHR aEglImage)
       
   481     {
       
   482     TRAPD
       
   483         (err,
       
   484         //Convert the image to a CTestVgEglImage
       
   485         CTestVgEglImage* vgEglImage = CTestVgEglImage::NewL(aEglImage);
       
   486         CleanupStack::PushL(vgEglImage);
       
   487         
       
   488         //Check the corners and center pixel are the same colour.
       
   489         //Since this test is focussed on correct OOM behaviour, 
       
   490         //we panic if the functionality is incorrect.
       
   491         PANIC_IF_FALSE(vgEglImage->IsSolidColourL());
       
   492         
       
   493         CleanupStack::PopAndDestroy(vgEglImage);
       
   494         );
       
   495     return err;
       
   496     }
       
   497 
       
   498 
       
   499 void CEndpointExercise::SetupInThreadContextL()
       
   500     {
       
   501     //Colour to fill surface with (this is incremented every frame).
       
   502     iCurrentColour = 0x88CC44;
       
   503     
       
   504     //Connections to SUS and surface manager.
       
   505     User::LeaveIfError(iSurfaceManager.Open());
       
   506     User::LeaveIfError(iSurfaceUpdate.Connect(5));
       
   507     
       
   508     //Surface attribs to create surface with.
       
   509     iSurfaceAttribs().iSize = TSize(100, 100);
       
   510     iSurfaceAttribs().iBuffers = 2;
       
   511     iSurfaceAttribs().iPixelFormat = EUidPixelFormatARGB_8888_PRE;
       
   512     iSurfaceAttribs().iStride = 100 * 4;
       
   513     iSurfaceAttribs().iOffsetToFirstBuffer = 0;
       
   514     iSurfaceAttribs().iAlignment = 32;
       
   515     iSurfaceAttribs().iContiguous = EFalse;
       
   516     iSurfaceAttribs().iCacheAttrib = RSurfaceManager::ECached;
       
   517     iSurfaceAttribs().iOffsetBetweenBuffers = 0;
       
   518     iSurfaceAttribs().iSurfaceHints = NULL;
       
   519     iSurfaceAttribs().iHintCount = 0;
       
   520     iSurfaceAttribs().iMappable = ETrue;
       
   521     
       
   522     iDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
       
   523     
       
   524     //Create an EglWindowSurface so we have a current context for vg operations.
       
   525     iDummyWindowSurface = CEglWindowSurface::NewL();
       
   526     iDummyWindowSurface->CreateL(EStandardSurface, TPoint(0, 0));
       
   527     iDummyWindowSurface->ActivateL();
       
   528     }
       
   529 
       
   530 
       
   531 void CEndpointExercise::TeardownInThreadContextL()
       
   532     {
       
   533     delete iDummyWindowSurface;
       
   534     iSurfaceUpdate.Close();
       
   535     iSurfaceManager.Close();
       
   536     }
       
   537 
       
   538 
       
   539 TBool CEndpointExercise::ExecuteInnerLoopBody()
       
   540     {
       
   541     TRAPD(err, ExecuteInnerLoopBodyL());
       
   542     if(err != KErrNone)
       
   543         {
       
   544         Logger().Log((TText8*)__FILE__, __LINE__, ESevrWarn, _L("Iteration %d did not run to completion, due to an acceptable error in low memory conditions"), iIteration);
       
   545         }
       
   546     iIteration++;
       
   547     return ETrue;
       
   548     }
       
   549 
       
   550 
       
   551 void CEndpointExercise::ExecuteInnerLoopBodyL()
       
   552     {
       
   553     //Create a surface.
       
   554     TCleanupSurface surface = {&iSurfaceManager, TSurfaceId::CreateNullId()};
       
   555     LOG_AND_LEAVE_IF_ERROR_L(iSurfaceManager.CreateSurface(iSurfaceAttribs, surface.iSurfaceId));
       
   556     CleanupStack::PushL(TCleanupItem(CleanupSurface, &surface));
       
   557     
       
   558     //Map surface and get pointer to buffer 0.
       
   559     RChunk surfaceChunk;
       
   560     TInt offset;
       
   561     PANIC_IF_ERROR(iSurfaceManager.MapSurface(surface.iSurfaceId, surfaceChunk));
       
   562     CleanupClosePushL(surfaceChunk);
       
   563     PANIC_IF_ERROR(iSurfaceManager.GetBufferOffset(surface.iSurfaceId, 0, offset));
       
   564     TUint32* buffer = (TUint32*)(surfaceChunk.Base() + offset);
       
   565     
       
   566     //Fill surface with current colour. This could
       
   567     //be much faster but its good enough for testing.
       
   568     TUint32 fillColour = TRgb(iCurrentColour, 255)._Color16MAP();
       
   569     for(TInt y=0; y < iSurfaceAttribs().iSize.iHeight; ++y)
       
   570         {
       
   571         for(TInt x=0; x < iSurfaceAttribs().iSize.iWidth; ++x)
       
   572             {
       
   573             buffer[x] = fillColour;
       
   574             }
       
   575         buffer += iSurfaceAttribs().iStride >> 2;
       
   576         }
       
   577     
       
   578     //Create an endpoint for the surface.
       
   579     TCleanupEndpoint endpoint = {iDisplay, EGL_NO_ENDPOINT_NOK};
       
   580     endpoint.iEndpoint = iEglEp.CreateEndpoint(iDisplay, EGL_ENDPOINT_TYPE_CONSUMER_NOK, EGL_TSURFACEID_NOK, &surface.iSurfaceId, NULL);
       
   581     LOG_AND_LEAVE_IF_FALSE_L(endpoint.iEndpoint != EGL_NO_ENDPOINT_NOK);
       
   582     CleanupStack::PushL(TCleanupItem(CleanupEndpoint, &endpoint));
       
   583     
       
   584     //Submit buffer 0 to surface update server.
       
   585     TRequestStatus displayed;
       
   586     iSurfaceUpdate.NotifyWhenDisplayedXTimes(1, displayed);
       
   587     LOG_AND_LEAVE_IF_ERROR_L(iSurfaceUpdate.SubmitUpdate(KAllScreens, surface.iSurfaceId, 0, NULL));
       
   588     User::WaitForRequest(displayed);
       
   589     
       
   590     //Begin streaming. Should not fail since we have submitted a buffer since creating ep.
       
   591     LOG_AND_LEAVE_IF_FALSE_L(iEglEp.EndpointBeginStreaming(iDisplay, endpoint.iEndpoint));
       
   592     
       
   593     //Acquire an image from the endpoint.
       
   594     TCleanupImage image = {iDisplay, endpoint.iEndpoint, EGL_NO_IMAGE_KHR};
       
   595     image.iImage = iEglEp.AcquireImage(iDisplay, endpoint.iEndpoint);
       
   596     LOG_AND_LEAVE_IF_FALSE_L(image.iImage != EGL_NO_IMAGE_KHR);
       
   597     CleanupStack::PushL(TCleanupItem(CleanupImage, &image));
       
   598     
       
   599     //Check that the image we acquired is coherrent.
       
   600     LOG_AND_LEAVE_IF_ERROR_L(CheckImage(image.iImage));
       
   601     
       
   602     //Release image, destroy endpoint, close chunk and close surface.
       
   603     CleanupStack::PopAndDestroy(4);
       
   604     
       
   605     //Modify the colour that we draw.
       
   606     iCurrentColour += 16;
       
   607     }
       
   608 
       
   609 //--------------------------------------------------------------------------------
       
   610 
       
   611 
       
   612 //Remote test step----------------------------------------------------------------
       
   613 
       
   614 CEglTest_RemoteTestStep_EndpointThreadStress::CEglTest_RemoteTestStep_EndpointThreadStress() :
       
   615     CRemoteTestStepBase(ETestUidEndpointThreadStress)
       
   616     {
       
   617     }
       
   618 
       
   619 
       
   620 CEglTest_RemoteTestStep_EndpointThreadStress::~CEglTest_RemoteTestStep_EndpointThreadStress()
       
   621     {
       
   622     }
       
   623 
       
   624 
       
   625 TRemoteTestVerdict CEglTest_RemoteTestStep_EndpointThreadStress::DoStartRemoteTestStepL(const TRemoteTestParams& /*aMessageIn*/)
       
   626     {
       
   627     REMOTE_INFO_PRINTF1(_L("Starting Remote Test Step."));
       
   628     EglStartL();
       
   629     return ERtvPass;
       
   630     }
       
   631 
       
   632 
       
   633 TRemoteTestVerdict CEglTest_RemoteTestStep_EndpointThreadStress::DoEndRemoteTestStepL(const TRemoteTestParams& /*aMessageIn*/)
       
   634     {
       
   635     REMOTE_INFO_PRINTF1(_L("Ending Remote Test Step."));
       
   636     EglEndL();
       
   637     return ERtvPass;
       
   638     }
       
   639 
       
   640 
       
   641 TInt CEglTest_RemoteTestStep_EndpointThreadStress::Timeout() const
       
   642     {
       
   643     return 120 * 1000000; //2 min.
       
   644     }
       
   645 
       
   646 
       
   647 TRemoteTestVerdict CEglTest_RemoteTestStep_EndpointThreadStress::DoRunRemoteTestCaseL(TInt aTestCase, const TRemoteTestParams& aParams)
       
   648     {
       
   649     switch(aTestCase)
       
   650         {
       
   651         case 0:     return CrazyThreadingTestCaseL(aParams);
       
   652         case 1:     return OutOfHeapMemoryTestCaseL(aParams);
       
   653         default:    return ERtvAbort;
       
   654         }
       
   655     }
       
   656 
       
   657 
       
   658 //For a detailed description of this test case (GRAPHICS-EGL-594), see the local side cpp file.
       
   659 TRemoteTestVerdict CEglTest_RemoteTestStep_EndpointThreadStress::CrazyThreadingTestCaseL(const TRemoteTestParams& /*aParams*/)
       
   660     {
       
   661     //Create the exercises. These run an endpoint exercise in a tight loop in a private thread.
       
   662     CEndpointExercise* exercise1 = CEndpointExercise::NewL(EFalse);
       
   663     CleanupStack::PushL(exercise1);
       
   664     CEndpointExercise* exercise2 = CEndpointExercise::NewL(EFalse);
       
   665     CleanupStack::PushL(exercise2);
       
   666     
       
   667     //Create a monitor to cleanup if any of the threads panic. The controller thread 
       
   668     //must be at index zero in the array. This will even work if a deadlock occurs 
       
   669     //between the  exercise threads, since the call to stop the exercise will never 
       
   670     //return and the framework will eventually time us out. The monitor will notice
       
   671     //that the controller thread has panicked and will forward the panic to the exercises.
       
   672     RArray<TThreadId> threads;
       
   673     CleanupClosePushL(threads);
       
   674     threads.AppendL(RThread().Id());
       
   675     threads.AppendL(exercise1->ThreadId());
       
   676     threads.AppendL(exercise2->ThreadId());
       
   677     CThreadMonitor* monitor = CThreadMonitor::NewL(threads);
       
   678     CleanupStack::PushL(monitor);
       
   679     
       
   680     //Start the exercises.
       
   681     exercise1->Start();
       
   682     exercise2->Start();
       
   683     
       
   684     //Let the exercises run for 20 seconds.
       
   685     User::After(20 * 1000000);
       
   686     
       
   687     //Stop the exercises and record the results.
       
   688     TRemoteTestVerdict result1 = exercise1->Stop();
       
   689     TRemoteTestVerdict result2 = exercise2->Stop();
       
   690     
       
   691     CleanupStack::PopAndDestroy(4, exercise1);
       
   692     return (result1 != ERtvPass) ? result1 : result2;
       
   693     }
       
   694 
       
   695 
       
   696 class THeapGobbler
       
   697     {
       
   698 public:
       
   699     static THeapGobbler* New(TInt aSize)
       
   700         {
       
   701         THeapGobbler* self = (THeapGobbler*)new TUint8[sizeof(THeapGobbler) - sizeof(TUint8) + aSize];
       
   702         if(!self)
       
   703             {
       
   704             return NULL;
       
   705             }
       
   706         self->iSize = aSize;
       
   707         self->iNext = NULL;
       
   708         return self;
       
   709         }
       
   710     
       
   711 public:
       
   712     THeapGobbler* iNext;
       
   713     TInt iSize;
       
   714     TUint8 iMemory[1];
       
   715     };
       
   716 
       
   717 
       
   718 //For a detailed description of this test case (GRAPHICS-EGL-601), see the local side cpp file.
       
   719 TRemoteTestVerdict CEglTest_RemoteTestStep_EndpointThreadStress::OutOfHeapMemoryTestCaseL(const TRemoteTestParams& aParams)
       
   720     {
       
   721     const TInt KHeapSizeMin = 0x100000;   //1MB.
       
   722     const TInt KHeapSizeMax = 0x10000000; //256MB.
       
   723 
       
   724     RHeap* testHeap = User::ChunkHeap(NULL, KHeapSizeMin, KHeapSizeMax, KMinHeapGrowBy, 4);
       
   725     if(!testHeap)
       
   726         {
       
   727         REMOTE_ERR_PRINTF1(_L("Failed to create chunk heap. Aborting."));
       
   728         return ERtvAbort;
       
   729         }
       
   730     RHeap* oldHeap = User::SwitchHeap(testHeap);
       
   731     
       
   732     CTrapCleanup *cleanUpStack = CTrapCleanup::New();
       
   733     if (!cleanUpStack)
       
   734         {
       
   735         User::SwitchHeap(oldHeap);
       
   736         testHeap->Close();
       
   737         User::Leave(KErrNoMemory);
       
   738         }
       
   739 
       
   740     TRemoteTestVerdict verdict = ERtvPass;
       
   741     TRAPD(err, verdict = DoOutOfHeapMemoryTestCaseL(aParams));
       
   742     
       
   743     delete cleanUpStack;
       
   744     User::SwitchHeap(oldHeap);
       
   745     testHeap->Close();
       
   746     
       
   747     User::LeaveIfError(err);
       
   748     return verdict;
       
   749     }
       
   750 
       
   751  
       
   752 TRemoteTestVerdict CEglTest_RemoteTestStep_EndpointThreadStress::DoOutOfHeapMemoryTestCaseL(const TRemoteTestParams& aParams)
       
   753     {
       
   754     const TInt numExercises = aParams.iEndpointThreadStress.iNumThreads;
       
   755     
       
   756     const TInt KMinCellSize = 500;
       
   757     const TInt KMaxCellSize = 2000;
       
   758     const TInt KNumIterations = 20;
       
   759     TInt heapAllocSize[KNumIterations];
       
   760     TRemoteTestVerdict exerciseResult = ERtvPass;
       
   761     
       
   762     //One iteration of the outer loop results in one data point for deciding if the heap is leaking or not. 
       
   763     for(TInt x=0; x < KNumIterations; x++)
       
   764         {
       
   765         //Reserving space in these arrays ahead of time to 
       
   766         //make cleanup stack manipulation more staightforward.
       
   767         RPointerArray<CEndpointExercise> exercises;
       
   768         CleanupStack::PushL(TCleanupItem(CleanupPointerArray, &exercises));
       
   769         exercises.ReserveL(numExercises);
       
   770         RArray<TThreadId> threads;
       
   771         CleanupClosePushL(threads);
       
   772         threads.ReserveL(numExercises + 1);
       
   773         
       
   774         //Save the controller thread id for the monitor.
       
   775         threads.Append(RThread().Id());
       
   776         
       
   777         //Create endpoint exercise threads and save the thread Ids for the monitor.
       
   778         for(TInt j=0; j < numExercises; j++)
       
   779             {
       
   780             //Appends can't fail since we have already reserved space.
       
   781             //Note that the exercises all share the same heap as this thread.
       
   782             exercises.Append(CEndpointExercise::NewL(ETrue));
       
   783             threads.Append(exercises[j]->ThreadId());
       
   784             }
       
   785 
       
   786         //Create a monitor to handle thread cleanup if something panics or deadlocks.
       
   787         CThreadMonitor* monitor = CThreadMonitor::NewL(threads);
       
   788         
       
   789         //Nothing can leave after this.
       
   790         CleanupStack::Pop(2);
       
   791         
       
   792         //Start the exercises.
       
   793         for(TInt j=0; j < numExercises; j++)
       
   794             {
       
   795             exercises[j]->Start();
       
   796             }
       
   797         
       
   798         THeapGobbler* firstCell = NULL;
       
   799         THeapGobbler* lastCell = NULL;
       
   800         TInt numberOfCells = 0;
       
   801         
       
   802         for(TInt i=0; i < 2; i++)
       
   803             {
       
   804             //Allocate random sizes until full.
       
   805             THeapGobbler* newCell = THeapGobbler::New(RandomNumberInRange(KMinCellSize, KMaxCellSize));
       
   806             while(newCell)
       
   807                 {
       
   808                 if(lastCell)
       
   809                     lastCell->iNext = newCell;
       
   810                 if(!firstCell)
       
   811                     firstCell = newCell;
       
   812                 lastCell = newCell;
       
   813                 numberOfCells++;
       
   814                 newCell = THeapGobbler::New(RandomNumberInRange(KMinCellSize, KMaxCellSize));
       
   815                 }
       
   816             
       
   817             //Let exercise run while heap is full.
       
   818             User::After(1 * 1000);
       
   819             
       
   820             //Deallocate n/4 cells.
       
   821             for(TInt n = numberOfCells / 4; n >= 1; --n)
       
   822                 {
       
   823                 THeapGobbler* oldCell = firstCell;
       
   824                 firstCell = oldCell->iNext;
       
   825                 delete oldCell;
       
   826                 numberOfCells--;
       
   827                 if(!firstCell)
       
   828                     {
       
   829                     lastCell = NULL;
       
   830                     ASSERT(numberOfCells == 0);
       
   831                     break;
       
   832                     }
       
   833                 }
       
   834             
       
   835             //Let exercise run while heap is not full.
       
   836             User::After(1 * 1000);
       
   837             }
       
   838         
       
   839         //Deallocate all cells.
       
   840         while(firstCell)
       
   841             {
       
   842             THeapGobbler* oldCell = firstCell;
       
   843             firstCell = oldCell->iNext;
       
   844             delete oldCell;
       
   845             }
       
   846         lastCell = NULL;
       
   847         numberOfCells = 0;
       
   848         
       
   849         //Stop the exercises and save the result.
       
   850         for(TInt j=0; j < numExercises; j++)
       
   851             {
       
   852             TRemoteTestVerdict ret = exercises[j]->Stop();
       
   853             exerciseResult = (exerciseResult == ERtvPass) ? ret : exerciseResult;
       
   854             }
       
   855 
       
   856         delete monitor;
       
   857         threads.Close();
       
   858         exercises.ResetAndDestroy();
       
   859         
       
   860         if(exerciseResult != ERtvPass)
       
   861             {
       
   862             REMOTE_ERR_PRINTF2(_L("Aborting because the endpoint exercise failed for iteration %d"), x);
       
   863             return exerciseResult;
       
   864             }
       
   865         
       
   866         //Save the heap size.
       
   867         User::Heap().AllocSize(heapAllocSize[x]);
       
   868         }
       
   869     
       
   870     //Work out if any memory has leaked and return a verdict.
       
   871     TBool memoryIsLeaking = SamplesAreIncreasing(heapAllocSize, KNumIterations);
       
   872     if(memoryIsLeaking)
       
   873         {
       
   874         REMOTE_ERR_PRINTF1(_L("Heap memory is increasing over time with high certainty, there is probably a memory leak."));
       
   875         }
       
   876     else
       
   877         {
       
   878         REMOTE_INFO_PRINTF1(_L("No heap memory leak detected."));
       
   879         }
       
   880     return memoryIsLeaking ? ERtvFail : ERtvPass;
       
   881     }
       
   882 
       
   883 //--------------------------------------------------------------------------------