c437dc2c6af6f24281bff8fcdfb4051bdb9b8f20
[platform/core/uifw/dali-demo.git] / examples / benchmark / benchmark.cpp
1 /*
2  * Copyright (c) 2020 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // EXTERNAL INCLUDES
19 #include <dali-toolkit/dali-toolkit.h>
20
21 // INTERNAL INCLUDES
22 #include "shared/utility.h"
23
24 using namespace Dali;
25 using namespace Dali::Toolkit;
26
27 namespace
28 {
29 const char* IMAGE_PATH[] = {
30   DEMO_IMAGE_DIR "gallery-medium-1.jpg",
31   DEMO_IMAGE_DIR "gallery-medium-2.jpg",
32   DEMO_IMAGE_DIR "gallery-medium-3.jpg",
33   DEMO_IMAGE_DIR "gallery-medium-4.jpg",
34   DEMO_IMAGE_DIR "gallery-medium-5.jpg",
35   DEMO_IMAGE_DIR "gallery-medium-6.jpg",
36   DEMO_IMAGE_DIR "gallery-medium-7.jpg",
37   DEMO_IMAGE_DIR "gallery-medium-8.jpg",
38   DEMO_IMAGE_DIR "gallery-medium-9.jpg",
39   DEMO_IMAGE_DIR "gallery-medium-10.jpg",
40   DEMO_IMAGE_DIR "gallery-medium-11.jpg",
41   DEMO_IMAGE_DIR "gallery-medium-12.jpg",
42   DEMO_IMAGE_DIR "gallery-medium-13.jpg",
43   DEMO_IMAGE_DIR "gallery-medium-14.jpg",
44   DEMO_IMAGE_DIR "gallery-medium-15.jpg",
45   DEMO_IMAGE_DIR "gallery-medium-16.jpg",
46   DEMO_IMAGE_DIR "gallery-medium-17.jpg",
47   DEMO_IMAGE_DIR "gallery-medium-18.jpg",
48   DEMO_IMAGE_DIR "gallery-medium-19.jpg",
49   DEMO_IMAGE_DIR "gallery-medium-20.jpg",
50   DEMO_IMAGE_DIR "gallery-medium-21.jpg",
51   DEMO_IMAGE_DIR "gallery-medium-22.jpg",
52   DEMO_IMAGE_DIR "gallery-medium-23.jpg",
53   DEMO_IMAGE_DIR "gallery-medium-24.jpg",
54   DEMO_IMAGE_DIR "gallery-medium-25.jpg",
55   DEMO_IMAGE_DIR "gallery-medium-26.jpg",
56   DEMO_IMAGE_DIR "gallery-medium-27.jpg",
57   DEMO_IMAGE_DIR "gallery-medium-28.jpg",
58   DEMO_IMAGE_DIR "gallery-medium-29.jpg",
59   DEMO_IMAGE_DIR "gallery-medium-30.jpg",
60   DEMO_IMAGE_DIR "gallery-medium-31.jpg",
61   DEMO_IMAGE_DIR "gallery-medium-32.jpg",
62   DEMO_IMAGE_DIR "gallery-medium-33.jpg",
63   DEMO_IMAGE_DIR "gallery-medium-34.jpg",
64   DEMO_IMAGE_DIR "gallery-medium-35.jpg",
65   DEMO_IMAGE_DIR "gallery-medium-36.jpg",
66   DEMO_IMAGE_DIR "gallery-medium-37.jpg",
67   DEMO_IMAGE_DIR "gallery-medium-38.jpg",
68   DEMO_IMAGE_DIR "gallery-medium-39.jpg",
69   DEMO_IMAGE_DIR "gallery-medium-40.jpg",
70   DEMO_IMAGE_DIR "gallery-medium-41.jpg",
71   DEMO_IMAGE_DIR "gallery-medium-42.jpg",
72   DEMO_IMAGE_DIR "gallery-medium-43.jpg",
73   DEMO_IMAGE_DIR "gallery-medium-44.jpg",
74   DEMO_IMAGE_DIR "gallery-medium-45.jpg",
75   DEMO_IMAGE_DIR "gallery-medium-46.jpg",
76   DEMO_IMAGE_DIR "gallery-medium-47.jpg",
77   DEMO_IMAGE_DIR "gallery-medium-48.jpg",
78   DEMO_IMAGE_DIR "gallery-medium-49.jpg",
79   DEMO_IMAGE_DIR "gallery-medium-50.jpg",
80   DEMO_IMAGE_DIR "gallery-medium-51.jpg",
81   DEMO_IMAGE_DIR "gallery-medium-52.jpg",
82   DEMO_IMAGE_DIR "gallery-medium-53.jpg",
83 };
84
85 const char* NINEPATCH_IMAGE_PATH[] = {
86   DEMO_IMAGE_DIR "selection-popup-bg.1.9.png",
87   DEMO_IMAGE_DIR "selection-popup-bg.2.9.png",
88   DEMO_IMAGE_DIR "selection-popup-bg.3.9.png",
89   DEMO_IMAGE_DIR "selection-popup-bg.4.9.png",
90   DEMO_IMAGE_DIR "selection-popup-bg.5.9.png",
91   DEMO_IMAGE_DIR "selection-popup-bg.6.9.png",
92   DEMO_IMAGE_DIR "selection-popup-bg.7.9.png",
93   DEMO_IMAGE_DIR "selection-popup-bg.8.9.png",
94   DEMO_IMAGE_DIR "selection-popup-bg.9.9.png",
95   DEMO_IMAGE_DIR "selection-popup-bg.10.9.png",
96   DEMO_IMAGE_DIR "selection-popup-bg.11.9.png",
97   DEMO_IMAGE_DIR "selection-popup-bg.12.9.png",
98   DEMO_IMAGE_DIR "selection-popup-bg.13.9.png",
99   DEMO_IMAGE_DIR "selection-popup-bg.14.9.png",
100   DEMO_IMAGE_DIR "selection-popup-bg.15.9.png",
101   DEMO_IMAGE_DIR "selection-popup-bg.16.9.png",
102   DEMO_IMAGE_DIR "selection-popup-bg.17.9.png",
103   DEMO_IMAGE_DIR "selection-popup-bg.18.9.png",
104   DEMO_IMAGE_DIR "selection-popup-bg.19.9.png",
105   DEMO_IMAGE_DIR "selection-popup-bg.20.9.png",
106   DEMO_IMAGE_DIR "selection-popup-bg.21.9.png",
107   DEMO_IMAGE_DIR "selection-popup-bg.22.9.png",
108   DEMO_IMAGE_DIR "selection-popup-bg.23.9.png",
109   DEMO_IMAGE_DIR "selection-popup-bg.24.9.png",
110   DEMO_IMAGE_DIR "selection-popup-bg.25.9.png",
111   DEMO_IMAGE_DIR "selection-popup-bg.26.9.png",
112   DEMO_IMAGE_DIR "selection-popup-bg.27.9.png",
113   DEMO_IMAGE_DIR "selection-popup-bg.28.9.png",
114   DEMO_IMAGE_DIR "selection-popup-bg.29.9.png",
115   DEMO_IMAGE_DIR "selection-popup-bg.30.9.png",
116   DEMO_IMAGE_DIR "selection-popup-bg.31.9.png",
117   DEMO_IMAGE_DIR "selection-popup-bg.32.9.png",
118   DEMO_IMAGE_DIR "selection-popup-bg.33.9.png",
119   DEMO_IMAGE_DIR "button-disabled.9.png",
120   DEMO_IMAGE_DIR "button-down.9.png",
121   DEMO_IMAGE_DIR "button-down-disabled.9.png",
122   DEMO_IMAGE_DIR "button-up-1.9.png",
123   DEMO_IMAGE_DIR "button-up-2.9.png",
124   DEMO_IMAGE_DIR "button-up-3.9.png",
125   DEMO_IMAGE_DIR "button-up-4.9.png",
126   DEMO_IMAGE_DIR "button-up-5.9.png",
127   DEMO_IMAGE_DIR "button-up-6.9.png",
128   DEMO_IMAGE_DIR "button-up-7.9.png",
129   DEMO_IMAGE_DIR "button-up-8.9.png",
130   DEMO_IMAGE_DIR "button-up-9.9.png",
131   DEMO_IMAGE_DIR "button-up-10.9.png",
132   DEMO_IMAGE_DIR "button-up-11.9.png",
133   DEMO_IMAGE_DIR "button-up-12.9.png",
134   DEMO_IMAGE_DIR "button-up-13.9.png",
135   DEMO_IMAGE_DIR "button-up-14.9.png",
136   DEMO_IMAGE_DIR "button-up-15.9.png",
137   DEMO_IMAGE_DIR "button-up-16.9.png",
138   DEMO_IMAGE_DIR "button-up-17.9.png",
139 };
140
141 const unsigned int NUM_IMAGES           = sizeof(IMAGE_PATH) / sizeof(char*);
142 const unsigned int NUM_NINEPATCH_IMAGES = sizeof(NINEPATCH_IMAGE_PATH) / sizeof(char*);
143
144 const float ANIMATION_TIME(5.0f); // animation length in seconds
145
146 struct VertexWithTexture
147 {
148   Vector2 position;
149   Vector2 texCoord;
150 };
151
152 // clang-format off
153 const char* VERTEX_SHADER_TEXTURE = DALI_COMPOSE_SHADER(
154     attribute mediump vec2 aPosition;\n
155     attribute mediump vec2 aTexCoord;\n
156     uniform mediump mat4 uMvpMatrix;\n
157     uniform mediump vec3 uSize;\n
158     varying mediump vec2 vTexCoord;\n
159     void main()\n
160     {\n
161       vec4 position = vec4(aPosition,0.0,1.0)*vec4(uSize,1.0);\n
162       gl_Position = uMvpMatrix * position;\n
163       vTexCoord = aTexCoord;\n
164     }\n
165 );
166
167 const char* FRAGMENT_SHADER_TEXTURE = DALI_COMPOSE_SHADER(
168     uniform lowp vec4 uColor;\n
169     uniform sampler2D sTexture;\n
170     varying mediump vec2 vTexCoord;\n
171
172     void main()\n
173     {\n
174       gl_FragColor = texture2D( sTexture, vTexCoord ) * uColor;\n
175     }\n
176 );
177 // clang-format on
178
179 bool         gUseMesh(false);
180 bool         gNinePatch(false);
181 unsigned int gRowsPerPage(25);
182 unsigned int gColumnsPerPage(25);
183 unsigned int gPageCount(13);
184
185 Renderer CreateRenderer(unsigned int index, Geometry geometry, Shader shader)
186 {
187   Renderer    renderer   = Renderer::New(geometry, shader);
188   const char* imagePath  = !gNinePatch ? IMAGE_PATH[index] : NINEPATCH_IMAGE_PATH[index];
189   Texture     texture    = DemoHelper::LoadTexture(imagePath);
190   TextureSet  textureSet = TextureSet::New();
191   textureSet.SetTexture(0u, texture);
192   renderer.SetTextures(textureSet);
193   renderer.SetProperty(Renderer::Property::BLEND_MODE, BlendMode::OFF);
194   return renderer;
195 }
196
197 } // namespace
198 // Test application to compare performance between using a mesh and ImageView
199 // By default, the application consist of 10 pages of 25x25 Image views, this can be modified using the following command line arguments:
200 // -r NumberOfRows  (Modifies the number of rows per page)
201 // -c NumberOfColumns (Modifies the number of columns per page)
202 // -p NumberOfPages (Modifies the nimber of pages )
203 // --use-mesh ( Use new renderer API (as ImageView) but shares renderers between actors when possible )
204 // --nine-patch ( Use nine patch images )
205
206 //
207 class Benchmark : public ConnectionTracker
208 {
209 public:
210   Benchmark(Application& application)
211   : mApplication(application),
212     mRowsPerPage(gRowsPerPage),
213     mColumnsPerPage(gColumnsPerPage),
214     mPageCount(gPageCount)
215   {
216     // Connect to the Application's Init signal
217     mApplication.InitSignal().Connect(this, &Benchmark::Create);
218   }
219
220   ~Benchmark() = default;
221
222   // The Init signal is received once (only) during the Application lifetime
223   void Create(Application& application)
224   {
225     // Get a handle to the window
226     Window window = application.GetWindow();
227     window.SetBackgroundColor(Color::WHITE);
228     Vector2 windowSize = window.GetSize();
229
230     window.GetRootLayer().SetProperty(Layer::Property::DEPTH_TEST, false);
231
232     mSize = Vector3(windowSize.x / mColumnsPerPage, windowSize.y / mRowsPerPage, 0.0f);
233
234     // Respond to a click anywhere on the window
235     window.GetRootLayer().TouchedSignal().Connect(this, &Benchmark::OnTouch);
236
237     // Respond to key events
238     window.KeyEventSignal().Connect(this, &Benchmark::OnKeyEvent);
239
240     if(gUseMesh)
241     {
242       CreateMeshActors();
243     }
244     else
245     {
246       CreateImageViews();
247     }
248
249     ShowAnimation();
250   }
251
252   bool OnTouch(Actor actor, const TouchEvent& touch)
253   {
254     // quit the application
255     mApplication.Quit();
256     return true;
257   }
258
259   const char* ImagePath(int i)
260   {
261     return !gNinePatch ? IMAGE_PATH[i % NUM_IMAGES] : NINEPATCH_IMAGE_PATH[i % NUM_NINEPATCH_IMAGES];
262   }
263
264   void CreateImageViews()
265   {
266     Window       window = mApplication.GetWindow();
267     unsigned int actorCount(mRowsPerPage * mColumnsPerPage * mPageCount);
268     mImageView.resize(actorCount);
269
270     for(size_t i(0); i < actorCount; ++i)
271     {
272       mImageView[i] = ImageView::New(ImagePath(i));
273       mImageView[i].SetProperty(Actor::Property::SIZE, Vector3(0.0f, 0.0f, 0.0f));
274       mImageView[i].SetResizePolicy(ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS);
275       window.Add(mImageView[i]);
276     }
277   }
278
279   void CreateMeshActors()
280   {
281     unsigned int numImages = !gNinePatch ? NUM_IMAGES : NUM_NINEPATCH_IMAGES;
282
283     //Create all the renderers
284     std::vector<Renderer> renderers(numImages);
285     Shader                shader   = Shader::New(VERTEX_SHADER_TEXTURE, FRAGMENT_SHADER_TEXTURE);
286     Geometry              geometry = DemoHelper::CreateTexturedQuad();
287     for(unsigned int i(0); i < numImages; ++i)
288     {
289       renderers[i] = CreateRenderer(i, geometry, shader);
290     }
291
292     //Create the actors
293     Window       window = mApplication.GetWindow();
294     unsigned int actorCount(mRowsPerPage * mColumnsPerPage * mPageCount);
295     mActor.resize(actorCount);
296     for(size_t i(0); i < actorCount; ++i)
297     {
298       mActor[i] = Actor::New();
299       mActor[i].AddRenderer(renderers[i % numImages]);
300       mActor[i].SetProperty(Actor::Property::SIZE, Vector3(0.0f, 0.0f, 0.0f));
301       window.Add(mActor[i]);
302     }
303   }
304
305   void OnAnimationEnd(Animation& source)
306   {
307     if(source == mShow)
308     {
309       ScrollAnimation();
310     }
311     else if(source == mScroll)
312     {
313       HideAnimation();
314     }
315     else
316     {
317       mApplication.Quit();
318     }
319   }
320
321   void ShowAnimation()
322   {
323     Window        window = mApplication.GetWindow();
324     const Vector2 windowSize(window.GetSize());
325     Vector3       initialPosition(windowSize.width * 0.5f, windowSize.height * 0.5f, 1000.0f);
326
327     unsigned int totalColumns = mColumnsPerPage * mPageCount;
328
329     size_t count(0);
330     float  xpos, ypos;
331     mShow = Animation::New(0.0f);
332
333     float totalDuration(10.0f);
334     float durationPerActor(0.5f);
335     float delayBetweenActors = (totalDuration - durationPerActor) / (mRowsPerPage * mColumnsPerPage);
336     for(size_t i(0); i < totalColumns; ++i)
337     {
338       xpos = mSize.x * i;
339
340       for(size_t j(0); j < mRowsPerPage; ++j)
341       {
342         ypos = mSize.y * j;
343
344         float delay    = 0.0f;
345         float duration = 0.0f;
346         if(count < (static_cast<size_t>(mRowsPerPage) * mColumnsPerPage))
347         {
348           duration = durationPerActor;
349           delay    = delayBetweenActors * count;
350         }
351         if(gUseMesh)
352         {
353           mActor[count].SetProperty(Actor::Property::POSITION, initialPosition);
354           mActor[count].SetProperty(Actor::Property::SIZE, Vector3(0.0f, 0.0f, 0.0f));
355           mActor[count].SetProperty(Actor::Property::ORIENTATION, Quaternion(Radian(0.0f), Vector3::XAXIS));
356           mShow.AnimateTo(Property(mActor[count], Actor::Property::POSITION), Vector3(xpos + mSize.x * 0.5f, ypos + mSize.y * 0.5f, 0.0f), AlphaFunction::EASE_OUT_BACK, TimePeriod(delay, duration));
357           mShow.AnimateTo(Property(mActor[count], Actor::Property::SIZE), mSize, AlphaFunction::EASE_OUT_BACK, TimePeriod(delay, duration));
358         }
359         else
360         {
361           mImageView[count].SetProperty(Actor::Property::POSITION, initialPosition);
362           mImageView[count].SetProperty(Actor::Property::SIZE, Vector3(0.0f, 0.0f, 0.0f));
363           mImageView[count].SetProperty(Actor::Property::ORIENTATION, Quaternion(Radian(0.0f), Vector3::XAXIS));
364           mShow.AnimateTo(Property(mImageView[count], Actor::Property::POSITION), Vector3(xpos + mSize.x * 0.5f, ypos + mSize.y * 0.5f, 0.0f), AlphaFunction::EASE_OUT_BACK, TimePeriod(delay, duration));
365           mShow.AnimateTo(Property(mImageView[count], Actor::Property::SIZE), mSize, AlphaFunction::EASE_OUT_BACK, TimePeriod(delay, duration));
366         }
367         ++count;
368       }
369     }
370     mShow.Play();
371     mShow.FinishedSignal().Connect(this, &Benchmark::OnAnimationEnd);
372   }
373
374   void ScrollAnimation()
375   {
376     Window  window = mApplication.GetWindow();
377     Vector3 windowSize(window.GetSize());
378
379     mScroll = Animation::New(10.0f);
380     size_t actorCount(static_cast<size_t>(mRowsPerPage) * mColumnsPerPage * mPageCount);
381     for(size_t i(0); i < actorCount; ++i)
382     {
383       if(gUseMesh)
384       {
385         mScroll.AnimateBy(Property(mActor[i], Actor::Property::POSITION), Vector3(-4.0f * windowSize.x, 0.0f, 0.0f), AlphaFunction::EASE_OUT, TimePeriod(0.0f, 3.0f));
386         mScroll.AnimateBy(Property(mActor[i], Actor::Property::POSITION), Vector3(-4.0f * windowSize.x, 0.0f, 0.0f), AlphaFunction::EASE_OUT, TimePeriod(3.0f, 3.0f));
387         mScroll.AnimateBy(Property(mActor[i], Actor::Property::POSITION), Vector3(-4.0f * windowSize.x, 0.0f, 0.0f), AlphaFunction::EASE_OUT, TimePeriod(6.0f, 2.0f));
388         mScroll.AnimateBy(Property(mActor[i], Actor::Property::POSITION), Vector3(12.0f * windowSize.x, 0.0f, 0.0f), AlphaFunction::EASE_OUT, TimePeriod(8.0f, 2.0f));
389       }
390       else
391       {
392         mScroll.AnimateBy(Property(mImageView[i], Actor::Property::POSITION), Vector3(-4.0f * windowSize.x, 0.0f, 0.0f), AlphaFunction::EASE_OUT, TimePeriod(0.0f, 3.0f));
393         mScroll.AnimateBy(Property(mImageView[i], Actor::Property::POSITION), Vector3(-4.0f * windowSize.x, 0.0f, 0.0f), AlphaFunction::EASE_OUT, TimePeriod(3.0f, 3.0f));
394         mScroll.AnimateBy(Property(mImageView[i], Actor::Property::POSITION), Vector3(-4.0f * windowSize.x, 0.0f, 0.0f), AlphaFunction::EASE_OUT, TimePeriod(6.0f, 2.0f));
395         mScroll.AnimateBy(Property(mImageView[i], Actor::Property::POSITION), Vector3(12.0f * windowSize.x, 0.0f, 0.0f), AlphaFunction::EASE_OUT, TimePeriod(8.0f, 2.0f));
396       }
397     }
398     mScroll.Play();
399     mScroll.FinishedSignal().Connect(this, &Benchmark::OnAnimationEnd);
400   }
401
402   void HideAnimation()
403   {
404     size_t       count(0);
405     unsigned int actorsPerPage(mRowsPerPage * mColumnsPerPage);
406     mHide = Animation::New(0.0f);
407
408     unsigned int totalColumns = mColumnsPerPage * mPageCount;
409
410     float finalZ = mApplication.GetWindow().GetRenderTaskList().GetTask(0).GetCameraActor().GetCurrentProperty<Vector3>(Actor::Property::WORLD_POSITION).z;
411     float totalDuration(5.0f);
412     float durationPerActor(0.5f);
413     float delayBetweenActors = (totalDuration - durationPerActor) / (mRowsPerPage * mColumnsPerPage);
414     for(size_t i(0); i < mRowsPerPage; ++i)
415     {
416       for(size_t j(0); j < totalColumns; ++j)
417       {
418         float delay    = 0.0f;
419         float duration = 0.0f;
420         if(count < actorsPerPage)
421         {
422           duration = durationPerActor;
423           delay    = delayBetweenActors * count;
424         }
425
426         if(gUseMesh)
427         {
428           mHide.AnimateTo(Property(mActor[count], Actor::Property::ORIENTATION), Quaternion(Radian(Degree(70.0f)), Vector3::XAXIS), AlphaFunction::EASE_OUT, TimePeriod(delay, duration));
429           mHide.AnimateBy(Property(mActor[count], Actor::Property::POSITION_Z), finalZ, AlphaFunction::EASE_OUT_BACK, TimePeriod(delay + delayBetweenActors * actorsPerPage + duration, duration));
430         }
431         else
432         {
433           mHide.AnimateTo(Property(mImageView[count], Actor::Property::ORIENTATION), Quaternion(Radian(Degree(70.0f)), Vector3::XAXIS), AlphaFunction::EASE_OUT, TimePeriod(delay, duration));
434           mHide.AnimateBy(Property(mImageView[count], Actor::Property::POSITION_Z), finalZ, AlphaFunction::EASE_OUT_BACK, TimePeriod(delay + delayBetweenActors * actorsPerPage + duration, duration));
435         }
436         ++count;
437       }
438     }
439
440     mHide.Play();
441     mHide.FinishedSignal().Connect(this, &Benchmark::OnAnimationEnd);
442   }
443
444   void OnKeyEvent(const KeyEvent& event)
445   {
446     if(event.GetState() == KeyEvent::DOWN)
447     {
448       if(IsKey(event, Dali::DALI_KEY_ESCAPE) || IsKey(event, Dali::DALI_KEY_BACK))
449       {
450         mApplication.Quit();
451       }
452     }
453   }
454
455 private:
456   Application& mApplication;
457
458   std::vector<Actor>     mActor;
459   std::vector<ImageView> mImageView;
460
461   Vector3      mSize;
462   unsigned int mRowsPerPage;
463   unsigned int mColumnsPerPage;
464   unsigned int mPageCount;
465
466   Animation mShow;
467   Animation mScroll;
468   Animation mHide;
469 };
470
471 int DALI_EXPORT_API main(int argc, char** argv)
472 {
473   Application application = Application::New(&argc, &argv);
474
475   for(int i(1); i < argc; ++i)
476   {
477     std::string arg(argv[i]);
478     if(arg.compare("--use-mesh") == 0)
479     {
480       gUseMesh = true;
481     }
482     else if(arg.compare("--nine-patch") == 0)
483     {
484       gNinePatch = true;
485     }
486     else if(arg.compare(0, 2, "-r") == 0)
487     {
488       gRowsPerPage = atoi(arg.substr(2, arg.size()).c_str());
489     }
490     else if(arg.compare(0, 2, "-c") == 0)
491     {
492       gColumnsPerPage = atoi(arg.substr(2, arg.size()).c_str());
493     }
494     else if(arg.compare(0, 2, "-p") == 0)
495     {
496       gPageCount = atoi(arg.substr(2, arg.size()).c_str());
497     }
498   }
499
500   Benchmark test(application);
501   application.MainLoop();
502
503   return 0;
504 }