|
1 // Copyright (c) 2009 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 // Description: |
|
14 // This class does performance tests for eglSwapBuffers() and eglSwapBuffersRegionNOK(). |
|
15 // The function eglSwapBuffersRegionNOK() is a vendor specific EGL extension and allows users to |
|
16 // perform region based surface updates. The test should show how the performance of the |
|
17 // extension function compares to the default one. |
|
18 // |
|
19 |
|
20 |
|
21 /** |
|
22 @file |
|
23 @test |
|
24 @internalComponent - Internal Symbian test code |
|
25 */ |
|
26 |
|
27 |
|
28 #include "teglswapbuffer.h" |
|
29 |
|
30 #include <VG/openvg.h> |
|
31 |
|
32 |
|
33 // If the condition that is passed to the macro is false |
|
34 // the macro leaves with the EGL error code |
|
35 #define EGL_CHECK_ERRORL(PASS) { if (!(PASS)) { SetTestStepResult(EFail); ERR_PRINTF2(KErrEgl, eglGetError()); User::Leave(eglGetError()); } } |
|
36 |
|
37 // Configuration for a Color16MAP - Window |
|
38 static const EGLint KConfigAttribs[] = |
|
39 { |
|
40 EGL_BUFFER_SIZE, 32, |
|
41 EGL_RED_SIZE, 8, |
|
42 EGL_GREEN_SIZE, 8, |
|
43 EGL_BLUE_SIZE, 8, |
|
44 EGL_ALPHA_SIZE, 8, |
|
45 EGL_RENDERABLE_TYPE, EGL_OPENVG_BIT, |
|
46 EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_VG_ALPHA_FORMAT_PRE_BIT, |
|
47 EGL_NONE |
|
48 }; |
|
49 |
|
50 // Additional attributes for the window surface |
|
51 static const EGLint KWindowSurfaceAttribs[] = |
|
52 { |
|
53 EGL_VG_ALPHA_FORMAT, EGL_VG_ALPHA_FORMAT_PRE, |
|
54 EGL_NONE |
|
55 }; |
|
56 |
|
57 // The test draws alternating backgrounds to show the affect |
|
58 // of different swapBuffer functions |
|
59 static const TInt KMaxClearColors = 2; |
|
60 static const VGfloat KClearColors[KMaxClearColors][4] = |
|
61 { |
|
62 {0.5f, 0.5f, 0.5f, 1.0f}, // gray |
|
63 {0.1f, 0.2f, 0.4f, 1.0f} // blue |
|
64 }; |
|
65 |
|
66 // Datatype for a function pointer to eglSwapBuffersRegionNOK() |
|
67 typedef EGLBoolean (*TFPtrEglSwapBuffersRegionNok) (EGLDisplay dpy, EGLSurface surface, EGLint numRects, const EGLint* rects); |
|
68 |
|
69 // Number of iterations, it defines how often the swapBuffer function is called |
|
70 const TInt KIterationsToTest = 1000; |
|
71 |
|
72 // Maximum number of rectangles for eglSwapBuffersRegionNOK() stress test |
|
73 const TInt KStressTestMaxNoRects = 100; |
|
74 // Defines the increase of number of rectangles for each iteration |
|
75 const TInt KStressTestNoRectsStepSize = 5; |
|
76 // Size of the dirty rectangles for the stress test |
|
77 const TSize KStressTestRectSize(10, 10); |
|
78 // Gap between the dirty Rectangles |
|
79 const TInt KStressTestRectGap = 3; |
|
80 |
|
81 // Window dimensions |
|
82 const TSize KWindowSize(200, 200); |
|
83 const TPoint KWindowPosition(30, 30); |
|
84 // Region dimensions (top left hand corner and bottom right hand corner) |
|
85 const TRect KRegionRect(50, 50, 60, 60); |
|
86 |
|
87 // This test step meassures the performance of eglSwapBuffers() |
|
88 _LIT(KTestStep0018,"GRAPHICS-UI-BENCH-S60-0018"); |
|
89 // This test step meassures the performance of eglSwapBuffersRegionNOK() |
|
90 _LIT(KTestStep0019,"GRAPHICS-UI-BENCH-S60-0019"); |
|
91 // This test step meassures the performance of eglSwapBuffersRegionNOK() with a lot of dirty rectangles |
|
92 _LIT(KTestStep0020,"GRAPHICS-UI-BENCH-S60-0020"); |
|
93 |
|
94 _LIT(KErrEgl, "EGL error 0x%x"); |
|
95 _LIT(KErrEglConfigNotSupported, "EGL config is not supported."); |
|
96 _LIT(KInfoRectangles, "Number of dirty rectangles: %d"); |
|
97 _LIT(KWarnStressTestRectCount, "Dirty rectangles for stress test don't fit onto window surface (%d of %d)."); |
|
98 |
|
99 |
|
100 CTEglSwapBuffer::CTEglSwapBuffer() |
|
101 { |
|
102 SetTestStepName(KTEglSwapBuffer); |
|
103 } |
|
104 |
|
105 CTEglSwapBuffer::~CTEglSwapBuffer() |
|
106 { |
|
107 // Make sure that this EGL status is active |
|
108 eglMakeCurrent(iEglDisplay, iEglSurface, iEglSurface, iEglContext); |
|
109 if (iEglContext != EGL_NO_CONTEXT) |
|
110 { |
|
111 eglDestroyContext(iEglDisplay, iEglContext); |
|
112 } |
|
113 if (iEglSurface != EGL_NO_SURFACE) |
|
114 { |
|
115 eglDestroySurface(iEglDisplay, iEglSurface); |
|
116 } |
|
117 // Call eglMakeCurrent() to ensure the surfaces and contexts are truly destroyed |
|
118 eglMakeCurrent(iEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); |
|
119 eglTerminate(iEglDisplay); |
|
120 eglReleaseThread(); |
|
121 |
|
122 iWindow.Close(); |
|
123 iWindowGroup.Close(); |
|
124 iWs.Close(); |
|
125 } |
|
126 |
|
127 /** |
|
128 * It's called by the test framework before the actual test. It's used |
|
129 * to do the preparation for the test. It's important to call the |
|
130 * baseclass implementation also. |
|
131 * |
|
132 * @return TVerdict code |
|
133 */ |
|
134 TVerdict CTEglSwapBuffer::doTestStepPreambleL() |
|
135 { |
|
136 CTe_graphicsperformanceSuiteStepBase::doTestStepPreambleL(); |
|
137 |
|
138 // Establish the connection to the window server and create |
|
139 // a WindowGroup and a Window object |
|
140 TESTNOERRORL(iWs.Connect()); |
|
141 iWindowGroup = RWindowGroup(iWs); |
|
142 TESTNOERRORL(iWindowGroup.Construct(0)); |
|
143 iWindow = RWindow(iWs); |
|
144 // The window is automatically fullscreen if it's a child of a window group |
|
145 TESTNOERRORL(iWindow.Construct(iWindowGroup, reinterpret_cast<TUint32>(this))); |
|
146 iWindow.SetSize(KWindowSize); |
|
147 iWindow.SetPosition(KWindowPosition); |
|
148 iWindow.Activate(); |
|
149 |
|
150 // Create display object |
|
151 iEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); |
|
152 EGL_CHECK_ERRORL(iEglDisplay != EGL_NO_DISPLAY); |
|
153 EGL_CHECK_ERRORL(eglInitialize(iEglDisplay, 0, 0)); |
|
154 |
|
155 // Choose EGL config |
|
156 EGLConfig matchingConfigs[1]; |
|
157 EGLint numConfigs = 0; |
|
158 eglChooseConfig(iEglDisplay, KConfigAttribs, matchingConfigs, 1, &numConfigs); |
|
159 if (numConfigs <= 0) // Abort the test if the EGL config is not supported |
|
160 { |
|
161 ERR_PRINTF1(KErrEglConfigNotSupported); |
|
162 SetTestStepError(KErrNotSupported); |
|
163 return TestStepResult(); |
|
164 } |
|
165 |
|
166 // Use OpenVG to draw |
|
167 EGL_CHECK_ERRORL(eglBindAPI(EGL_OPENVG_API)); |
|
168 |
|
169 // Create the window surface and the egl context and make them current |
|
170 iEglSurface = eglCreateWindowSurface(iEglDisplay, matchingConfigs[0], &iWindow, KWindowSurfaceAttribs); |
|
171 EGL_CHECK_ERRORL(iEglSurface != EGL_NO_SURFACE); |
|
172 iEglContext = eglCreateContext(iEglDisplay, matchingConfigs[0], EGL_NO_CONTEXT, NULL); |
|
173 EGL_CHECK_ERRORL(iEglContext != EGL_NO_CONTEXT); |
|
174 EGL_CHECK_ERRORL(eglMakeCurrent(iEglDisplay, iEglSurface, iEglSurface, iEglContext)); |
|
175 |
|
176 return TestStepResult(); |
|
177 } |
|
178 |
|
179 /** |
|
180 * Override of base class pure virtual function. |
|
181 * This implementation only gets called if the base class doTestStepPreambleL() did |
|
182 * not leave. That being the case, the current test result value should be EPass. |
|
183 * |
|
184 * @return TVerdict code |
|
185 */ |
|
186 TVerdict CTEglSwapBuffer::doTestStepL() |
|
187 { |
|
188 // Tests the performance of eglSwapBuffers() |
|
189 SetTestStepID(KTestStep0018); |
|
190 TRAPD(err, EglSwapBufferL()); |
|
191 if (err != KErrNone) |
|
192 { |
|
193 SetTestStepResult(EAbort); |
|
194 } |
|
195 RecordTestResultL(); |
|
196 |
|
197 // Tests the maximum performance of eglSwapBuffersRegionNOK() |
|
198 SetTestStepID(KTestStep0019); |
|
199 TRAP(err, EglSwapBufferRegionL()); |
|
200 if (err != KErrNone) |
|
201 { |
|
202 SetTestStepResult(EAbort); |
|
203 } |
|
204 RecordTestResultL(); |
|
205 |
|
206 // Stress tests the performance of eglSwapBuffersRegionNOK() |
|
207 SetTestStepID(KTestStep0020); |
|
208 for (TInt noRects = KStressTestNoRectsStepSize; noRects <= KStressTestMaxNoRects; noRects += KStressTestNoRectsStepSize) |
|
209 { |
|
210 // TRAP here is on purpose, normally you shouldn't use it in loops |
|
211 TRAP(err, EglSwapBufferRegionStressL(noRects)); |
|
212 if (err != KErrNone) |
|
213 { |
|
214 SetTestStepResult(EAbort); |
|
215 } |
|
216 } |
|
217 RecordTestResultL(); |
|
218 |
|
219 // Close the test and return result to the testframework |
|
220 CloseTMSGraphicsStep(); |
|
221 return TestStepResult(); |
|
222 } |
|
223 |
|
224 /** |
|
225 @SYMTestCaseID GRAPHICS-UI-BENCH-S60-0018 |
|
226 |
|
227 @SYMTestPriority 1 |
|
228 |
|
229 @SYMPREQ 2677 |
|
230 |
|
231 @SYMTestCaseDesc |
|
232 Tests how long it takes to swap window surface buffers if the whole surface is updated. |
|
233 |
|
234 @SYMTestActions |
|
235 Clear the window surface with alternating background colors, swap the surface buffers |
|
236 and measure how long it takes. |
|
237 |
|
238 @SYMTestExpectedResults |
|
239 Test should pass and print the average framerate to a log file. |
|
240 */ |
|
241 void CTEglSwapBuffer::EglSwapBufferL() |
|
242 { |
|
243 // Initialise uibench and reset the timer |
|
244 iProfiler->InitResults(); |
|
245 // Perform the test |
|
246 for(TInt i = KIterationsToTest; i > 0; --i) |
|
247 { |
|
248 // Clean the surface with the background color |
|
249 vgSetfv(VG_CLEAR_COLOR, 4, KClearColors[i % KMaxClearColors]); |
|
250 vgClear(0, 0, KWindowSize.iWidth, KWindowSize.iHeight); |
|
251 // Swap the surface buffers |
|
252 EGL_CHECK_ERRORL(eglSwapBuffers(iEglDisplay, iEglSurface)); |
|
253 } |
|
254 // Mark the time and print the results to the log file |
|
255 iProfiler->MarkResultSetL(); |
|
256 iProfiler->ResultsAnalysisFrameRate(KTestStep0018, 0, 0, 0, |
|
257 KIterationsToTest, KWindowSize.iWidth * KWindowSize.iHeight); |
|
258 } |
|
259 |
|
260 /** |
|
261 @SYMTestCaseID GRAPHICS-UI-BENCH-S60-0019 |
|
262 |
|
263 @SYMTestPriority 1 |
|
264 |
|
265 @SYMPREQ 2677 |
|
266 |
|
267 @SYMTestCaseDesc |
|
268 Tests how long it takes to swap window surface buffers if only a small region is updated. This |
|
269 test should show the maximum possible performance increase. |
|
270 |
|
271 @SYMTestActions |
|
272 Clear the window surface with alternating background colors, swap the surface buffers |
|
273 and measure how long it takes. |
|
274 |
|
275 @SYMTestExpectedResults |
|
276 Test should pass and print the average framerate to a log file. |
|
277 */ |
|
278 void CTEglSwapBuffer::EglSwapBufferRegionL() |
|
279 { |
|
280 // Number of rectangles |
|
281 EGLint count = 1; |
|
282 // Rectangle for partial swap buffer function |
|
283 EGLint rects[] = {KRegionRect.iTl.iX, KRegionRect.iTl.iY, KRegionRect.Width(), KRegionRect.Height()}; |
|
284 // Get the function pointer for eglSwapBuffersRegionNOK() |
|
285 TFPtrEglSwapBuffersRegionNok pfnEglSwapBuffersRegionNok = reinterpret_cast<TFPtrEglSwapBuffersRegionNok>(eglGetProcAddress("eglSwapBuffersRegionNOK")); |
|
286 EGL_CHECK_ERRORL(pfnEglSwapBuffersRegionNok); |
|
287 |
|
288 // Clear the surface |
|
289 vgSetfv(VG_CLEAR_COLOR, 4, KClearColors[0]); |
|
290 vgClear(0, 0, KWindowSize.iWidth, KWindowSize.iHeight); |
|
291 EGL_CHECK_ERRORL(eglSwapBuffers(iEglDisplay, iEglSurface)); |
|
292 |
|
293 // Initialise uibench and reset the timer |
|
294 iProfiler->InitResults(); |
|
295 // Perform the test |
|
296 for(TInt i = KIterationsToTest; i > 0; --i) |
|
297 { |
|
298 // Clean the surface with the background color |
|
299 vgSetfv(VG_CLEAR_COLOR, 4, KClearColors[i % KMaxClearColors]); |
|
300 vgClear(0, 0, KWindowSize.iWidth, KWindowSize.iHeight); |
|
301 // Swap the surface buffers |
|
302 EGL_CHECK_ERRORL(pfnEglSwapBuffersRegionNok(iEglDisplay, iEglSurface, count, rects)); |
|
303 } |
|
304 // Mark the time and print the results to the log file |
|
305 iProfiler->MarkResultSetL(); |
|
306 iProfiler->ResultsAnalysisFrameRate(KTestStep0019, 0, 0, 0, |
|
307 KIterationsToTest, KWindowSize.iWidth * KWindowSize.iHeight); |
|
308 } |
|
309 |
|
310 /** |
|
311 @SYMTestCaseID GRAPHICS-UI-BENCH-S60-0020 |
|
312 |
|
313 @SYMTestPriority 1 |
|
314 |
|
315 @SYMPREQ 2677 |
|
316 |
|
317 @SYMTestCaseDesc |
|
318 Tests how long it takes to swap window surface buffers if only a small region is updated. This |
|
319 test should show the maximum possible performance increase. |
|
320 |
|
321 @SYMTestActions |
|
322 Clear the window surface with alternating background colors, swap the surface buffers |
|
323 and measure how long it takes. |
|
324 |
|
325 @SYMTestExpectedResults |
|
326 Test should pass and print the average framerate to a log file. |
|
327 */ |
|
328 void CTEglSwapBuffer::EglSwapBufferRegionStressL(EGLint aCount) |
|
329 { |
|
330 TInt* rects = static_cast<TInt*>(User::AllocLC(sizeof(TInt) * 4 * aCount)); |
|
331 TInt actualRectCount = 0; |
|
332 TInt idx = 0; |
|
333 for (TInt y = 0; (y < KWindowSize.iHeight - KStressTestRectSize.iHeight - 1) && (actualRectCount < aCount); y += KStressTestRectSize.iHeight + KStressTestRectGap) |
|
334 { |
|
335 for (TInt x = 0; (x < KWindowSize.iWidth - KStressTestRectSize.iWidth - 1) && (actualRectCount < aCount); x += KStressTestRectSize.iWidth + KStressTestRectGap) |
|
336 { |
|
337 rects[idx++] = x; |
|
338 rects[idx++] = y; |
|
339 rects[idx++] = KStressTestRectSize.iWidth; |
|
340 rects[idx++] = KStressTestRectSize.iHeight; |
|
341 actualRectCount++; |
|
342 } |
|
343 } |
|
344 TESTL(actualRectCount > 0); |
|
345 if (actualRectCount != aCount) |
|
346 { |
|
347 WARN_PRINTF3(KWarnStressTestRectCount, actualRectCount, aCount); |
|
348 } |
|
349 |
|
350 // Get the function pointer for eglSwapBuffersRegionNOK() |
|
351 TFPtrEglSwapBuffersRegionNok pfnEglSwapBuffersRegionNok = reinterpret_cast<TFPtrEglSwapBuffersRegionNok>(eglGetProcAddress("eglSwapBuffersRegionNOK")); |
|
352 EGL_CHECK_ERRORL(pfnEglSwapBuffersRegionNok); |
|
353 |
|
354 // Clear the surface |
|
355 vgSetfv(VG_CLEAR_COLOR, 4, KClearColors[0]); |
|
356 vgClear(0, 0, KWindowSize.iWidth, KWindowSize.iHeight); |
|
357 EGL_CHECK_ERRORL(eglSwapBuffers(iEglDisplay, iEglSurface)); |
|
358 |
|
359 // Initialise uibench and reset the timer |
|
360 iProfiler->InitResults(); |
|
361 // Perform the test |
|
362 for(TInt i = KIterationsToTest; i > 0; --i) |
|
363 { |
|
364 // Clean the surface with the background color |
|
365 vgSetfv(VG_CLEAR_COLOR, 4, KClearColors[i % KMaxClearColors]); |
|
366 vgClear(0, 0, KWindowSize.iWidth, KWindowSize.iHeight); |
|
367 // Swap the surface buffers |
|
368 EGL_CHECK_ERRORL(pfnEglSwapBuffersRegionNok(iEglDisplay, iEglSurface, actualRectCount, rects)); |
|
369 } |
|
370 // Mark the time and print the results to the log file |
|
371 iProfiler->MarkResultSetL(); |
|
372 INFO_PRINTF2(KInfoRectangles, aCount); |
|
373 iProfiler->ResultsAnalysisFrameRate(KTestStep0020, 0, 0, 0, |
|
374 KIterationsToTest, KWindowSize.iWidth * KWindowSize.iHeight); |
|
375 CleanupStack::PopAndDestroy(rects); |
|
376 } |