Use a non-uniform bitmap for image tests in the 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 struct GraphicsBenchmarkOptions
23 {
24 GraphicsBenchmarkOptions()
25 {
26 mapMode = 0;
27 penWidth = 0;
28
29 width = 800;
30 height = 600;
31
32 numIters = 1000;
33
34 testBitmaps =
35 testImages =
36 testLines =
37 testRawBitmaps =
38 testRectangles = false;
39
40 usePaint =
41 useClient =
42 useMemory = false;
43
44 useDC =
45 useGC = false;
46 }
47
48 long mapMode,
49 penWidth,
50 width,
51 height,
52 numIters;
53
54 bool testBitmaps,
55 testImages,
56 testLines,
57 testRawBitmaps,
58 testRectangles;
59
60 bool usePaint,
61 useClient,
62 useMemory;
63
64 bool useDC,
65 useGC;
66 } opts;
67
68 class GraphicsBenchmarkFrame : public wxFrame
69 {
70 public:
71 GraphicsBenchmarkFrame()
72 : wxFrame(NULL, wxID_ANY, "wxWidgets Graphics Benchmark")
73 {
74 Connect(wxEVT_PAINT,
75 wxPaintEventHandler(GraphicsBenchmarkFrame::OnPaint));
76
77 m_bitmap.Create(64, 64, 32);
78
79 Show();
80 SetClientSize(opts.width, opts.height);
81 }
82
83 private:
84 // Just change the image in some (quick) way to show that it's really being
85 // updated on screen.
86 void UpdateRGB(unsigned char* data, int n)
87 {
88 for ( int y = 0; y < opts.height; ++y )
89 {
90 memset(data, n % 256, 3*opts.width);
91
92 data += 3*opts.width;
93 n++;
94 }
95 }
96 void OnPaint(wxPaintEvent& WXUNUSED(event))
97 {
98 if ( opts.usePaint )
99 {
100 wxPaintDC dc(this);
101 wxGCDC gcdc(dc);
102 BenchmarkDCAndGC("paint", dc, gcdc);
103 }
104
105 if ( opts.useClient )
106 {
107 wxClientDC dc(this);
108 wxGCDC gcdc(dc);
109 BenchmarkDCAndGC("client", dc, gcdc);
110 }
111
112 if ( opts.useMemory )
113 {
114 wxBitmap bmp(opts.width, opts.height);
115 wxMemoryDC dc(bmp);
116 wxGCDC gcdc(dc);
117 BenchmarkDCAndGC("memory", dc, gcdc);
118 }
119
120 wxTheApp->ExitMainLoop();
121 }
122
123 void BenchmarkDCAndGC(const char* dckind, wxDC& dc, wxGCDC& gcdc)
124 {
125 if ( opts.useDC )
126 BenchmarkAll(wxString::Format("%6s DC", dckind), dc);
127 if ( opts.useGC )
128 BenchmarkAll(wxString::Format("%6s GC", dckind), gcdc);
129 }
130
131 void BenchmarkAll(const wxString& msg, wxDC& dc)
132 {
133 BenchmarkBitmaps(msg, dc);
134 BenchmarkImages(msg, dc);
135 BenchmarkLines(msg, dc);
136 BenchmarkRawBitmaps(msg, dc);
137 BenchmarkRectangles(msg, dc);
138 }
139
140 void BenchmarkLines(const wxString& msg, wxDC& dc)
141 {
142 if ( !opts.testLines )
143 return;
144
145 if ( opts.mapMode != 0 )
146 dc.SetMapMode((wxMappingMode)opts.mapMode);
147 if ( opts.penWidth != 0 )
148 dc.SetPen(wxPen(*wxWHITE, opts.penWidth));
149
150 wxPrintf("Benchmarking %s: ", msg);
151 fflush(stdout);
152
153 wxStopWatch sw;
154 int x = 0,
155 y = 0;
156 for ( int n = 0; n < opts.numIters; n++ )
157 {
158 int x1 = rand() % opts.width,
159 y1 = rand() % opts.height;
160
161 dc.DrawLine(x, y, x1, y1);
162
163 x = x1;
164 y = y1;
165 }
166
167 const long t = sw.Time();
168
169 wxPrintf("%ld lines done in %ldms = %gus/line\n",
170 opts.numIters, t, (1000. * t)/opts.numIters);
171 }
172
173
174 void BenchmarkRectangles(const wxString& msg, wxDC& dc)
175 {
176 if ( !opts.testRectangles )
177 return;
178
179 if ( opts.mapMode != 0 )
180 dc.SetMapMode((wxMappingMode)opts.mapMode);
181 if ( opts.penWidth != 0 )
182 dc.SetPen(wxPen(*wxWHITE, opts.penWidth));
183
184 dc.SetBrush( *wxRED_BRUSH );
185
186 wxPrintf("Benchmarking %s: ", msg);
187 fflush(stdout);
188
189 wxStopWatch sw;
190 for ( int n = 0; n < opts.numIters; n++ )
191 {
192 int x = rand() % opts.width,
193 y = rand() % opts.height;
194
195 dc.DrawRectangle(x, y, 32, 32);
196 }
197
198 const long t = sw.Time();
199
200 wxPrintf("%ld rects done in %ldms = %gus/rect\n",
201 opts.numIters, t, (1000. * t)/opts.numIters);
202 }
203
204 void BenchmarkBitmaps(const wxString& msg, wxDC& dc)
205 {
206 if ( !opts.testBitmaps )
207 return;
208
209 if ( opts.mapMode != 0 )
210 dc.SetMapMode((wxMappingMode)opts.mapMode);
211 if ( opts.penWidth != 0 )
212 dc.SetPen(wxPen(*wxWHITE, opts.penWidth));
213
214 wxPrintf("Benchmarking %s: ", msg);
215 fflush(stdout);
216
217 wxStopWatch sw;
218 for ( int n = 0; n < opts.numIters; n++ )
219 {
220 int x = rand() % opts.width,
221 y = rand() % opts.height;
222
223 dc.DrawBitmap(m_bitmap, x, y, true);
224 }
225
226 const long t = sw.Time();
227
228 wxPrintf("%ld bitmaps done in %ldms = %gus/bitmap\n",
229 opts.numIters, t, (1000. * t)/opts.numIters);
230 }
231
232 void BenchmarkImages(const wxString& msg, wxDC& dc)
233 {
234 if ( !opts.testImages )
235 return;
236
237 if ( opts.mapMode != 0 )
238 dc.SetMapMode((wxMappingMode)opts.mapMode);
239
240 wxPrintf("Benchmarking %s: ", msg);
241 fflush(stdout);
242
243 wxImage image(wxSize(opts.width, opts.height), false /* don't clear */);
244
245 wxStopWatch sw;
246 for ( int n = 0; n < opts.numIters; n++ )
247 {
248 UpdateRGB(image.GetData(), n);
249 dc.DrawBitmap(image, 0, 0);
250 }
251
252 const long t = sw.Time();
253
254 wxPrintf("%ld images done in %ldms = %gus/image or %d FPS\n",
255 opts.numIters, t, (1000. * t)/opts.numIters,
256 (1000*opts.numIters + t - 1)/t);
257 }
258
259 void BenchmarkRawBitmaps(const wxString& msg, wxDC& dc)
260 {
261 if ( !opts.testRawBitmaps )
262 return;
263
264 if ( opts.mapMode != 0 )
265 dc.SetMapMode((wxMappingMode)opts.mapMode);
266
267 wxPrintf("Benchmarking %s: ", msg);
268 fflush(stdout);
269
270 wxBitmap bitmap(opts.width, opts.height, 24);
271 wxNativePixelData data(bitmap);
272
273 wxStopWatch sw;
274 for ( int n = 0; n < opts.numIters; n++ )
275 {
276 unsigned char c = n % 256;
277 {
278 wxNativePixelData::Iterator p(data);
279 for ( int y = 0; y < opts.height; ++y )
280 {
281 wxNativePixelData::Iterator rowStart = p;
282
283 for ( int x = 0; x < opts.width; ++x )
284 {
285 p.Red() =
286 p.Green() =
287 p.Blue() = c;
288 ++p;
289 }
290
291 p = rowStart;
292 p.OffsetY(data, 1);
293 c++;
294 }
295 }
296
297 dc.DrawBitmap(bitmap, 0, 0);
298 }
299
300 const long t = sw.Time();
301
302 wxPrintf("%ld raw bitmaps done in %ldms = %gus/bitmap or %d FPS\n",
303 opts.numIters, t, (1000. * t)/opts.numIters,
304 (1000*opts.numIters + t - 1)/t);
305 }
306
307
308 wxBitmap m_bitmap;
309 };
310
311 class GraphicsBenchmarkApp : public wxApp
312 {
313 public:
314 virtual void OnInitCmdLine(wxCmdLineParser& parser)
315 {
316 static const wxCmdLineEntryDesc desc[] =
317 {
318 { wxCMD_LINE_SWITCH, "", "bitmaps" },
319 { wxCMD_LINE_SWITCH, "", "images" },
320 { wxCMD_LINE_SWITCH, "", "lines" },
321 { wxCMD_LINE_SWITCH, "", "rawbmp" },
322 { wxCMD_LINE_SWITCH, "", "rectangles" },
323 { wxCMD_LINE_SWITCH, "", "paint" },
324 { wxCMD_LINE_SWITCH, "", "client" },
325 { wxCMD_LINE_SWITCH, "", "memory" },
326 { wxCMD_LINE_SWITCH, "", "dc" },
327 { wxCMD_LINE_SWITCH, "", "gc" },
328 { wxCMD_LINE_OPTION, "m", "map-mode", "", wxCMD_LINE_VAL_NUMBER },
329 { wxCMD_LINE_OPTION, "p", "pen-width", "", wxCMD_LINE_VAL_NUMBER },
330 { wxCMD_LINE_OPTION, "w", "width", "", wxCMD_LINE_VAL_NUMBER },
331 { wxCMD_LINE_OPTION, "h", "height", "", wxCMD_LINE_VAL_NUMBER },
332 { wxCMD_LINE_OPTION, "I", "images", "", wxCMD_LINE_VAL_NUMBER },
333 { wxCMD_LINE_OPTION, "N", "number-of-iterations", "", wxCMD_LINE_VAL_NUMBER },
334 { wxCMD_LINE_NONE },
335 };
336
337 parser.SetDesc(desc);
338 }
339
340 virtual bool OnCmdLineParsed(wxCmdLineParser& parser)
341 {
342 if ( parser.Found("m", &opts.mapMode) &&
343 (opts.mapMode < 1 || opts.mapMode > wxMM_METRIC) )
344 return false;
345 if ( parser.Found("p", &opts.penWidth) && opts.penWidth < 1 )
346 return false;
347 if ( parser.Found("w", &opts.width) && opts.width < 1 )
348 return false;
349 if ( parser.Found("h", &opts.height) && opts.height < 1 )
350 return false;
351 if ( parser.Found("N", &opts.numIters) && opts.numIters < 1 )
352 return false;
353
354 opts.testBitmaps = parser.Found("bitmaps");
355 opts.testImages = parser.Found("images");
356 opts.testLines = parser.Found("lines");
357 opts.testRawBitmaps = parser.Found("rawbmp");
358 opts.testRectangles = parser.Found("rectangles");
359 if ( !(opts.testBitmaps || opts.testImages || opts.testLines
360 || opts.testRawBitmaps || opts.testRectangles) )
361 {
362 // Do everything by default.
363 opts.testBitmaps =
364 opts.testImages =
365 opts.testLines =
366 opts.testRawBitmaps =
367 opts.testRectangles = true;
368 }
369
370 opts.usePaint = parser.Found("paint");
371 opts.useClient = parser.Found("client");
372 opts.useMemory = parser.Found("memory");
373 if ( !(opts.usePaint || opts.useClient || opts.useMemory) )
374 {
375 opts.usePaint =
376 opts.useClient =
377 opts.useMemory = true;
378 }
379
380 opts.useDC = parser.Found("dc");
381 opts.useGC = parser.Found("gc");
382 if ( !(opts.useDC || opts.useGC) )
383 {
384 opts.useDC =
385 opts.useGC = true;
386 }
387
388 return true;
389 }
390
391 virtual bool OnInit()
392 {
393 if ( !wxApp::OnInit() )
394 return false;
395
396 new GraphicsBenchmarkFrame;
397
398 return true;
399 }
400 };
401
402 IMPLEMENT_APP_CONSOLE(GraphicsBenchmarkApp)