egl/egltest/endpointtestsuite/automated/tsrc/egltest_surface.cpp
author hgs
Fri, 30 Jul 2010 11:41:40 +0300
changeset 136 62bb7c97884c
parent 98 bf7481649c98
permissions -rw-r--r--
201030_2

// Copyright (c) 2007-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 "egltest_surface.h"
#include "egltest_endpoint_images.h"
#include <graphics/surfaceconfiguration.h>
#include <e32std.h>
#include <e32math.h>
#include <VG/vgu.h>


#define SURF_ASSERT(x) { if (!(x)) { RDebug::Printf("ASSERT(%s) failed at %s:%d", #x, __FILE__, __LINE__); User::Panic(_L("ASSERT SURF"), __LINE__); }}

// Macros for indicating what is what.
#define SIZE(x, y) x, y
#define Buffers(x) x
#define DefaultAlignment 32  // Pick some value that is valid.
#define Alignment(x) x
#define Stride(x) x
#define DefaultStride 0
// Note: Offset to first buffer.
#define Offset(x) x
#define WindowPos(x, y)  x, y
#define WindowMode(m) m

#define LARGEST_POSSIBLE_FLAG 0x80000000

static const TSurfaceParamsCommon KSurfaceParams[] =
{
    {
        EStandardSurface,
        SIZE(100, 100),
        Buffers(2),
        DefaultAlignment,
        DefaultStride,
        Offset(0),
        EUidPixelFormatARGB_8888_PRE,
        EFalse,
        { 0 },
        WindowPos(0, 0),
        WindowMode(EColor16MAP)
    },
    {
        EBadAttribSurface,
        SIZE(100, 100),
        Buffers(2),
        DefaultAlignment,
        DefaultStride,
        Offset(0),
        EUidPixelFormatARGB_8888_PRE,
        ETrue,
        { 1, 1, EGL_NONE },
        WindowPos(0, 0),
        WindowMode(EColor16MAP)
    },
    {
        EEmptyAttribSurface,
        SIZE(100, 100),
        Buffers(2),
        DefaultAlignment,
        DefaultStride,
        Offset(0),
        EUidPixelFormatARGB_8888_PRE,
        ETrue,
        { EGL_NONE },
        WindowPos(0, 0),
        WindowMode(EColor16MAP)
    },
    {
        EStandard128sqSurface,
        SIZE(128, 128),
        Buffers(3),
        DefaultAlignment,
        DefaultStride,
        Offset(0),
        EUidPixelFormatARGB_8888_PRE,
        EFalse,
        { 0 },
        WindowPos(20, 20),
        WindowMode(EColor16MAP)
    },
    {
        EUnusualStrideSurface,
        SIZE(167,263),
        Buffers(2),
        Alignment(8),
        Stride(167*4+64),
        Offset(200),
        EUidPixelFormatARGB_8888_PRE,
        EFalse,
        { 0 },
        WindowPos(0, 0),
        WindowMode(EColor16MAP)
    },
    {
        EUnalignedPixelSizeSurface,
        SIZE(103, 107),
        Buffers(2),
        Alignment(8),
        Stride(103*4),
        Offset(0),
        EUidPixelFormatARGB_8888_PRE,
        EFalse,
        { 0 },
        WindowPos(0, 0),
        WindowMode(EColor16MAP)
    },
    {
        ELargeSurface,
        SIZE(800, 600),
        Buffers(2),
        DefaultAlignment,
        DefaultStride,
        Offset(0),
        EUidPixelFormatARGB_8888_PRE,
        EFalse,
        { 0 },
        WindowPos(0, 0),
        WindowMode(EColor16MAP)
    },
    {
        ELargestPossibleSurface,
        SIZE(LARGEST_POSSIBLE_FLAG, LARGEST_POSSIBLE_FLAG),
        Buffers(2),
        DefaultAlignment,
        DefaultStride,
        Offset(0),
        EUidPixelFormatARGB_8888_PRE,
        EFalse,
        { 0 },
        WindowPos(0, 0),
        WindowMode(EColor16MAP)
    },    
    {
        ESmallSurface,
        SIZE(16, 16),
        Buffers(1),
        DefaultAlignment,
        DefaultStride,
        Offset(0),
        EUidPixelFormatARGB_8888_PRE,
        EFalse,
        { 0 },
        WindowPos(0, 0),
        WindowMode(EColor16MAP)
    },
    {
        ETinySurface,
        SIZE(8, 8),
        Buffers(1),
        DefaultAlignment,
        DefaultStride,
        Offset(0),
        EUidPixelFormatARGB_8888_PRE,
        EFalse,
        { 0 },
        WindowPos(0, 0),
        WindowMode(EColor16MAP)
    },
};

const TInt KSurfaceMaxIndex = sizeof(KSurfaceParams) / sizeof(KSurfaceParams[0]);

struct TSurfaceSize
    {
    TInt iWidth;
    TInt iHeight;
    };

static const TSurfaceSize KSurfaceSizes[] =
    {
        {  320,  240 },
        {  640,  480 },
        {  720,  480 },
        {  854,  480 },
        {  720,  576 },
        {  854,  576 },
        { 1280,  720 },
        { 1024,  768 },
        { 1280, 1024 },
        { 1920, 1080 },
        { 1600, 1200 },
#if 0
        { 2048, 1536 },
        { 2560, 1920 },
        { 3648, 2736 },
        { 4216, 2638 },
        { 4000, 3000 },
        { 4616, 2600 },
#endif
    };

const TInt KMaxSurfaceSizes =  sizeof(KSurfaceSizes) / sizeof(KSurfaceSizes[0]);

LOCAL_C TUint RandomNumberInRange(TUint aLow, TUint aHigh)
    {
    TReal32 rand = Math::Random();
    rand /= KMaxTUint;
    rand *= aHigh - aLow;
    rand += aLow;
    return TUint(rand);
    }


void CSurface::CreateL(TInt aIndex)
    {
    CreateL(aIndex, TPoint(0, 0));
    }


TSize CSurface::Size()
    {
    return iActualSize;
    }


TInt CSurface::SizeInBytes() const
    {
    RSurfaceManager::TInfoBuf infoBuf;
    RSurfaceManager surfMgr;
    TInt err = surfMgr.Open();
    if (err != KErrNone)
        {
        RDebug::Printf("Error opening surface manager... Err=%d", err);
        return 0;
        }
    err = surfMgr.SurfaceInfo(SurfaceId(), infoBuf);
    if (err != KErrNone)
        {
        RDebug::Printf("Could not get surface info - err = %d", err);
        return 0;
        }
    TInt size = infoBuf().iBuffers * infoBuf().iSize.iHeight * infoBuf().iStride;
    surfMgr.Close();
    return size;
    }


CRawSurface* CRawSurface::NewL()
    {
    CRawSurface* obj = new (ELeave) CRawSurface();
    CleanupStack::PushL(obj);
    obj->ConstructL();
    CleanupStack::Pop(obj);
    return obj;
    }



CRawSurface::CRawSurface() : iDrawBuffer(0), iBuffers(0)
    {
    }


void CRawSurface::ConstructL()
    {
    iSurfaceId = TSurfaceId::CreateNullId();
    User::LeaveIfError(iSurfaceManager.Open());
    User::LeaveIfError(iSurfaceUpdate.Connect());
    }


CRawSurface::~CRawSurface()
    {
    iSurfaceUpdate.Close();
    if(!iSurfaceId.IsNull())
        {
        iSurfaceManager.CloseSurface(iSurfaceId);
        }
    iSurfaceManager.Close();
    }


TInt CRawSurface::PixelSize(TUidPixelFormat aPixelFormat)
    {
    switch(aPixelFormat)
        {
        case EUidPixelFormatARGB_8888_PRE:
        case EUidPixelFormatARGB_8888:
        case EUidPixelFormatABGR_8888:
        case EUidPixelFormatABGR_8888_PRE:
            return 4;

        case EUidPixelFormatARGB_4444:
        case EUidPixelFormatRGB_565:
            return 2;

        default:
            SURF_ASSERT(0);
            break;
        }
    return 0; // Make sure no compiler moans about "not all paths return a value".
    }


void CRawSurface::GetSurfAttribs(RSurfaceManager::TSurfaceCreationAttributesBuf &aSurfaceAttribs, 
        TInt aIndex, TInt aSizeIndex)
    {
    SURF_ASSERT(aIndex < KSurfaceMaxIndex);
    SURF_ASSERT(aIndex == KSurfaceParams[aIndex].iIndex);
    iParamIndex = aIndex;
    if (KSurfaceParams[aIndex].iXSize & LARGEST_POSSIBLE_FLAG)
        {
        
        aSurfaceAttribs().iSize = 
                TSize(KSurfaceSizes[aSizeIndex].iWidth, KSurfaceSizes[aSizeIndex].iHeight);
        }
    else
        {
        aSurfaceAttribs().iSize = 
                TSize(KSurfaceParams[aIndex].iXSize, KSurfaceParams[aIndex].iYSize);
        }
    iBuffers = KSurfaceParams[aIndex].iBuffers;
    aSurfaceAttribs().iBuffers = iBuffers;
    aSurfaceAttribs().iPixelFormat = KSurfaceParams[aIndex].iPixelFormat;
    TInt stride = KSurfaceParams[aIndex].iStrideInBytes;
    if (stride == 0)
        {
        stride = aSurfaceAttribs().iSize.iWidth * PixelSize(KSurfaceParams[aIndex].iPixelFormat);
        }
    aSurfaceAttribs().iStride = stride;
    aSurfaceAttribs().iOffsetToFirstBuffer = KSurfaceParams[aIndex].iOffsetToFirstBuffer;
    aSurfaceAttribs().iAlignment = KSurfaceParams[aIndex].iAlignment;
    aSurfaceAttribs().iContiguous = EFalse;
    aSurfaceAttribs().iCacheAttrib = RSurfaceManager::ECached;
    aSurfaceAttribs().iOffsetBetweenBuffers = 0;
    aSurfaceAttribs().iSurfaceHints = NULL;
    aSurfaceAttribs().iHintCount = 0;
    aSurfaceAttribs().iMappable = ETrue;
    }


void CRawSurface::CreateL(TInt aIndex, const TPoint &/* aPoint */)
    {
    RSurfaceManager::TSurfaceCreationAttributesBuf surfaceAttribs;
    SURF_ASSERT(aIndex < KSurfaceMaxIndex);
    TInt sizeIndex = 0;
    if (KSurfaceParams[aIndex].iXSize & LARGEST_POSSIBLE_FLAG)
        {
        sizeIndex = KMaxSurfaceSizes-1;
        
        }
    TInt err = KErrNone;
    do
        {
        GetSurfAttribs(surfaceAttribs, aIndex, sizeIndex);
        err = iSurfaceManager.CreateSurface(surfaceAttribs, iSurfaceId);
        iActualSize = surfaceAttribs().iSize;
        sizeIndex--;
        }
    while(err != KErrNone && sizeIndex >= 0);
    User::LeaveIfError(err);
    }


TUint8* CRawSurface::MapSurfaceAndGetInfoLC(RSurfaceManager::TSurfaceInfoV01& aInfo)
    {
    SURF_ASSERT(!iSurfaceId.IsNull());
    User::LeaveIfError(iSurfaceManager.MapSurface(iSurfaceId, iSurfaceChunk));
    CleanupClosePushL(iSurfaceChunk);
    RSurfaceManager::TInfoBuf infoBuf;
    User::LeaveIfError(iSurfaceManager.SurfaceInfo(iSurfaceId, infoBuf));
    aInfo = infoBuf();
    TInt offset = -1000;  // So we hopefully detect when it goes horribly wrong.
    User::LeaveIfError(iSurfaceManager.GetBufferOffset(iSurfaceId, iDrawBuffer, offset));
    SURF_ASSERT(offset >= 0);
    return iSurfaceChunk.Base() + offset;
    }


void CRawSurface::DrawContentL(TInt aImageIndex)
    {
    CTestCFbsImage *image = CTestCFbsImage::NewL(aImageIndex);
    CleanupStack::PushL(image);

    RSurfaceManager::TSurfaceInfoV01 info;
    TUint8 *dataAddress = MapSurfaceAndGetInfoLC(info);
    TInt stride = info.iStride;

    CFbsBitmap *bitmap = image->Bitmap();
    TDisplayMode displaymode = bitmap->DisplayMode();
    TInt pixelStride = stride / CFbsBitmap::ScanLineLength(1, displaymode);
    for(TInt y = 0; y < image->Size().iHeight; y++)
        {
        TPtr8 buf(dataAddress + y * stride, stride);

        // TODO: We need to check that the bitsperpixel matches between the surface and bitmap.
        bitmap->GetScanLine(buf, TPoint(0, y), pixelStride, displaymode);
        }

    CleanupStack::PopAndDestroy(2, image);
    }

void CRawSurface::DrawContentL(const TRgb& aColour)
    {
    //Map the surface and get its info.
    RSurfaceManager::TSurfaceInfoV01 surfaceInfo;
    TUint32* buffer = (TUint32*)MapSurfaceAndGetInfoLC(surfaceInfo);

    //Currently this function only supports drawing into ARGB_8888_PRE surfaces.
    //This is because the only test that uses this function uses this type of surface.
    //If this functionallity needs expanding, you must correctly convert the TRgb colour
    //and pack it into the surface buffer correctly.
    SURF_ASSERT(surfaceInfo.iPixelFormat == EUidPixelFormatARGB_8888_PRE);

    TUint32 fillColour = aColour._Color16MAP();

    //Loop over each pixel in the surface and colour it.
    //This is deliberately slow since it is only used for the tearing test
    //and we want to spend most of our time drawing so that the chances of the other thread
    //picking up a buffer in the middle of drawing is increased.
    for(TInt y=0; y < surfaceInfo.iSize.iHeight; ++y)
        {
        for(TInt x=0; x < surfaceInfo.iSize.iWidth; ++x)
            {
            buffer[x] = fillColour;
            }
        buffer += surfaceInfo.iStride >> 2;
        }

    CleanupStack::PopAndDestroy();
    }


void CRawSurface::DrawComplexL(const TRgb& aColour)
    {
    DrawContentL(aColour);
    }


TInt CRawSurface::SubmitContent(TBool aShouldWaitForDisplay, TInt /* aRectsIndex */)
    {
    TRequestStatus displayNotify = KRequestPending;
    TTimeStamp timeStamp;

    if(aShouldWaitForDisplay)
        {
        Notify(ENotifyWhenDisplayed, displayNotify, 0);
        }

    TInt err = iSurfaceUpdate.SubmitUpdate(KAllScreens, iSurfaceId, iDrawBuffer, NULL);
    if (err != KErrNone)
        {
        if (err != KErrNone)
            {
            RDebug::Printf("%s:%d: SubmitUpdate gave unexpected error %d", __FILE__, __LINE__, err);
            }
        return err;
        }
    iDrawBuffer = (iDrawBuffer + 1) % iBuffers;

    if(aShouldWaitForDisplay)
        {
        TUint32 dummy;
        err = WaitFor(ENotifyWhenDisplayed, displayNotify, 100 * 1000, dummy);
        if (err != KErrNone && err != KErrNotVisible && err != KErrOverflow)
            {
//            RDebug::Printf("%s:%d: NotifyWhenDisplayed gave unexpected error %d", __FILE__, __LINE__, err);
            return err;
            }
        }
    return KErrNone;
    }


TSurfaceId CRawSurface::SurfaceId() const
    {
    return iSurfaceId;
    }


void CRawSurface::GetSurfaceParamsL(TSurfaceParamsRemote &aParams)
    {
    aParams.iCommonParams = KSurfaceParams[iParamIndex];
    aParams.iCommonParams.iBuffers = iBuffers; // May have been changed if it's a single buffered surface...
    aParams.iSurfaceId = SurfaceId();
    }

const TText *CRawSurface::GetSurfaceTypeStr() const
    {
    return _S("CRawSurface");
    }

TInt CRawSurface::Notify(TNotification aWhen, TRequestStatus& aStatus, TUint32 aXTimes)
    {
    aStatus = KRequestPending;
    switch(aWhen)
        {
        case ENotifyWhenAvailable:
            iSurfaceUpdate.NotifyWhenAvailable(aStatus);
            break;
        case ENotifyWhenDisplayed:
            iSurfaceUpdate.NotifyWhenDisplayed(aStatus, iTimeStamp);
            break;
        case ENotifyWhenDispXTimes:
            iSurfaceUpdate.NotifyWhenDisplayedXTimes(aXTimes, aStatus);
            break;
        default:
            RDebug::Printf("%s:%d: Invalid notification: %d. Panicking...", __FILE__, __LINE__, aWhen);
            User::Panic(_L("CRawSurface::Notify()"), __LINE__);
            break;
        }
    return KErrNone;
    }


TInt CRawSurface::WaitFor(TNotification aWhen, TRequestStatus& aStatus, TInt aTimeoutInMicroSeconds, TUint32& aTimeStamp)
    {
    RTimer timer;
    TInt err = timer.CreateLocal();
    if (err != KErrNone)
        {
        RDebug::Printf("%s:%d: Could not create timer... err= %d", __FILE__, __LINE__, err);
        return err;
        }
    TRequestStatus timerStatus = KRequestPending;
#if __WINS__
    // Windows timer isn't very precise - add some "fuzz" to the timeout to ensure we do not wait "too little".
    const TInt KTimeOutExtra = 20000;
#else
    // On hardware, we should be able to run with less "fuzz".
    const TInt KTimeOutExtra = 10000;
#endif
    timer.HighRes(timerStatus, aTimeoutInMicroSeconds + KTimeOutExtra);
    User::WaitForRequest(timerStatus, aStatus);
    if (aStatus == KRequestPending)
        {
        if (aWhen == ENotifyWhenDisplayed)
            {
            aTimeStamp = User::FastCounter();
            }
        return KErrTimedOut;
        }
    if (aWhen == ENotifyWhenDisplayed)
        {
        aTimeStamp = iTimeStamp();
        }
    timer.Cancel();
    timer.Close();
    TInt result = aStatus.Int();
    aStatus = KRequestPending;
    return result;
    }

const TText *CRawSingleBufferSurface::GetSurfaceTypeStr() const
    {
    return _S("CRawSingleBufferedSurface");
    }

CRawSingleBufferSurface *CRawSingleBufferSurface::NewL()
    {
    CRawSingleBufferSurface* obj = new (ELeave) CRawSingleBufferSurface();
    CleanupStack::PushL(obj);
    obj->ConstructL();
    CleanupStack::Pop(obj);
    return obj;
    }


void CRawSingleBufferSurface::CreateL(TInt aIndex, const TPoint & /*aPoint */)
    {
    RSurfaceManager::TSurfaceCreationAttributesBuf surfaceAttribs;

    TInt sizeIndex = 0;
    if (KSurfaceParams[aIndex].iXSize & LARGEST_POSSIBLE_FLAG)
        {
        sizeIndex = KMaxSurfaceSizes-1;
        }
    TInt err = KErrNone;
    do
        {
        GetSurfAttribs(surfaceAttribs, aIndex, sizeIndex);
        iBuffers = 1;
        surfaceAttribs().iBuffers = 1;
        err = iSurfaceManager.CreateSurface(surfaceAttribs, iSurfaceId);
        iActualSize = surfaceAttribs().iSize;
        sizeIndex--;
        }
    while(err != KErrNone && sizeIndex >= 0);
    }

CRawSingleBufferSurface::~CRawSingleBufferSurface()
    {
    }


TInt CEglSurfaceBase::Activate()
    {
    if (!eglMakeCurrent(iDisplay, iSurface, iSurface, iContext))
        {
        EGLint err = eglGetError();
        RDebug::Printf("%s:%d: eglMakeCurrent gave error 0x%x", __FILE__, __LINE__, err);
        return KErrBadHandle;
        }
    return KErrNone;
    }

void CEglSurfaceBase::ActivateL()
    {
    User::LeaveIfError(Activate());
    }

void CEglSurfaceBase::DrawComplexL(const TRgb& aColour)
    {
    ActivateL();

    TSize size;
    eglQuerySurface(iDisplay, iSurface, EGL_WIDTH, &size.iWidth);
    eglQuerySurface(iDisplay, iSurface, EGL_HEIGHT, &size.iHeight);
    
    //Paint lots of random circles to keep the GPU busy.
    for(TInt i=0; i < 300; i++)
        {
        VGPaint paint = vgCreatePaint();
        VGPath path = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1.0f, 0.0f, 0, 0, VG_PATH_CAPABILITY_APPEND_TO);
        
        TInt minDim = Min(size.iWidth, size.iHeight);
        VGfloat cx = RandomNumberInRange(0, size.iWidth);
        VGfloat cy = RandomNumberInRange(0, size.iHeight);
        VGfloat diameter = RandomNumberInRange(minDim / 20, minDim / 3);
        TRgb fillColour(RandomNumberInRange(0, 255), RandomNumberInRange(0, 255), RandomNumberInRange(0, 255), RandomNumberInRange(0, 255));
        
        vguEllipse(path, cx, cy, diameter, diameter);
        vgSetPaint(paint, VG_FILL_PATH);
        vgSetColor(paint, fillColour.Value());
        vgDrawPath(path, VG_FILL_PATH);
        
        vgDestroyPath(path);
        vgDestroyPaint(paint);
        }
    
    //Paint the top corner with aColour so we can identify the drawing.
    VGfloat fillColour[4];
    fillColour[0] = (VGfloat)aColour.Red() / 255.0f;
    fillColour[1] = (VGfloat)aColour.Green() / 255.0f;
    fillColour[2] = (VGfloat)aColour.Blue() / 255.0f;
    fillColour[3] = (VGfloat)aColour.Alpha() / 255.0f;
    
    vgSetfv(VG_CLEAR_COLOR, 4, fillColour);
    vgClear(0, 0, 20, size.iHeight);
    }

void CEglSurfaceBase::DrawContentL(const TRgb& aColour)
    {
    ActivateL();

    TSize size;
    eglQuerySurface(iDisplay, iSurface, EGL_WIDTH, &size.iWidth);
    eglQuerySurface(iDisplay, iSurface, EGL_HEIGHT, &size.iHeight);

    VGfloat fillColour[4];
    fillColour[0] = (VGfloat)aColour.Red() / 255.0f;
    fillColour[1] = (VGfloat)aColour.Green() / 255.0f;
    fillColour[2] = (VGfloat)aColour.Blue() / 255.0f;
    fillColour[3] = (VGfloat)aColour.Alpha() / 255.0f;

    vgSetfv(VG_CLEAR_COLOR, 4, fillColour);
    vgClear(0, 0, size.iWidth, size.iHeight);
    }

void CEglSurfaceBase::CreateL(TInt aIndex, const TPoint &aOffset)
    {
    SURF_ASSERT(aIndex < KSurfaceMaxIndex);
    SURF_ASSERT(aIndex == KSurfaceParams[aIndex].iIndex);

    TInt sizeIndex = 0;
    if (KSurfaceParams[aIndex].iXSize & LARGEST_POSSIBLE_FLAG)
        {
        sizeIndex = KMaxSurfaceSizes-1;
        }
    TInt err = KErrNone;
    do
        {
        TRAP(err, DoCreateL(aIndex, aOffset, sizeIndex));
        sizeIndex--;
        }
    while(err != KErrNone && sizeIndex >= 0);
    if (err != KErrNone)
        {
//        RDebug::Printf("%s:%d: err=%d (%d x %d)", __FILE__, __LINE__, err, iActualSize.iWidth, iActualSize.iHeight);
        User::Leave(err);
        }
    }

TInt CEglSurfaceBase::SubmitContent(TBool aShouldWaitForDisplay, TInt /* aRectsIndex */)
    {
    TInt err = Activate();
    if (err != KErrNone)
        {
        return err;
        }
    if (!eglSwapBuffers(iDisplay, iSurface))
        {
        EGLint err = eglGetError();
        RDebug::Printf("%s:%d: eglSwapBuffers gave error 0x%x", __FILE__, __LINE__, err);
        return KErrBadHandle;
        }
    if (aShouldWaitForDisplay)
        {
        // We are cheating: We just wait for a bit to ensure that the swapbuffer is actually finished.
        // There is no way to determine how long this takes, so we just grab a number that should be
        // large enough...
        User::After(100 * 1000);  // Wait 100ms.
        }
    return KErrNone;
    }

void CEglSurfaceBase::DrawContentL(TInt aIndex)
    {
    ActivateL();
    CTestVgImage *vgImage = CTestVgImage::NewL(aIndex);
    CleanupStack::PushL(vgImage);
    vgDrawImage(vgImage->VGImage());
    CleanupStack::PopAndDestroy(vgImage);
    }

void CEglSurfaceBase::GetSurfaceParamsL(TSurfaceParamsRemote &aParams)
    {
    RSurfaceManager surfaceManager;
    User::LeaveIfError(surfaceManager.Open());
    RSurfaceManager::TInfoBuf infoBuf;
    TInt err = surfaceManager.SurfaceInfo(SurfaceId(), infoBuf);
    User::LeaveIfError(err);
    surfaceManager.Close();
    RSurfaceManager::TSurfaceInfoV01& info = infoBuf();
    aParams.iSurfaceId = SurfaceId();
    aParams.iCommonParams.iAlignment = -1;  // N/A
    aParams.iCommonParams.iBuffers = info.iBuffers;
    aParams.iCommonParams.iOffsetToFirstBuffer = -1;
    aParams.iCommonParams.iPixelFormat = info.iPixelFormat;
    aParams.iCommonParams.iStrideInBytes = info.iStride;
    aParams.iCommonParams.iXSize = info.iSize.iWidth;
    aParams.iCommonParams.iYSize = info.iSize.iHeight;
    aParams.iCommonParams.iUseAttribList = KSurfaceParams[iParamIndex].iUseAttribList;
    for(TInt i = 0; i < KNumAttribs; i++)
        {
        aParams.iCommonParams.iAttribs[i] = KSurfaceParams[iParamIndex].iAttribs[i];
        }
    }


TInt CEglSurfaceBase::Notify(TNotification /*aWhen*/, TRequestStatus& /*aStatus*/, TUint32 /*aXTImes*/)
    {
    return KErrNotSupported;
    }

TInt CEglSurfaceBase::WaitFor(TNotification /*aWhen*/, TRequestStatus& /*aStatus*/,
        TInt /*aTimeoutinMicroseconds*/, TUint32 & /*aTimeStamp*/)
    {
    return KErrNotSupported;
    }

void CEglSurfaceBase::BaseCreateL(TInt aIndex, EGLint aSurfaceType)
    {
    iParamIndex = aIndex;
    iDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    
    EGLint err;
    if (iDisplay == EGL_NO_DISPLAY)
        {
        err = eglGetError();
        RDebug::Printf("%s:%d: err = 0x%x", __FILE__, __LINE__, err);
        User::Leave(KErrNotSupported);
        }
    
    EGLint nConfigs = 0;
    
    // TODO: Need to use differnet config attribs based on aIndex.
    EGLint configAttribs[] =
    {
        EGL_BUFFER_SIZE,    32,
        EGL_RED_SIZE,       8,
        EGL_GREEN_SIZE,     8,
        EGL_BLUE_SIZE,      8,
        EGL_ALPHA_SIZE,     8,
        EGL_SURFACE_TYPE,   EGL_WINDOW_BIT,
        EGL_RENDERABLE_TYPE,EGL_OPENVG_BIT,
        EGL_NONE
    };
    
    // Update surfacetype type to match 
    for(TInt i = 0; configAttribs[i] != EGL_NONE; i += 2)
        {
        if (configAttribs[i] == EGL_SURFACE_TYPE)
            {
            configAttribs[i+1] = aSurfaceType;
            }
        }
    // Need some way to configure the attribs ...
    eglChooseConfig(iDisplay, configAttribs, &iConfig, 1, &nConfigs);
    if (!nConfigs)
        {
        err = eglGetError();
        RDebug::Printf("%s:%d: err = %d", __FILE__, __LINE__, err);
        User::Leave(KErrNotSupported);
        }
    
    if (!eglBindAPI(EGL_OPENVG_API))
        {
        err = eglGetError();
        RDebug::Printf("%s:%d: err = %d", __FILE__, __LINE__, err);
        User::Leave(KErrNotSupported);
        }
    iContext = eglCreateContext(iDisplay, iConfig, 0, NULL);
    if (iContext == EGL_NO_CONTEXT)
        {
        err = eglGetError();
        //RDebug::Printf("%s:%d: err = %d", __FILE__, __LINE__, err);
        User::Leave(KErrNotSupported);
        }
    }

void CEglSurfaceBase::Destroy()
    {
    eglMakeCurrent(iDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    if (iSurface != EGL_NO_SURFACE)
        {
        eglDestroySurface(iDisplay, iSurface);
        iSurface = EGL_NO_SURFACE;
        }

    if (iDisplay != EGL_NO_DISPLAY)
        {
        eglDestroyContext(iDisplay, iContext);
        }
    }


class CWindow: public CBase
    {
public:
    static CWindow *NewL(TInt aIndex, const TPoint &aOffset, TInt aSizeIndex);
    RWindow& Window();
    ~CWindow();
private:
    void ConstructL(TInt aIndex, const TPoint &aOffset, TInt aSizeIndex);
    CWindow();

private:
    RWindow iWindow;
    RWindowGroup iWindowGroup;
    RWsSession iWsSession;
    };


CWindow* CWindow::NewL(TInt aIndex, const TPoint &aOffset, TInt aSizeIndex)
    {
    CWindow *self = new (ELeave) CWindow;
    CleanupStack::PushL(self);
    self->ConstructL(aIndex, aOffset, aSizeIndex);
    CleanupStack::Pop(self);
    return self;
    }


void CWindow::ConstructL(TInt aIndex, const TPoint &aOffset, TInt aSizeIndex)
    {
    RFbsSession::Connect();
    if (aIndex >= KSurfaceMaxIndex)
        {
        User::Leave(KErrOverflow);
        }
    User::LeaveIfError(iWsSession.Connect());
    iWindowGroup = RWindowGroup(iWsSession);
    User::LeaveIfError(iWindowGroup.Construct((TUint32)this));
    iWindow = RWindow(iWsSession);
    User::LeaveIfError(iWindow.Construct(iWindowGroup, -1U));
    TSurfaceParamsCommon winAttrib = KSurfaceParams[aIndex];
    TSize winSize;
    if (winAttrib.iXSize & LARGEST_POSSIBLE_FLAG)
        {
        winSize = TSize(KSurfaceSizes[aSizeIndex].iWidth, KSurfaceSizes[aSizeIndex].iHeight);
        }
    else
        {
        winSize = TSize(winAttrib.iXSize, winAttrib.iYSize);
        }
    iWindow.SetExtent(TPoint(winAttrib.iXPos + aOffset.iX, winAttrib.iYPos + aOffset.iY), winSize);
    iWindow.SetRequiredDisplayMode(winAttrib.iDisplayMode);
    iWindow.Activate();
    }


CWindow::~CWindow()
    {
    iWindow.Close();
    iWindowGroup.Close();
    iWsSession.Close();
    RFbsSession::Disconnect();
    }


CWindow::CWindow()
    {
    }


RWindow& CWindow::Window()
    {
    return iWindow;
    }


CEglWindowSurface* CEglWindowSurface::NewL()
    {
    CEglWindowSurface* self = new (ELeave) CEglWindowSurface;
    CleanupStack::PushL(self);
    self->ConstructL();
    CleanupStack::Pop(self);
    return self;
    }


void CEglWindowSurface::ConstructL()
    {
    }


CEglWindowSurface::CEglWindowSurface()
    {
    }


void CEglWindowSurface::DoCreateL(TInt aIndex, const TPoint &aOffset, TInt aSizeIndex)
    {
    iParamIndex = aIndex;
    iWindow = CWindow::NewL(aIndex, aOffset, aSizeIndex);
    iActualSize = iWindow->Window().Size();
    
    CEglSurfaceBase::BaseCreateL(aIndex, EGL_WINDOW_BIT);
    
    iSurface = eglCreateWindowSurface(iDisplay, iConfig, &iWindow->Window(), NULL);
    if (iSurface == EGL_NO_SURFACE)
        {
        EGLint err = eglGetError();
        RDebug::Printf("%s:%d: err = %x (%d x %d)", __FILE__, __LINE__, err, iActualSize.iWidth, iActualSize.iHeight);
        User::Leave(KErrNotSupported);
        }
    }


CEglWindowSurface::~CEglWindowSurface()
    {
    Destroy();
	eglReleaseThread();
    delete iWindow;
    }


TSurfaceId CEglWindowSurface::SurfaceId() const
    {
    // Default constructor for id sets it to a NULL-value, so if no window is created, we get
    // a defined surface id value that is invalid.
    TSurfaceId id;
    if (iWindow)
        {
        TSurfaceConfiguration surfConfig;
        iWindow->Window().GetBackgroundSurface(surfConfig);
        surfConfig.GetSurfaceId(id);
        }
    return id;
    }


const TText *CEglWindowSurface::GetSurfaceTypeStr() const
    {
    return _S("CEglWindowSurface");
    }


CEglPBufferSurface::CEglPBufferSurface()
    {
    }


CEglPBufferSurface::~CEglPBufferSurface()
    {
    Destroy();
	eglReleaseThread();
    }
    

CEglPBufferSurface* CEglPBufferSurface::NewL()
    {
    CEglPBufferSurface* self = new (ELeave) CEglPBufferSurface;
    CleanupStack::PushL(self);
    self->ConstructL();
    CleanupStack::Pop(self);
    return self;
    }


void CEglPBufferSurface::ConstructL()
    {
    }
    

const TText *CEglPBufferSurface::GetSurfaceTypeStr() const
    {
    return _S("CEglPBufferSurface");
    }


void CEglPBufferSurface::DoCreateL(TInt aIndex, const TPoint &/*aOffset*/, TInt aSizeIndex)
    {
    CEglSurfaceBase::BaseCreateL(aIndex, EGL_PBUFFER_BIT);

    EGLint attribs[] = 
            {
                EGL_WIDTH, 0,
                EGL_HEIGHT, 0,
                EGL_NONE,
            };
    if (KSurfaceParams[aIndex].iXSize & ELargestPossibleSurface)
        {
        iActualSize.iWidth = KSurfaceSizes[aSizeIndex].iWidth;
        iActualSize.iHeight = KSurfaceSizes[aSizeIndex].iHeight;
        }
    else
        {
        iActualSize.iWidth = KSurfaceParams[aIndex].iXSize;
        iActualSize.iHeight = KSurfaceParams[aIndex].iYSize;
        }
    for(TInt i = 0; attribs[i] != EGL_NONE; i += 2)
        {
        switch(attribs[i])
            {
            case EGL_HEIGHT:
                attribs[i+1] = iActualSize.iHeight;
                break;
            case EGL_WIDTH:
                attribs[i+1] = iActualSize.iWidth;
                break;
            }
        }
    
    iSurface = eglCreatePbufferSurface(iDisplay, iConfig, attribs);
    if (iSurface == EGL_NO_SURFACE)
        {
        EGLint err = eglGetError();
        User::Leave(KErrNotSupported);
        }
    }


TSurfaceId CEglPBufferSurface::SurfaceId() const
    {
    SURF_ASSERT(0);  // We shouldn't call this!
    return TSurfaceId::CreateNullId();
    }

TInt CEglPBufferSurface::SizeInBytes() const
    {
    // size of a pixel in bits. 
    EGLint size;
    if (!eglGetConfigAttrib(iDisplay, iConfig, EGL_BUFFER_SIZE, &size))
        {
        RDebug::Printf("Unable to get EGL_BUFFER_SIZE from config %d, err = %04x", iConfig, eglGetError());
        return 0;
        }
    
    return (KSurfaceParams[iParamIndex].iXSize * KSurfaceParams[iParamIndex].iYSize * size) / 8;
    }


// Factory function.
CSurface *CSurface::SurfaceFactoryL(TSurfaceType aSurfaceType)
    {
    switch(aSurfaceType)
        {
        case ESurfTypeRaw:
            return CRawSurface::NewL();
            
        case ESurfTypeEglWindow:
            return CEglWindowSurface::NewL();
            
        case ESurfTypeRawSingleBuffered:
            return CRawSingleBufferSurface::NewL();
            
        case ESurfTypePBuffer:
            return CEglPBufferSurface::NewL();
            
        default:
            SURF_ASSERT(0);
            return NULL;
        }
    }