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