Don't abort just because libosso failed to initialize
[glmemperf] / glmemperf.cpp
1 /**
2  * OpenGL ES 2.0 memory performance estimator
3  * Copyright (C) 2009 Nokia
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * \author Sami Kyöstilä <sami.kyostila@nokia.com>
20  */
21 #include <GLES2/gl2.h>
22 #include <GLES2/gl2ext.h>
23 #include <X11/Xutil.h>
24 #include <EGL/egl.h>
25 #include <string>
26 #include <unistd.h>
27 #include <time.h>
28 #include <memory>
29 #include <list>
30 #include <iostream>
31 #include <algorithm>
32 #include <sys/stat.h>
33
34 #include "native.h"
35 #include "util.h"
36 #include "test.h"
37 #include "blittest.h"
38 #include "cleartest.h"
39 #include "pixmapblittest.h"
40 #include "fboblittest.h"
41 #include "shaderblittest.h"
42 #include "cpuinterleavingtest.h"
43 #include "config.h"
44
45 #if defined(HAVE_LIBOSSO)
46 #include <libosso.h>
47 #endif
48
49 /**
50  *  Command line options
51  */
52 static struct
53 {
54     int                    bitsPerPixel;
55     bool                   verbose;
56     int                    minTime;
57     bool                   listTests;
58     std::list<std::string> includedTests;
59     std::list<std::string> excludedTests;
60 } options;
61
62 /** Shared EGL objects */
63 struct Context ctx;
64
65 #if defined(HAVE_LIBOSSO)
66 osso_context_t* ossoContext;
67 #endif
68
69 bool initializeEgl(int width, int height, const EGLint* configAttrs, const EGLint* contextAttrs)
70 {
71     EGLint configCount = 0;
72     
73 #if defined(HAVE_LIBOSSO)
74     ossoContext = osso_initialize("com.nokia.memperf", "1.0", FALSE, NULL);
75     if (!ossoContext)
76     {
77         printf("Warning: osso_initialize failed\n");
78     }
79 #endif
80
81     ctx.dpy = eglGetDisplay(ctx.nativeDisplay);
82     ASSERT_EGL();
83    
84     eglInitialize(ctx.dpy, NULL, NULL);
85     eglChooseConfig(ctx.dpy, configAttrs, &ctx.config, 1, &configCount);
86     ASSERT_EGL();
87
88     if (!configCount)
89     {
90         printf("Config not found\n");
91         goto out_error;
92     }
93
94     if (options.verbose)
95     {
96         printf("Config attributes:\n");
97         dumpConfig(ctx.dpy, ctx.config);
98     }
99
100     if (!nativeCreateWindow(ctx.nativeDisplay, ctx.dpy, ctx.config, __FILE__,
101                             width, height, &ctx.win))
102     {
103         printf("Unable to create a window\n");
104         goto out_error;
105     }
106
107     ctx.context = eglCreateContext(ctx.dpy, ctx.config, EGL_NO_CONTEXT, contextAttrs);
108     ASSERT_EGL();
109     if (!ctx.context)
110     {
111         printf("Unable to create a context\n");
112         goto out_error;
113     }
114     
115     ctx.surface = eglCreateWindowSurface(ctx.dpy, ctx.config, ctx.win, NULL);
116     ASSERT_EGL();
117     if (!ctx.surface)
118     {
119         printf("Unable to create a surface\n");
120         goto out_error;
121     }
122
123     eglMakeCurrent(ctx.dpy, ctx.surface, ctx.surface, ctx.context);
124     ASSERT_EGL();
125     
126     eglSwapInterval(ctx.dpy, 0);
127     return true;
128
129 out_error:
130     eglMakeCurrent(ctx.dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
131     eglDestroySurface(ctx.dpy, ctx.surface);
132     eglDestroyContext(ctx.dpy, ctx.context);
133     eglTerminate(ctx.dpy);
134     nativeDestroyWindow(ctx.nativeDisplay, ctx.win);
135     nativeDestroyDisplay(ctx.nativeDisplay);
136     return false;
137 }
138
139 void terminateEgl()
140 {
141     eglMakeCurrent(ctx.dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
142     eglDestroySurface(ctx.dpy, ctx.surface);
143     eglDestroyContext(ctx.dpy, ctx.context);
144     eglTerminate(ctx.dpy);
145     nativeDestroyWindow(ctx.nativeDisplay, ctx.win);
146     nativeDestroyDisplay(ctx.nativeDisplay);
147
148 #if defined(HAVE_LIBOSSO)
149     osso_deinitialize(ossoContext);
150     ossoContext = 0;
151 #endif
152 }
153
154 int64_t timeDiff(const struct timespec& start, const struct timespec& end)
155 {
156     int64_t s = start.tv_sec * (1000 * 1000 * 1000LL) + start.tv_nsec;
157     int64_t e =   end.tv_sec * (1000 * 1000 * 1000LL) +   end.tv_nsec;
158     return e - s;
159 }
160
161 bool shouldRunTest(const std::string& testName)
162 {
163     std::list<std::string>::iterator i;
164     bool result = true;
165
166     if (options.includedTests.size())
167     {
168         result = false;
169         for (i = options.includedTests.begin(); i != options.includedTests.end(); ++i)
170         {
171             if (testName.find(*i) != std::string::npos)
172             {
173                 result = true;
174                 break;
175             }
176         }
177     }
178
179     for (i = options.excludedTests.begin(); i != options.excludedTests.end(); ++i)
180     {
181         if (testName.find(*i) != std::string::npos)
182         {
183             result = false;
184             break;
185         }
186     }
187
188     return result;
189 }
190
191 void runTest(Test& test)
192 {
193     int frames = 0;
194     int frameLimit = 100;
195     int warmup = 20;
196     int64_t minTime = options.minTime * 1000 * 1000 * 1000LL;
197     struct timespec res, start, end;
198
199     if (options.listTests)
200     {
201         printf("%s\n", test.name().c_str());
202         return;
203     }
204
205     if (!shouldRunTest(test.name()))
206     {
207         return;
208     }
209
210     clock_getres(CLOCK_REALTIME, &res);
211     //printf("Timer resolution: %d.%09d s\n", res.tv_sec, res.tv_nsec);
212     printf("%-40s", (test.name() + ":").c_str());
213     fflush(stdout);
214
215     try
216     {
217         test.prepare();
218         ASSERT_GL();
219         ASSERT_EGL();
220     } catch (const std::exception& e)
221     {
222         printf("%s\n", e.what());
223         return;
224     }
225
226     while (warmup--)
227     {
228         test(0);
229         swapBuffers();
230     }
231
232     ASSERT_GL();
233     ASSERT_EGL();
234
235 #if defined(HAVE_LIBOSSO)
236     osso_display_blanking_pause(ossoContext);
237 #endif
238
239     clock_gettime(CLOCK_REALTIME, &start);
240     while (frames < frameLimit)
241     {
242         test(frames);
243         swapBuffers();
244         clock_gettime(CLOCK_REALTIME, &end);
245         frames++;
246         if (frames >= frameLimit && timeDiff(start, end) < minTime)
247         {
248             frameLimit *= 2;
249         }
250     }
251
252     ASSERT_GL();
253     ASSERT_EGL();
254     
255     test.teardown();
256     ASSERT_GL();
257     ASSERT_EGL();
258
259     int64_t diff = timeDiff(start, end);
260     int fps = static_cast<int>((1000 * 1000 * 1000LL * frames) / diff);
261     //printf("%d frames in %6.2f ms (%3d fps) ", frames, diff / (1000.0f * 1000.0f), fps);
262     printf("%3d fps ", fps);
263
264     while (fps > 0)
265     {
266         fputc('#', stdout);
267         fps -= 3;
268     }
269     fputc('\n', stdout);
270 }
271
272 void getScreenSize(int& width, int& height)
273 {
274     Window rootWindow = DefaultRootWindow(ctx.nativeDisplay);
275     XWindowAttributes rootAttrs;
276
277     XGetWindowAttributes(ctx.nativeDisplay, rootWindow, &rootAttrs);
278
279     width = rootAttrs.width;
280     height = rootAttrs.height;
281 }
282
283 void showIntro()
284 {
285     std::cout << 
286         "GLMemPerf v" PACKAGE_VERSION " - OpenGL ES 2.0 memory performance benchmark\n"
287         "Copyright (C) 2009 Nokia Corporation. GLMemPerf comes with ABSOLUTELY\n"
288         "NO WARRANTY; This is free software, and you are welcome to redistribute\n"
289         "it under certain conditions.\n"
290         "\n";
291 }
292
293 void showUsage()
294 {
295     std::cout << 
296         "Usage:\n"
297         "       glmemperf [OPTIONS]\n"
298         "Options:\n"
299         "       -h             This text\n"
300         "       -v             Verbose mode\n"
301         "       -l             List all tests without running them\n"
302         "       -i TEST        Include a specific test (full name or substring)\n"
303         "       -e TEST        Exclude a specific test (full name or substring)\n"
304         "       -t SECS        Minimum time to run each test\n"
305         "       -b BPP         Bits per pixel\n";
306 }
307
308 void parseArguments(const std::list<std::string>& args)
309 {
310     std::list<std::string>::const_iterator i;
311
312     // Set up defaults
313     options.verbose = false;
314     options.minTime = 1;
315     options.bitsPerPixel = 16;
316     options.listTests = false;
317
318     for (i = args.begin(), i++; i != args.end(); ++i)
319     {
320         if (*i == "-h" || *i == "--help")
321         {
322             showUsage();
323             exit(0);
324         }
325         else if (*i == "-i" && ++i != args.end())
326         {
327             options.includedTests.push_back(*i);
328         }
329         else if (*i == "-e" && ++i != args.end())
330         {
331             options.excludedTests.push_back(*i);
332         }
333         else if (*i == "-t" && ++i != args.end())
334         {
335             options.minTime = atoi((*i).c_str());
336         }
337         else if (*i == "-b" && ++i != args.end())
338         {
339             options.bitsPerPixel = atoi((*i).c_str());
340         }
341         else if (*i == "-v")
342         {
343             options.verbose = true;
344         }
345         else if (*i == "-l")
346         {
347             options.listTests = true;
348         }
349         else
350         {
351             std::cerr << "Invalid option: " << *i << std::endl;
352             showUsage();
353             exit(1);
354         }
355     }
356 }
357
358 void findDataDirectory()
359 {
360     struct stat st;
361     if (stat("data", &st) == 0)
362     {
363         return;
364     }
365     chdir(PREFIX "/share/glmemperf/");
366     assert(stat("data", &st) == 0);
367 }
368
369 #define ADD_TEST(TEST) runTest(*std::auto_ptr<Test>(new TEST));
370
371 int main(int argc, char** argv)
372 {
373     std::list<std::string> args(argv, argv + argc);
374     
375     showIntro();
376     parseArguments(args);
377     findDataDirectory();
378
379     const EGLint configAttrs[] =
380     {
381         EGL_BUFFER_SIZE, options.bitsPerPixel,
382         EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
383         EGL_NONE
384     };
385
386     const EGLint configAttrs32[] =
387     {
388         EGL_BUFFER_SIZE, 32,
389         EGL_NONE
390     };
391
392     const EGLint contextAttrs[] =
393     {
394         EGL_CONTEXT_CLIENT_VERSION, 2,
395         EGL_NONE
396     };
397     int winWidth = 800;
398     int winHeight = 480;
399     const float w = winWidth, h = winHeight;
400     EGLConfig config32 = 0;
401     EGLint configCount = 0;
402
403     bool result = nativeCreateDisplay(&ctx.nativeDisplay);
404     assert(result);
405
406     getScreenSize(winWidth, winHeight);
407     result = initializeEgl(winWidth, winHeight, configAttrs, contextAttrs);
408     assert(result);
409
410     eglChooseConfig(ctx.dpy, configAttrs32, &config32, 1, &configCount);
411
412     if (!configCount)
413     {
414         printf("32bpp config not found\n");
415     }
416
417     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
418     ASSERT_GL();
419
420     // Clear test
421     ADD_TEST(ClearTest());
422
423     // Normal blits
424     ADD_TEST(BlitTest(GL_RGBA, GL_UNSIGNED_BYTE,              800, 480, "data/water2_800x480_rgba8888.raw"));
425     ADD_TEST(BlitTest(GL_RGB,  GL_UNSIGNED_BYTE,              800, 480, "data/water2_800x480_rgb888.raw"));
426     ADD_TEST(BlitTest(GL_RGBA, GL_UNSIGNED_BYTE,             1024, 512, "data/digital_nature2_1024x512_rgba8888.raw", false, 800.0 / 1024, 480.0 / 512));
427     ADD_TEST(BlitTest(GL_RGB,  GL_UNSIGNED_SHORT_5_6_5,       800, 480, "data/water2_800x480_rgb565.raw"));
428     ADD_TEST(BlitTest(GL_RGB,  GL_UNSIGNED_SHORT_5_6_5,      1024, 512, "data/digital_nature2_1024x512_rgb565.raw", false, 800.0 / 1024, 480.0 / 512));
429     ADD_TEST(BlitTest(GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG, 0, 1024, 512, "data/abstract3_1024x512_pvrtc4.raw", false, 800.0 / 1024, 480.0 / 512));
430     ADD_TEST(BlitTest(GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG, 0, 1024, 512, "data/abstract3_1024x512_pvrtc2.raw", false, 800.0 / 1024, 480.0 / 512));
431     ADD_TEST(BlitTest(GL_ETC1_RGB8_OES,                   0, 1024, 512, "data/abstract3_1024x512_etc1.raw", false, 800.0 / 1024, 480.0 / 512));
432     ADD_TEST(PixmapBlitTest(w, h, ctx.config));
433     ADD_TEST(PixmapBlitTest(w, h, config32));
434     ADD_TEST(FBOBlitTest(GL_RGBA, GL_UNSIGNED_BYTE,          w, h));
435     ADD_TEST(FBOBlitTest(GL_RGBA, GL_UNSIGNED_BYTE,          1024, 512, false, w / 1024, h / 512));
436     ADD_TEST(FBOBlitTest(GL_RGB,  GL_UNSIGNED_SHORT_5_6_5,   w, h));
437     ADD_TEST(FBOBlitTest(GL_RGB,  GL_UNSIGNED_SHORT_5_6_5,   1024, 512, false, w / 1042, h / 512));
438
439     // Rotated blits
440     ADD_TEST(BlitTest(GL_RGBA, GL_UNSIGNED_BYTE,              480,  800, "data/water2_480x800_rgba8888.raw", true));
441     ADD_TEST(BlitTest(GL_RGB,  GL_UNSIGNED_BYTE,              480,  800, "data/water2_480x800_rgb888.raw", true));
442     ADD_TEST(BlitTest(GL_RGBA, GL_UNSIGNED_BYTE,              512, 1024, "data/digital_nature2_512x1024_rgba8888.raw", true, 480.0 / 512, 800.0 / 1024));
443     ADD_TEST(BlitTest(GL_RGB,  GL_UNSIGNED_SHORT_5_6_5,       480,  800, "data/water2_480x800_rgb565.raw", true));
444     ADD_TEST(BlitTest(GL_RGB,  GL_UNSIGNED_SHORT_5_6_5,       512, 1024, "data/digital_nature2_512x1024_rgb565.raw", true, 480.0 / 512, 800.0 / 1024));
445     ADD_TEST(BlitTest(GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG, 0,  512, 1024, "data/abstract3_512x1024_pvrtc4.raw", true, 480.0 / 512, 800.0 / 1024));
446     ADD_TEST(BlitTest(GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG, 0,  512, 1024, "data/abstract3_512x1024_pvrtc2.raw", true, 480.0 / 512, 800.0 / 1024));
447     ADD_TEST(BlitTest(GL_ETC1_RGB8_OES,                   0,  512, 1024, "data/abstract3_512x1024_etc1.raw", true, 480.0 / 512, 800.0 / 1024));
448     ADD_TEST(PixmapBlitTest(h, w, ctx.config, true));
449     ADD_TEST(PixmapBlitTest(h, w, config32,   true));
450     ADD_TEST(FBOBlitTest(GL_RGBA, GL_UNSIGNED_BYTE,        w, h, true, h / w, w / h));
451     ADD_TEST(FBOBlitTest(GL_RGBA, GL_UNSIGNED_BYTE,        1024, 512, true, h / 512, w / 1024));
452     ADD_TEST(FBOBlitTest(GL_RGB,  GL_UNSIGNED_SHORT_5_6_5, w, h, true, h / w, w / h));
453     ADD_TEST(FBOBlitTest(GL_RGB,  GL_UNSIGNED_SHORT_5_6_5, 1024, 512, true, h / 512, w / 1024));
454
455     int gridW = 5;
456     int gridH = 3;
457     float w2 = winWidth  / gridW;
458     float h2 = winHeight / gridH;
459
460     glEnable(GL_BLEND);
461     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
462
463     // Small blended blits
464     ADD_TEST(BlitTest(GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4,     128, 128, "data/xorg_128x128_rgba4444.raw", false, gridW, gridH, 128.0 / w2, 128.0 / h2));
465     ADD_TEST(BlitTest(GL_RGBA, GL_UNSIGNED_BYTE,              127, 127, "data/xorg_127x127_rgba8888.raw", false, gridW, gridH, 127.0 / w2, 127.0 / h2));
466     ADD_TEST(BlitTest(GL_RGBA, GL_UNSIGNED_BYTE,              128, 128, "data/xorg_128x128_rgba8888.raw", false, gridW, gridH, 128.0 / w2, 128.0 / h2));
467     ADD_TEST(BlitTest(GL_RGB, GL_UNSIGNED_SHORT_5_6_5,        127, 127, "data/xorg_127x127_rgb565.raw",   false, gridW, gridH, 127.0 / w2, 127.0 / h2));
468     ADD_TEST(BlitTest(GL_RGB, GL_UNSIGNED_SHORT_5_6_5,        128, 128, "data/xorg_128x128_rgb565.raw",   false, gridW, gridH, 128.0 / w2, 128.0 / h2));
469     ADD_TEST(BlitTest(GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG, 0, 128, 128, "data/xorg_128x128_pvrtc4.raw",   false, gridW, gridH, 128.0 / w2, 128.0 / h2));
470     ADD_TEST(BlitTest(GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG, 0, 128, 128, "data/xorg_128x128_pvrtc2.raw",   false, gridW, gridH, 128.0 / w2, 128.0 / h2));
471     ADD_TEST(BlitTest(GL_ETC1_RGB8_OES,                    0, 128, 128, "data/xorg_128x128_etc1.raw",     false, gridW, gridH, 128.0 / w2, 128.0 / h2));
472     ADD_TEST(ShaderBlitTest("mask", 128, 128, gridW, gridH * 0.5f, 128.0 / w2, 128.0 / h2));
473
474     // Rotated small blended blits
475     ADD_TEST(BlitTest(GL_RGBA, GL_UNSIGNED_BYTE,              127, 127, "data/xorg_127x127_rgba8888.raw", true, gridH, gridW, 127.0 / w2, 127.0 / h2));
476     ADD_TEST(BlitTest(GL_RGBA, GL_UNSIGNED_BYTE,              128, 128, "data/xorg_128x128_rgba8888.raw", true, gridH, gridW, 128.0 / w2, 128.0 / h2));
477     ADD_TEST(BlitTest(GL_RGB, GL_UNSIGNED_SHORT_5_6_5,        127, 127, "data/xorg_127x127_rgb565.raw",   true, gridH, gridW, 127.0 / w2, 127.0 / h2));
478     ADD_TEST(BlitTest(GL_RGB, GL_UNSIGNED_SHORT_5_6_5,        128, 128, "data/xorg_128x128_rgb565.raw",   true, gridH, gridW, 128.0 / w2, 128.0 / h2));
479     ADD_TEST(BlitTest(GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG, 0, 128, 128, "data/xorg_128x128_pvrtc4.raw",   true, gridH, gridW, 128.0 / w2, 128.0 / h2));
480     ADD_TEST(BlitTest(GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG, 0, 128, 128, "data/xorg_128x128_pvrtc2.raw",   true, gridH, gridW, 128.0 / w2, 128.0 / h2));
481     ADD_TEST(BlitTest(GL_ETC1_RGB8_OES,                    0, 128, 128, "data/xorg_128x128_etc1.raw",     true, gridH, gridW, 128.0 / w2, 128.0 / h2));
482
483     glDisable(GL_BLEND);
484
485     // Shader tests
486     ADD_TEST(ShaderBlitTest("const", w, h));
487     ADD_TEST(ShaderBlitTest("lingrad", w, h));
488     ADD_TEST(ShaderBlitTest("radgrad", w, h));
489     ADD_TEST(ShaderBlitTest("palette", w, h));
490     
491     // CPU interleaving
492     ADD_TEST(CPUInterleavingTest(CPUI_XSHM_IMAGE, 2, 16, winWidth, winHeight));
493     ADD_TEST(CPUInterleavingTest(CPUI_XSHM_IMAGE, 2, 32, winWidth, winHeight));
494     ADD_TEST(CPUInterleavingTest(CPUI_TEXTURE_UPLOAD, 2, 16, winWidth, winHeight));
495     ADD_TEST(CPUInterleavingTest(CPUI_TEXTURE_UPLOAD, 2, 32, winWidth, winHeight));
496
497     terminateEgl();
498 }