Fix printf format specifier in graphics benchmark.
[wxWidgets.git] / tests / benchmarks / graphics.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: graphics.cpp
3 // Purpose: Some benchmarks for measuring graphics operations performance
4 // Author: Vadim Zeitlin
5 // Created: 2008-04-13
6 // RCS-ID: $Id$
7 // Copyright: (c) 2008 Vadim Zeitlin <vadim@wxwidgets.org>
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 #include "wx/app.h"
12 #include "wx/frame.h"
13 #include "wx/cmdline.h"
14 #include "wx/dcclient.h"
15 #include "wx/dcmemory.h"
16 #include "wx/dcgraph.h"
17 #include "wx/image.h"
18 #include "wx/rawbmp.h"
19 #include "wx/stopwatch.h"
20 #include "wx/crt.h"
21
22 #if wxUSE_GLCANVAS
23 #include "wx/glcanvas.h"
24 #ifdef _MSC_VER
25 #pragma comment(lib, "opengl32")
26 #endif
27 #endif // wxUSE_GLCANVAS
28
29 #if wxUSE_GLCANVAS
30
31 GLuint g_texture;
32 wxImage g_image;
33
34 void InitializeTexture(int w, int h)
35 {
36 glGenTextures(1, &g_texture);
37 glBindTexture(GL_TEXTURE_2D, g_texture);
38
39 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
40
41 g_image.Create(w, h, false /* don't clear */);
42 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
43 glTexImage2D(GL_TEXTURE_2D, 0,
44 GL_RGB, g_image.GetWidth(), g_image.GetHeight(), 0,
45 GL_RGB, GL_UNSIGNED_BYTE, g_image.GetData());
46 }
47 #endif // wxUSE_GLCANVAS
48
49 struct GraphicsBenchmarkOptions
50 {
51 GraphicsBenchmarkOptions()
52 {
53 mapMode = 0;
54 penWidth = 0;
55
56 width = 800;
57 height = 600;
58
59 numIters = 1000;
60
61 testBitmaps =
62 testImages =
63 testLines =
64 testRawBitmaps =
65 testRectangles = false;
66
67 usePaint =
68 useClient =
69 useMemory = false;
70
71 useDC =
72 useGC =
73 useGL = false;
74 }
75
76 long mapMode,
77 penWidth,
78 width,
79 height,
80 numIters;
81
82 bool testBitmaps,
83 testImages,
84 testLines,
85 testRawBitmaps,
86 testRectangles;
87
88 bool usePaint,
89 useClient,
90 useMemory;
91
92 bool useDC,
93 useGC,
94 useGL;
95 } opts;
96
97 class GraphicsBenchmarkFrame : public wxFrame
98 {
99 public:
100 GraphicsBenchmarkFrame()
101 : wxFrame(NULL, wxID_ANY, "wxWidgets Graphics Benchmark")
102 {
103 SetClientSize(opts.width, opts.height);
104
105 #if wxUSE_GLCANVAS
106 m_glCanvas = NULL;
107
108 if ( opts.useGL )
109 {
110 m_glCanvas = new wxGLCanvas(this, wxID_ANY, NULL,
111 wxPoint(0, 0),
112 wxSize(opts.width, opts.height));
113 m_glContext = new wxGLContext(m_glCanvas);
114 m_glContext->SetCurrent(*m_glCanvas);
115
116 glViewport(0, 0, opts.width, opts.height);
117 glMatrixMode(GL_PROJECTION);
118 glLoadIdentity();
119 glOrtho(-1, 1, -1, 1, -1, 1);
120 glMatrixMode(GL_MODELVIEW);
121 glLoadIdentity();
122
123 InitializeTexture(opts.width, opts.height);
124
125 m_glCanvas->Connect(
126 wxEVT_PAINT,
127 wxPaintEventHandler(GraphicsBenchmarkFrame::OnGLRender),
128 NULL,
129 this
130 );
131 }
132 else // Not using OpenGL
133 #endif // wxUSE_GLCANVAS
134 {
135 Connect(wxEVT_PAINT,
136 wxPaintEventHandler(GraphicsBenchmarkFrame::OnPaint));
137 }
138
139 Connect(wxEVT_SIZE, wxSizeEventHandler(GraphicsBenchmarkFrame::OnSize));
140
141 m_bitmap.Create(64, 64, 32);
142
143 Show();
144 }
145
146 #if wxUSE_GLCANVAS
147 virtual ~GraphicsBenchmarkFrame()
148 {
149 delete m_glContext;
150 }
151 #endif // wxUSE_GLCANVAS
152
153 private:
154 // Just change the image in some (quick) way to show that it's really being
155 // updated on screen.
156 void UpdateRGB(unsigned char* data, int n)
157 {
158 for ( int y = 0; y < opts.height; ++y )
159 {
160 memset(data, n % 256, 3*opts.width);
161
162 data += 3*opts.width;
163 n++;
164 }
165 }
166
167 #if wxUSE_GLCANVAS
168 void OnGLRender(wxPaintEvent& WXUNUSED(event))
169 {
170 m_glContext->SetCurrent(*m_glCanvas);
171 glEnable(GL_TEXTURE_2D);
172
173 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
174 glClear(GL_COLOR_BUFFER_BIT);
175
176 wxPrintf("Benchmarking %s: ", "OpenGL images");
177 fflush(stdout);
178
179 wxStopWatch sw;
180 for ( int n = 0; n < opts.numIters; n++ )
181 {
182 UpdateRGB(g_image.GetData(), n);
183
184 glTexSubImage2D(GL_TEXTURE_2D, 0,
185 0, 0, opts.width, opts.height,
186 GL_RGB, GL_UNSIGNED_BYTE, g_image.GetData());
187 glBegin(GL_QUADS);
188 glTexCoord2f(0, 0);
189 glVertex2f(-1.0, -1.0);
190
191 glTexCoord2f(0, 1);
192 glVertex2f(-1.0, 1.0);
193
194 glTexCoord2f(1, 1);
195 glVertex2f(1.0, 1.0);
196
197 glTexCoord2f(1, 0);
198 glVertex2f(1.0, -1.0);
199 glEnd();
200
201 m_glCanvas->SwapBuffers();
202 }
203
204 const long t = sw.Time();
205
206 wxPrintf("%ld images done in %ldms = %gus/image or %ld FPS\n",
207 opts.numIters, t, (1000. * t)/opts.numIters,
208 (1000*opts.numIters + t - 1)/t);
209
210 wxTheApp->ExitMainLoop();
211 }
212 #endif // wxUSE_GLCANVAS
213
214 void OnPaint(wxPaintEvent& WXUNUSED(event))
215 {
216 if ( opts.usePaint )
217 {
218 wxPaintDC dc(this);
219 wxGCDC gcdc(dc);
220 BenchmarkDCAndGC("paint", dc, gcdc);
221 }
222
223 if ( opts.useClient )
224 {
225 wxClientDC dc(this);
226 wxGCDC gcdc(dc);
227 BenchmarkDCAndGC("client", dc, gcdc);
228 }
229
230 if ( opts.useMemory )
231 {
232 wxBitmap bmp(opts.width, opts.height);
233 wxMemoryDC dc(bmp);
234 wxGCDC gcdc(dc);
235 BenchmarkDCAndGC("memory", dc, gcdc);
236 }
237
238 wxTheApp->ExitMainLoop();
239 }
240
241 void BenchmarkDCAndGC(const char* dckind, wxDC& dc, wxGCDC& gcdc)
242 {
243 if ( opts.useDC )
244 BenchmarkAll(wxString::Format("%6s DC", dckind), dc);
245 if ( opts.useGC )
246 BenchmarkAll(wxString::Format("%6s GC", dckind), gcdc);
247 }
248
249 void BenchmarkAll(const wxString& msg, wxDC& dc)
250 {
251 BenchmarkBitmaps(msg, dc);
252 BenchmarkImages(msg, dc);
253 BenchmarkLines(msg, dc);
254 BenchmarkRawBitmaps(msg, dc);
255 BenchmarkRectangles(msg, dc);
256 }
257
258 void BenchmarkLines(const wxString& msg, wxDC& dc)
259 {
260 if ( !opts.testLines )
261 return;
262
263 if ( opts.mapMode != 0 )
264 dc.SetMapMode((wxMappingMode)opts.mapMode);
265 if ( opts.penWidth != 0 )
266 dc.SetPen(wxPen(*wxWHITE, opts.penWidth));
267
268 wxPrintf("Benchmarking %s: ", msg);
269 fflush(stdout);
270
271 wxStopWatch sw;
272 int x = 0,
273 y = 0;
274 for ( int n = 0; n < opts.numIters; n++ )
275 {
276 int x1 = rand() % opts.width,
277 y1 = rand() % opts.height;
278
279 dc.DrawLine(x, y, x1, y1);
280
281 x = x1;
282 y = y1;
283 }
284
285 const long t = sw.Time();
286
287 wxPrintf("%ld lines done in %ldms = %gus/line\n",
288 opts.numIters, t, (1000. * t)/opts.numIters);
289 }
290
291
292 void BenchmarkRectangles(const wxString& msg, wxDC& dc)
293 {
294 if ( !opts.testRectangles )
295 return;
296
297 if ( opts.mapMode != 0 )
298 dc.SetMapMode((wxMappingMode)opts.mapMode);
299 if ( opts.penWidth != 0 )
300 dc.SetPen(wxPen(*wxWHITE, opts.penWidth));
301
302 dc.SetBrush( *wxRED_BRUSH );
303
304 wxPrintf("Benchmarking %s: ", msg);
305 fflush(stdout);
306
307 wxStopWatch sw;
308 for ( int n = 0; n < opts.numIters; n++ )
309 {
310 int x = rand() % opts.width,
311 y = rand() % opts.height;
312
313 dc.DrawRectangle(x, y, 32, 32);
314 }
315
316 const long t = sw.Time();
317
318 wxPrintf("%ld rects done in %ldms = %gus/rect\n",
319 opts.numIters, t, (1000. * t)/opts.numIters);
320 }
321
322 void BenchmarkBitmaps(const wxString& msg, wxDC& dc)
323 {
324 if ( !opts.testBitmaps )
325 return;
326
327 if ( opts.mapMode != 0 )
328 dc.SetMapMode((wxMappingMode)opts.mapMode);
329 if ( opts.penWidth != 0 )
330 dc.SetPen(wxPen(*wxWHITE, opts.penWidth));
331
332 wxPrintf("Benchmarking %s: ", msg);
333 fflush(stdout);
334
335 wxStopWatch sw;
336 for ( int n = 0; n < opts.numIters; n++ )
337 {
338 int x = rand() % opts.width,
339 y = rand() % opts.height;
340
341 dc.DrawBitmap(m_bitmap, x, y, true);
342 }
343
344 const long t = sw.Time();
345
346 wxPrintf("%ld bitmaps done in %ldms = %gus/bitmap\n",
347 opts.numIters, t, (1000. * t)/opts.numIters);
348 }
349
350 void BenchmarkImages(const wxString& msg, wxDC& dc)
351 {
352 if ( !opts.testImages )
353 return;
354
355 if ( opts.mapMode != 0 )
356 dc.SetMapMode((wxMappingMode)opts.mapMode);
357
358 wxPrintf("Benchmarking %s: ", msg);
359 fflush(stdout);
360
361 wxImage image(wxSize(opts.width, opts.height), false /* don't clear */);
362
363 wxStopWatch sw;
364 for ( int n = 0; n < opts.numIters; n++ )
365 {
366 UpdateRGB(image.GetData(), n);
367 dc.DrawBitmap(image, 0, 0);
368 }
369
370 const long t = sw.Time();
371
372 wxPrintf("%ld images done in %ldms = %gus/image or %ld FPS\n",
373 opts.numIters, t, (1000. * t)/opts.numIters,
374 (1000*opts.numIters + t - 1)/t);
375 }
376
377 void BenchmarkRawBitmaps(const wxString& msg, wxDC& dc)
378 {
379 if ( !opts.testRawBitmaps )
380 return;
381
382 if ( opts.mapMode != 0 )
383 dc.SetMapMode((wxMappingMode)opts.mapMode);
384
385 wxPrintf("Benchmarking %s: ", msg);
386 fflush(stdout);
387
388 wxBitmap bitmap(opts.width, opts.height, 24);
389 wxNativePixelData data(bitmap);
390
391 wxStopWatch sw;
392 for ( int n = 0; n < opts.numIters; n++ )
393 {
394 unsigned char c = n % 256;
395 {
396 wxNativePixelData::Iterator p(data);
397 for ( int y = 0; y < opts.height; ++y )
398 {
399 wxNativePixelData::Iterator rowStart = p;
400
401 for ( int x = 0; x < opts.width; ++x )
402 {
403 p.Red() =
404 p.Green() =
405 p.Blue() = c;
406 ++p;
407 }
408
409 p = rowStart;
410 p.OffsetY(data, 1);
411 c++;
412 }
413 }
414
415 dc.DrawBitmap(bitmap, 0, 0);
416 }
417
418 const long t = sw.Time();
419
420 wxPrintf("%ld raw bitmaps done in %ldms = %gus/bitmap or %ld FPS\n",
421 opts.numIters, t, (1000. * t)/opts.numIters,
422 (1000*opts.numIters + t - 1)/t);
423 }
424
425
426 wxBitmap m_bitmap;
427 #if wxUSE_GLCANVAS
428 wxGLCanvas* m_glCanvas;
429 wxGLContext* m_glContext;
430 #endif // wxUSE_GLCANVAS
431 };
432
433 class GraphicsBenchmarkApp : public wxApp
434 {
435 public:
436 virtual void OnInitCmdLine(wxCmdLineParser& parser)
437 {
438 static const wxCmdLineEntryDesc desc[] =
439 {
440 { wxCMD_LINE_SWITCH, "", "bitmaps" },
441 { wxCMD_LINE_SWITCH, "", "images" },
442 { wxCMD_LINE_SWITCH, "", "lines" },
443 { wxCMD_LINE_SWITCH, "", "rawbmp" },
444 { wxCMD_LINE_SWITCH, "", "rectangles" },
445 { wxCMD_LINE_SWITCH, "", "paint" },
446 { wxCMD_LINE_SWITCH, "", "client" },
447 { wxCMD_LINE_SWITCH, "", "memory" },
448 { wxCMD_LINE_SWITCH, "", "dc" },
449 { wxCMD_LINE_SWITCH, "", "gc" },
450 #if wxUSE_GLCANVAS
451 { wxCMD_LINE_SWITCH, "", "gl" },
452 #endif // wxUSE_GLCANVAS
453 { wxCMD_LINE_OPTION, "m", "map-mode", "", wxCMD_LINE_VAL_NUMBER },
454 { wxCMD_LINE_OPTION, "p", "pen-width", "", wxCMD_LINE_VAL_NUMBER },
455 { wxCMD_LINE_OPTION, "w", "width", "", wxCMD_LINE_VAL_NUMBER },
456 { wxCMD_LINE_OPTION, "h", "height", "", wxCMD_LINE_VAL_NUMBER },
457 { wxCMD_LINE_OPTION, "I", "images", "", wxCMD_LINE_VAL_NUMBER },
458 { wxCMD_LINE_OPTION, "N", "number-of-iterations", "", wxCMD_LINE_VAL_NUMBER },
459 { wxCMD_LINE_NONE },
460 };
461
462 parser.SetDesc(desc);
463 }
464
465 virtual bool OnCmdLineParsed(wxCmdLineParser& parser)
466 {
467 if ( parser.Found("m", &opts.mapMode) &&
468 (opts.mapMode < 1 || opts.mapMode > wxMM_METRIC) )
469 return false;
470 if ( parser.Found("p", &opts.penWidth) && opts.penWidth < 1 )
471 return false;
472 if ( parser.Found("w", &opts.width) && opts.width < 1 )
473 return false;
474 if ( parser.Found("h", &opts.height) && opts.height < 1 )
475 return false;
476 if ( parser.Found("N", &opts.numIters) && opts.numIters < 1 )
477 return false;
478
479 opts.testBitmaps = parser.Found("bitmaps");
480 opts.testImages = parser.Found("images");
481 opts.testLines = parser.Found("lines");
482 opts.testRawBitmaps = parser.Found("rawbmp");
483 opts.testRectangles = parser.Found("rectangles");
484 if ( !(opts.testBitmaps || opts.testImages || opts.testLines
485 || opts.testRawBitmaps || opts.testRectangles) )
486 {
487 // Do everything by default.
488 opts.testBitmaps =
489 opts.testImages =
490 opts.testLines =
491 opts.testRawBitmaps =
492 opts.testRectangles = true;
493 }
494
495 opts.usePaint = parser.Found("paint");
496 opts.useClient = parser.Found("client");
497 opts.useMemory = parser.Found("memory");
498 if ( !(opts.usePaint || opts.useClient || opts.useMemory) )
499 {
500 opts.usePaint =
501 opts.useClient =
502 opts.useMemory = true;
503 }
504
505 opts.useDC = parser.Found("dc");
506 opts.useGC = parser.Found("gc");
507 #if wxUSE_GLCANVAS
508 opts.useGL = parser.Found("gl");
509 if ( opts.useGL )
510 {
511 if ( opts.useDC || opts.useGC )
512 {
513 wxLogError("Can't use both OpenGL and normal graphics.");
514 return false;
515 }
516 }
517 else // Not using OpenGL
518 #endif // wxUSE_GLCANVAS
519 {
520 if ( !(opts.useDC || opts.useGC) )
521 {
522 opts.useDC =
523 opts.useGC = true;
524 }
525 }
526
527 return true;
528 }
529
530 virtual bool OnInit()
531 {
532 if ( !wxApp::OnInit() )
533 return false;
534
535 new GraphicsBenchmarkFrame;
536
537 return true;
538 }
539 };
540
541 IMPLEMENT_APP_CONSOLE(GraphicsBenchmarkApp)