]> git.saurik.com Git - wxWidgets.git/blame - tests/benchmarks/graphics.cpp
applying editor part of patch, see #15003
[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
6// RCS-ID: $Id$
7// Copyright: (c) 2008 Vadim Zeitlin <vadim@wxwidgets.org>
526954c5 8// Licence: wxWindows licence
e0257cc5
VZ
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"
2a408a4b 16#include "wx/dcgraph.h"
e45606e9
VZ
17#include "wx/image.h"
18#include "wx/rawbmp.h"
e0257cc5 19#include "wx/stopwatch.h"
f8497215 20#include "wx/crt.h"
e0257cc5 21
54d25f9d
VZ
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
31GLuint g_texture;
32wxImage g_image;
33
34void 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
e0257cc5
VZ
49struct GraphicsBenchmarkOptions
50{
51 GraphicsBenchmarkOptions()
52 {
53 mapMode = 0;
54 penWidth = 0;
55
56 width = 800;
57 height = 600;
58
ce0cdeb0 59 numIters = 1000;
51f64663
VZ
60
61 testBitmaps =
e45606e9 62 testImages =
51f64663 63 testLines =
e45606e9 64 testRawBitmaps =
51f64663 65 testRectangles = false;
8c14cbc9
VZ
66
67 usePaint =
68 useClient =
69 useMemory = false;
70
71 useDC =
54d25f9d
VZ
72 useGC =
73 useGL = false;
e0257cc5
VZ
74 }
75
76 long mapMode,
77 penWidth,
78 width,
79 height,
ce0cdeb0 80 numIters;
51f64663
VZ
81
82 bool testBitmaps,
e45606e9 83 testImages,
51f64663 84 testLines,
e45606e9 85 testRawBitmaps,
51f64663 86 testRectangles;
8c14cbc9
VZ
87
88 bool usePaint,
89 useClient,
90 useMemory;
91
92 bool useDC,
54d25f9d
VZ
93 useGC,
94 useGL;
e0257cc5
VZ
95} opts;
96
97class GraphicsBenchmarkFrame : public wxFrame
98{
99public:
100 GraphicsBenchmarkFrame()
101 : wxFrame(NULL, wxID_ANY, "wxWidgets Graphics Benchmark")
102 {
54d25f9d
VZ
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));
e0257cc5 140
f8497215 141 m_bitmap.Create(64, 64, 32);
2a408a4b 142
e0257cc5 143 Show();
f8497215 144 }
2a408a4b 145
54d25f9d
VZ
146#if wxUSE_GLCANVAS
147 virtual ~GraphicsBenchmarkFrame()
148 {
149 delete m_glContext;
150 }
151#endif // wxUSE_GLCANVAS
152
f8497215 153private:
6e6f4d35
VZ
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 }
54d25f9d
VZ
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
5adf2ecd 206 wxPrintf("%ld images done in %ldms = %gus/image or %ld FPS\n",
54d25f9d
VZ
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
e0257cc5
VZ
214 void OnPaint(wxPaintEvent& WXUNUSED(event))
215 {
8c14cbc9 216 if ( opts.usePaint )
b9fb3b06
VZ
217 {
218 wxPaintDC dc(this);
219 wxGCDC gcdc(dc);
220 BenchmarkDCAndGC("paint", dc, gcdc);
221 }
e0257cc5 222
8c14cbc9 223 if ( opts.useClient )
b9fb3b06
VZ
224 {
225 wxClientDC dc(this);
226 wxGCDC gcdc(dc);
227 BenchmarkDCAndGC("client", dc, gcdc);
228 }
229
8c14cbc9 230 if ( opts.useMemory )
b9fb3b06
VZ
231 {
232 wxBitmap bmp(opts.width, opts.height);
233 wxMemoryDC dc(bmp);
234 wxGCDC gcdc(dc);
235 BenchmarkDCAndGC("memory", dc, gcdc);
236 }
e0257cc5
VZ
237
238 wxTheApp->ExitMainLoop();
239 }
240
b9fb3b06
VZ
241 void BenchmarkDCAndGC(const char* dckind, wxDC& dc, wxGCDC& gcdc)
242 {
8c14cbc9
VZ
243 if ( opts.useDC )
244 BenchmarkAll(wxString::Format("%6s DC", dckind), dc);
245 if ( opts.useGC )
246 BenchmarkAll(wxString::Format("%6s GC", dckind), gcdc);
b9fb3b06
VZ
247 }
248
249 void BenchmarkAll(const wxString& msg, wxDC& dc)
250 {
e45606e9
VZ
251 BenchmarkBitmaps(msg, dc);
252 BenchmarkImages(msg, dc);
b9fb3b06 253 BenchmarkLines(msg, dc);
e45606e9 254 BenchmarkRawBitmaps(msg, dc);
b9fb3b06 255 BenchmarkRectangles(msg, dc);
b9fb3b06 256 }
2a408a4b 257
b9fb3b06 258 void BenchmarkLines(const wxString& msg, wxDC& dc)
e0257cc5 259 {
51f64663
VZ
260 if ( !opts.testLines )
261 return;
262
e0257cc5 263 if ( opts.mapMode != 0 )
2a408a4b 264 dc.SetMapMode((wxMappingMode)opts.mapMode);
e0257cc5
VZ
265 if ( opts.penWidth != 0 )
266 dc.SetPen(wxPen(*wxWHITE, opts.penWidth));
267
b9fb3b06 268 wxPrintf("Benchmarking %s: ", msg);
c80e612f 269 fflush(stdout);
e0257cc5
VZ
270
271 wxStopWatch sw;
272 int x = 0,
273 y = 0;
ce0cdeb0 274 for ( int n = 0; n < opts.numIters; n++ )
e0257cc5
VZ
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
f8497215 287 wxPrintf("%ld lines done in %ldms = %gus/line\n",
ce0cdeb0 288 opts.numIters, t, (1000. * t)/opts.numIters);
e0257cc5 289 }
2a408a4b
VZ
290
291
b9fb3b06 292 void BenchmarkRectangles(const wxString& msg, wxDC& dc)
2a408a4b 293 {
51f64663
VZ
294 if ( !opts.testRectangles )
295 return;
296
2a408a4b
VZ
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
b9fb3b06 304 wxPrintf("Benchmarking %s: ", msg);
c80e612f 305 fflush(stdout);
2a408a4b
VZ
306
307 wxStopWatch sw;
ce0cdeb0 308 for ( int n = 0; n < opts.numIters; n++ )
2a408a4b
VZ
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
f8497215 318 wxPrintf("%ld rects done in %ldms = %gus/rect\n",
ce0cdeb0 319 opts.numIters, t, (1000. * t)/opts.numIters);
2a408a4b
VZ
320 }
321
b9fb3b06 322 void BenchmarkBitmaps(const wxString& msg, wxDC& dc)
2a408a4b 323 {
51f64663
VZ
324 if ( !opts.testBitmaps )
325 return;
326
2a408a4b
VZ
327 if ( opts.mapMode != 0 )
328 dc.SetMapMode((wxMappingMode)opts.mapMode);
329 if ( opts.penWidth != 0 )
330 dc.SetPen(wxPen(*wxWHITE, opts.penWidth));
331
b9fb3b06 332 wxPrintf("Benchmarking %s: ", msg);
c80e612f 333 fflush(stdout);
2a408a4b
VZ
334
335 wxStopWatch sw;
ce0cdeb0 336 for ( int n = 0; n < opts.numIters; n++ )
2a408a4b
VZ
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
f8497215 346 wxPrintf("%ld bitmaps done in %ldms = %gus/bitmap\n",
ce0cdeb0 347 opts.numIters, t, (1000. * t)/opts.numIters);
2a408a4b
VZ
348 }
349
e45606e9
VZ
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;
ce0cdeb0 364 for ( int n = 0; n < opts.numIters; n++ )
e45606e9 365 {
6e6f4d35 366 UpdateRGB(image.GetData(), n);
e45606e9
VZ
367 dc.DrawBitmap(image, 0, 0);
368 }
369
370 const long t = sw.Time();
371
5adf2ecd 372 wxPrintf("%ld images done in %ldms = %gus/image or %ld FPS\n",
ce0cdeb0
VZ
373 opts.numIters, t, (1000. * t)/opts.numIters,
374 (1000*opts.numIters + t - 1)/t);
e45606e9
VZ
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;
ce0cdeb0 392 for ( int n = 0; n < opts.numIters; n++ )
e45606e9 393 {
6e6f4d35 394 unsigned char c = n % 256;
e45606e9
VZ
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);
6e6f4d35 411 c++;
e45606e9
VZ
412 }
413 }
414
415 dc.DrawBitmap(bitmap, 0, 0);
416 }
417
418 const long t = sw.Time();
419
5adf2ecd 420 wxPrintf("%ld raw bitmaps done in %ldms = %gus/bitmap or %ld FPS\n",
ce0cdeb0
VZ
421 opts.numIters, t, (1000. * t)/opts.numIters,
422 (1000*opts.numIters + t - 1)/t);
e45606e9
VZ
423 }
424
2a408a4b
VZ
425
426 wxBitmap m_bitmap;
54d25f9d
VZ
427#if wxUSE_GLCANVAS
428 wxGLCanvas* m_glCanvas;
429 wxGLContext* m_glContext;
430#endif // wxUSE_GLCANVAS
e0257cc5
VZ
431};
432
433class GraphicsBenchmarkApp : public wxApp
434{
435public:
436 virtual void OnInitCmdLine(wxCmdLineParser& parser)
437 {
438 static const wxCmdLineEntryDesc desc[] =
439 {
51f64663 440 { wxCMD_LINE_SWITCH, "", "bitmaps" },
e45606e9 441 { wxCMD_LINE_SWITCH, "", "images" },
51f64663 442 { wxCMD_LINE_SWITCH, "", "lines" },
e45606e9 443 { wxCMD_LINE_SWITCH, "", "rawbmp" },
51f64663 444 { wxCMD_LINE_SWITCH, "", "rectangles" },
8c14cbc9
VZ
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" },
54d25f9d
VZ
450#if wxUSE_GLCANVAS
451 { wxCMD_LINE_SWITCH, "", "gl" },
452#endif // wxUSE_GLCANVAS
e0257cc5
VZ
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 },
ce0cdeb0
VZ
457 { wxCMD_LINE_OPTION, "I", "images", "", wxCMD_LINE_VAL_NUMBER },
458 { wxCMD_LINE_OPTION, "N", "number-of-iterations", "", wxCMD_LINE_VAL_NUMBER },
2a408a4b 459 { wxCMD_LINE_NONE },
e0257cc5
VZ
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;
ce0cdeb0 476 if ( parser.Found("N", &opts.numIters) && opts.numIters < 1 )
e0257cc5
VZ
477 return false;
478
51f64663 479 opts.testBitmaps = parser.Found("bitmaps");
e45606e9 480 opts.testImages = parser.Found("images");
51f64663 481 opts.testLines = parser.Found("lines");
e45606e9 482 opts.testRawBitmaps = parser.Found("rawbmp");
51f64663 483 opts.testRectangles = parser.Found("rectangles");
e45606e9
VZ
484 if ( !(opts.testBitmaps || opts.testImages || opts.testLines
485 || opts.testRawBitmaps || opts.testRectangles) )
51f64663
VZ
486 {
487 // Do everything by default.
488 opts.testBitmaps =
e45606e9 489 opts.testImages =
51f64663 490 opts.testLines =
e45606e9 491 opts.testRawBitmaps =
51f64663
VZ
492 opts.testRectangles = true;
493 }
494
8c14cbc9
VZ
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");
54d25f9d
VZ
507#if wxUSE_GLCANVAS
508 opts.useGL = parser.Found("gl");
509 if ( opts.useGL )
8c14cbc9 510 {
54d25f9d
VZ
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 }
8c14cbc9
VZ
525 }
526
e0257cc5
VZ
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
541IMPLEMENT_APP_CONSOLE(GraphicsBenchmarkApp)