graphics.cpp 14 KB

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