os/graphics/egl/egltest/src/egltest_benchmark_swapbuffers.cpp
changeset 0 bde4ae8d615e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/os/graphics/egl/egltest/src/egltest_benchmark_swapbuffers.cpp	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,384 @@
     1.4 +// Copyright (c) 2009 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 +// This class does performance tests for eglSwapBuffers() and eglSwapBuffersRegionNOK().
    1.18 +// The function eglSwapBuffersRegionNOK() is a vendor specific EGL extension and allows users to 
    1.19 +// perform region based surface updates. The test should show how the performance of the
    1.20 +// extension function compares to the default one. 
    1.21 +// 
    1.22 +
    1.23 +/**
    1.24 + @file
    1.25 + @test 
    1.26 +*/
    1.27 +
    1.28 +#include "egltest_benchmark_swapbuffers.h"
    1.29 +
    1.30 +#include <VG/openvg.h>
    1.31 +#include <test/tprofiler.h>
    1.32 +#include <test/egltestcommonutils.h>
    1.33 +#include <test/egltestcommoninisettings.h>
    1.34 +
    1.35 +_LIT(KSwapBuffersSection, "SwapBuffers");
    1.36 +
    1.37 +// The test draws alternating backgrounds to show the affect
    1.38 +// of different swapBuffer functions 
    1.39 +static const TInt KMaxClearColors = 2;
    1.40 +static const VGfloat KClearColors[KMaxClearColors][4] = 
    1.41 +    {
    1.42 +        {0.5f, 0.5f, 0.5f, 1.0f}, // gray
    1.43 +        {0.1f, 0.2f, 0.4f, 1.0f}  // blue
    1.44 +    };
    1.45 +
    1.46 +// Number of iterations, it defines how often the swapBuffer function is called
    1.47 +static const TInt KIterationsToTest = 10;
    1.48 +
    1.49 +// Maximum number of rectangles for eglSwapBuffersRegionNOK() stress test
    1.50 +static const TInt KStressTestMaxNoRects = 100;
    1.51 +// Defines the increase of number of rectangles for each iteration
    1.52 +static const TInt KStressTestNoRectsStepSize = 5;
    1.53 +// Gap between the dirty Rectangles
    1.54 +static const TInt KStressTestRectGap = 3;
    1.55 +
    1.56 +// This test step meassures the performance of eglSwapBuffers()
    1.57 +_LIT(KTestStep0528,"GRAPHICS-EGL-0528");
    1.58 +// This test step meassures the performance of eglSwapBuffersRegionNOK()
    1.59 +_LIT(KTestStep0529,"GRAPHICS-EGL-0529");
    1.60 +// This test step meassures the performance of eglSwapBuffersRegionNOK() with a lot of dirty rectangles
    1.61 +_LIT(KTestStep0530,"GRAPHICS-EGL-0530");
    1.62 +
    1.63 +_LIT(KErrEglConfigNotSupported, "EGL config is not supported.");
    1.64 +_LIT(KInfoRectangles, "Number of dirty rectangles: %d");
    1.65 +_LIT(KWarnStressTestRectCount, "Dirty rectangles for stress test don't fit onto window surface (%d of %d).");
    1.66 +
    1.67 +_LIT(KEglSwapBuffersRegionNokMsg, "eglSwapBuffersRegionNOK extension is not supported.");
    1.68 +
    1.69 +CEglTest_Benchmark_SwapBuffers::CEglTest_Benchmark_SwapBuffers()
    1.70 +	{
    1.71 +	SetTestStepName(KBenchmark_SwapBuffers);
    1.72 +	}
    1.73 +	
    1.74 +CEglTest_Benchmark_SwapBuffers::~CEglTest_Benchmark_SwapBuffers()	
    1.75 +	{
    1.76 +    // empty
    1.77 +	}
    1.78 +
    1.79 +/**
    1.80 + * It's called by the test framework before the actual test. It's used
    1.81 + * to do the preparation for the test. It's important to call the
    1.82 + * baseclass implementation also.
    1.83 + * 
    1.84 + * @return test framework code
    1.85 + * @leave Standard system errors
    1.86 + */
    1.87 +TVerdict CEglTest_Benchmark_SwapBuffers::doTestStepPreambleL()
    1.88 +    {
    1.89 +    CEglTestStep::doTestStepPreambleL();
    1.90 +    iProfiler = CTProfiler::NewL(*this);
    1.91 +    //read parameters from config (WindowSize)
    1.92 +    CEglTestCommonIniSettings* iniParser = CEglTestCommonIniSettings::NewL();
    1.93 +    CleanupStack::PushL(iniParser);
    1.94 +    iWindowSize = iniParser->GetWindowSize(KSwapBuffersSection);
    1.95 +    if(iWindowSize == TSize(0,0))
    1.96 +        {
    1.97 +        ERR_PRINTF1(_L("The window size whether is not specified in INI file or is TSize(0,0), the test will not be executed!"));
    1.98 +        User::Leave(KErrArgument);      
    1.99 +        }
   1.100 +    CleanupStack::PopAndDestroy(iniParser);
   1.101 +    
   1.102 +    // Establish the connection to the window server and create
   1.103 +    // a WindowGroup and a Window object
   1.104 +    TESTL(iWs.Connect() == KErrNone);    
   1.105 +    iWindowGroup = RWindowGroup(iWs);
   1.106 +    TESTL(iWindowGroup.Construct(0) == KErrNone);  
   1.107 +    iWindow = RWindow(iWs);
   1.108 +    // The window is automatically fullscreen if it's a child of a window group
   1.109 +    TESTL(iWindow.Construct(iWindowGroup, reinterpret_cast<TUint32>(this)) == KErrNone);
   1.110 +    iWindow.SetSize(iWindowSize);
   1.111 +    // Window dimensions
   1.112 +    const TPoint KWindowPosition(30, 30);
   1.113 +    iWindow.SetPosition(KWindowPosition);
   1.114 +    iWindow.Activate();
   1.115 +        
   1.116 +    // Create display object
   1.117 +    CEglTestStep::GetDisplayL();
   1.118 +    ASSERT_EGL_TRUE(eglInitialize(iDisplay, 0, 0));
   1.119 +        
   1.120 +    // Choose EGL config
   1.121 +    EGLConfig matchingConfigs[1];
   1.122 +    EGLint numConfigs = 0;
   1.123 +    eglChooseConfig(iDisplay, KConfigAttribs[2], matchingConfigs, 1, &numConfigs);
   1.124 +    if (numConfigs <= 0) // Abort the test if the EGL config is not supported
   1.125 +        {
   1.126 +        ERR_PRINTF1(KErrEglConfigNotSupported);
   1.127 +        SetTestStepError(KErrNotSupported);
   1.128 +        return TestStepResult();
   1.129 +        }
   1.130 +    
   1.131 +    // Use OpenVG to draw
   1.132 +    ASSERT_EGL_TRUE(eglBindAPI(EGL_OPENVG_API));
   1.133 +    
   1.134 +    // Create the window surface and the egl context and make them current
   1.135 +    iEglSurface = eglCreateWindowSurface(iDisplay, matchingConfigs[0], &iWindow, KPixmapAttribsVgAlphaFormatPre);
   1.136 +    ASSERT_EGL_TRUE(iEglSurface != EGL_NO_SURFACE);
   1.137 +    iEglContext = eglCreateContext(iDisplay, matchingConfigs[0], EGL_NO_CONTEXT, NULL);
   1.138 +    ASSERT_EGL_TRUE(iEglContext != EGL_NO_CONTEXT);
   1.139 +    ASSERT_EGL_TRUE(eglMakeCurrent(iDisplay, iEglSurface, iEglSurface, iEglContext));
   1.140 +    
   1.141 +    // Get the function pointer for eglSwapBuffersRegionNOK()
   1.142 +    iPfnEglSwapBuffersRegionNok = reinterpret_cast<PFNEGLSWAPBUFFERSREGIONNOKPROC>(eglGetProcAddress("eglSwapBuffersRegionNOK"));
   1.143 +    
   1.144 +    return TestStepResult();
   1.145 +    }
   1.146 +
   1.147 +TVerdict CEglTest_Benchmark_SwapBuffers::doTestStepPostambleL()
   1.148 +    {
   1.149 +    // Make sure that this EGL status is active
   1.150 +    eglMakeCurrent(iDisplay, iEglSurface, iEglSurface, iEglContext);
   1.151 +    // Call eglMakeCurrent() to ensure the surfaces and contexts are truly destroyed
   1.152 +    eglMakeCurrent(iDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
   1.153 +    if (iEglContext != EGL_NO_CONTEXT)
   1.154 +        {
   1.155 +        eglDestroyContext(iDisplay, iEglContext);
   1.156 +        }
   1.157 +    if (iEglSurface != EGL_NO_SURFACE)
   1.158 +        {
   1.159 +        eglDestroySurface(iDisplay, iEglSurface);
   1.160 +        }   
   1.161 +    eglTerminate(iDisplay);
   1.162 +    eglReleaseThread();
   1.163 +    
   1.164 +    iWindow.Close();
   1.165 +    iWindowGroup.Close();
   1.166 +    iWs.Close();
   1.167 +    
   1.168 +    delete iProfiler;
   1.169 +    iProfiler = NULL;
   1.170 +
   1.171 +    return CEglTestStep::doTestStepPostambleL();
   1.172 +    }
   1.173 +
   1.174 +/**
   1.175 + * Override of base class pure virtual function.
   1.176 + * This implementation only gets called if the base class doTestStepPreambleL() did
   1.177 + * not leave. That being the case, the current test result value should be EPass.
   1.178 + *
   1.179 + * @return test framework code
   1.180 + */
   1.181 +TVerdict CEglTest_Benchmark_SwapBuffers::doTestStepL()
   1.182 +    {
   1.183 +    // Tests  the performance of eglSwapBuffers()
   1.184 +    SetTestStepID(KTestStep0528);    
   1.185 +    TRAPD(err, EglSwapBufferL());
   1.186 +    if (err != KErrNone)
   1.187 +        {
   1.188 +        SetTestStepResult(EAbort);
   1.189 +        }    
   1.190 +    RecordTestResultL();
   1.191 +    
   1.192 +    // We only perform swap region benchmark test if eglSwapBuffersRegionNOK extension is supported
   1.193 +    if (iPfnEglSwapBuffersRegionNok != NULL)
   1.194 +        {
   1.195 +        // Tests the maximum performance of eglSwapBuffersRegionNOK()
   1.196 +        SetTestStepID(KTestStep0529);    
   1.197 +        TRAP(err, EglSwapBufferRegionL());
   1.198 +        if (err != KErrNone)
   1.199 +            {
   1.200 +            SetTestStepResult(EAbort);
   1.201 +            }    
   1.202 +        RecordTestResultL();
   1.203 +        
   1.204 +        // Stress tests the performance of eglSwapBuffersRegionNOK()
   1.205 +        SetTestStepID(KTestStep0530);    
   1.206 +        for (TInt noRects = KStressTestNoRectsStepSize; noRects <= KStressTestMaxNoRects; noRects += KStressTestNoRectsStepSize)
   1.207 +            {
   1.208 +            // TRAP here is on purpose, normally you shouldn't use it in loops
   1.209 +            TRAP(err, EglSwapBufferRegionStressL(noRects));
   1.210 +            if (err != KErrNone)
   1.211 +                {
   1.212 +                ERR_PRINTF2(_L("EglSwapBufferRegionStressL (leave code: %d)."), err);
   1.213 +                SetTestStepResult(EAbort);
   1.214 +                }
   1.215 +            }
   1.216 +        RecordTestResultL();
   1.217 +        }
   1.218 +    else
   1.219 +        {
   1.220 +        INFO_PRINTF1(KEglSwapBuffersRegionNokMsg);
   1.221 +        }
   1.222 +    
   1.223 +    // Close the test and return result to the testframework
   1.224 +    CloseTMSGraphicsStep();    
   1.225 +    return TestStepResult();
   1.226 +	}
   1.227 +
   1.228 +/**
   1.229 +@SYMTestCaseID GRAPHICS-EGL-0528
   1.230 +
   1.231 +@SYMTestPriority 1
   1.232 +
   1.233 +@SYMPREQ 2677
   1.234 +
   1.235 +@SYMTestCaseDesc
   1.236 +Tests how long it takes to swap window surface buffers if the whole surface is updated.
   1.237 +
   1.238 +@SYMTestActions
   1.239 +Clear the window surface with alternating background colors, swap the surface buffers 
   1.240 +(using eglSwapBuffers extension)and measure how long it takes.
   1.241 +
   1.242 +@SYMTestExpectedResults
   1.243 +Test should pass and print the average framerate to a log file.
   1.244 +*/
   1.245 +void CEglTest_Benchmark_SwapBuffers::EglSwapBufferL()
   1.246 +    {    
   1.247 +    //-------   start profiling
   1.248 +    iProfiler->InitResults();
   1.249 +    // Perform the test
   1.250 +    for(TInt i = KIterationsToTest; i > 0; --i)
   1.251 +        {
   1.252 +        // Clean the surface with the background color
   1.253 +        vgSetfv(VG_CLEAR_COLOR, 4, KClearColors[i % KMaxClearColors]);
   1.254 +        vgClear(0, 0, iWindowSize.iWidth, iWindowSize.iHeight);
   1.255 +        // Swap the surface buffers
   1.256 +        ASSERT_EGL_TRUE(eglSwapBuffers(iDisplay, iEglSurface));
   1.257 +        }
   1.258 +    // Mark the time and print the results to the log file
   1.259 +    iProfiler->MarkResultSetL();
   1.260 +    iProfiler->ResultsAnalysisFrameRate(KTestStep0528, 0, 0, 0,
   1.261 +            KIterationsToTest, iWindowSize.iWidth * iWindowSize.iHeight);   
   1.262 +    }
   1.263 +
   1.264 +/**
   1.265 +@SYMTestCaseID GRAPHICS-EGL-0529
   1.266 +
   1.267 +@SYMTestPriority 1
   1.268 +
   1.269 +@SYMPREQ 2677
   1.270 +
   1.271 +@SYMTestCaseDesc
   1.272 +Tests how long it takes to swap window surface buffers if only a small region is updated. This
   1.273 +test should show the maximum possible performance increase.
   1.274 +
   1.275 +@SYMTestActions
   1.276 +Clear the window surface with alternating background colors, swap the surface buffers
   1.277 +and measure how long it takes.
   1.278 +
   1.279 +@SYMTestExpectedResults
   1.280 +Test should pass and print the average framerate to a log file.
   1.281 +The average time shall be made available in an easy-to-use format for further 
   1.282 +analysis and comparison.
   1.283 +*/
   1.284 +void CEglTest_Benchmark_SwapBuffers::EglSwapBufferRegionL()
   1.285 +    {
   1.286 +    // Region dimensions (top left hand corner and bottom right hand corner)
   1.287 +    const TRect KRegionRect(50, 50, 60, 60);
   1.288 +    // Rectangle for partial swap buffer function
   1.289 +    const EGLint rects[] = {KRegionRect.iTl.iX, KRegionRect.iTl.iY, KRegionRect.Width(), KRegionRect.Height()};
   1.290 +    // Number of rectangles (one rectangle consist of 4 values)
   1.291 +    const EGLint count = (sizeof(rects) / (sizeof(rects[0] * 4)));
   1.292 +            
   1.293 +    // We obtain the func ptr in doTestStepPreambleL and only execute this test if it is not null
   1.294 +    TESTL(iPfnEglSwapBuffersRegionNok != NULL);
   1.295 +    
   1.296 +    // Clear the surface
   1.297 +    vgSetfv(VG_CLEAR_COLOR, 4, KClearColors[0]);
   1.298 +    vgClear(0, 0, iWindowSize.iWidth, iWindowSize.iHeight);
   1.299 +    ASSERT_EGL_TRUE(eglSwapBuffers(iDisplay, iEglSurface));
   1.300 +    
   1.301 +    // Initialise uibench and reset the timer
   1.302 +    iProfiler->InitResults();
   1.303 +    // Perform the test
   1.304 +    for(TInt i = KIterationsToTest; i > 0; --i)
   1.305 +        {
   1.306 +        // Clean the surface with the background color
   1.307 +        vgSetfv(VG_CLEAR_COLOR, 4, KClearColors[i % KMaxClearColors]);
   1.308 +        vgClear(0, 0, iWindowSize.iWidth, iWindowSize.iHeight);
   1.309 +        // Swap the surface buffers
   1.310 +        ASSERT_EGL_TRUE(iPfnEglSwapBuffersRegionNok(iDisplay, iEglSurface, count, rects));
   1.311 +        }
   1.312 +    // Mark the time and print the results to the log file
   1.313 +    iProfiler->MarkResultSetL();
   1.314 +    iProfiler->ResultsAnalysisFrameRate(KTestStep0529, 0, 0, 0,
   1.315 +            KIterationsToTest, iWindowSize.iWidth * iWindowSize.iHeight);
   1.316 +    }
   1.317 +
   1.318 +/**
   1.319 +@SYMTestCaseID GRAPHICS-EGL-0530
   1.320 +
   1.321 +@SYMTestPriority 1
   1.322 +
   1.323 +@SYMPREQ 2677
   1.324 +
   1.325 +@SYMTestCaseDesc
   1.326 +Stress test to show maximum possible performance increase when adding Rectangles to the region i.e. adding 100 rectangles with step size 5 
   1.327 +
   1.328 +@SYMTestActions
   1.329 +Clear the window surface with alternating background colors, swap the surface buffers
   1.330 +and measure how long it takes.
   1.331 +
   1.332 +@SYMTestExpectedResults
   1.333 +Test should pass and print the average framerate to a log file.
   1.334 +
   1.335 +@Param aCount
   1.336 +Number of rectangles to add to the region
   1.337 +*/
   1.338 +void CEglTest_Benchmark_SwapBuffers::EglSwapBufferRegionStressL(EGLint aCount)
   1.339 +    {
   1.340 +    TInt* rects = static_cast<TInt*>(User::AllocLC(sizeof(TInt) * 4 * aCount));
   1.341 +    TInt actualRectCount = 0;
   1.342 +    TInt idx = 0;
   1.343 +    // Size of the dirty rectangles for the stress test
   1.344 +    const TSize KStressTestRectSize(10, 10);
   1.345 +    for (TInt y = 0; (y < iWindowSize.iHeight - KStressTestRectSize.iHeight - 1) && (actualRectCount < aCount); y += KStressTestRectSize.iHeight + KStressTestRectGap)
   1.346 +        {
   1.347 +        for (TInt x = 0; (x < iWindowSize.iWidth - KStressTestRectSize.iWidth - 1) && (actualRectCount < aCount); x += KStressTestRectSize.iWidth + KStressTestRectGap)
   1.348 +            {
   1.349 +            rects[idx++] = x;
   1.350 +            rects[idx++] = y;
   1.351 +            rects[idx++] = KStressTestRectSize.iWidth;
   1.352 +            rects[idx++] = KStressTestRectSize.iHeight;
   1.353 +            actualRectCount++;
   1.354 +            }
   1.355 +        }
   1.356 +    TESTL(actualRectCount > 0);
   1.357 +    if (actualRectCount != aCount)
   1.358 +        {
   1.359 +        WARN_PRINTF3(KWarnStressTestRectCount, actualRectCount, aCount);
   1.360 +        }
   1.361 +    
   1.362 +    // We obtain the func ptr in doTestStepPreambleL and only execute this test if it is not null
   1.363 +    TESTL(iPfnEglSwapBuffersRegionNok != NULL);
   1.364 +    
   1.365 +    // Clear the surface
   1.366 +    vgSetfv(VG_CLEAR_COLOR, 4, KClearColors[0]);
   1.367 +    vgClear(0, 0, iWindowSize.iWidth, iWindowSize.iHeight);
   1.368 +    ASSERT_EGL_TRUE(eglSwapBuffers(iDisplay, iEglSurface));
   1.369 +    
   1.370 +    // Initialise uibench and reset the timer
   1.371 +    iProfiler->InitResults();
   1.372 +    // Perform the test
   1.373 +    for(TInt i = KIterationsToTest; i > 0; --i)
   1.374 +        {
   1.375 +        // Clean the surface with the background color
   1.376 +        vgSetfv(VG_CLEAR_COLOR, 4, KClearColors[i % KMaxClearColors]);
   1.377 +        vgClear(0, 0, iWindowSize.iWidth, iWindowSize.iHeight);
   1.378 +        // Swap the surface buffers
   1.379 +        ASSERT_EGL_TRUE(iPfnEglSwapBuffersRegionNok(iDisplay, iEglSurface, actualRectCount, rects));
   1.380 +        }
   1.381 +    // Mark the time and print the results to the log file
   1.382 +    iProfiler->MarkResultSetL();
   1.383 +    INFO_PRINTF2(KInfoRectangles, aCount);
   1.384 +    iProfiler->ResultsAnalysisFrameRate(KTestStep0530, 0, 0, 0,
   1.385 +            KIterationsToTest, iWindowSize.iWidth * iWindowSize.iHeight);
   1.386 +    CleanupStack::PopAndDestroy(rects);
   1.387 +    }