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