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 + }