1 // This is core/vgui/tests/test_drawpix_speed.cxx
2 #include <iostream>
3 #ifdef _MSC_VER
4 #  include "vcl_msvc_warnings.h"
5 #endif
6 
7 #include "vpl/vpl.h"
8 
9 #include "vul/vul_timer.h"
10 
11 #include "vgui/vgui_gl.h"
12 #include "vgui/vgui_glx.h"
13 #include "vgui/vgui_utils.h"
14 
15 #include <X11/Xlib.h>
16 #include <X11/Xutil.h>
17 
18 
19 #if VGUI_MESA
20 #  include <GL/xmesa.h>
21 #endif
22 
23 static int attribs[] = { GLX_RGBA, GLX_RED_SIZE, 5, GLX_GREEN_SIZE, 6, GLX_BLUE_SIZE, 5, GLX_DOUBLEBUFFER, None };
24 
25 unsigned char global_data[512 * 512 * 4];
26 
27 #if 0  // unused static function
28 static Bool WaitForNotify(Display *d, XEvent *e, char *arg)
29 {
30   return e->type == MapNotify && e->xmap.window == (Window)arg;
31 }
32 #endif // 0
33 
34 double
fps_gl(GLenum pack_type,GLenum pix_type)35 fps_gl(GLenum pack_type, GLenum pix_type)
36 {
37   int draws = 0;
38   int elapsed;
39   vul_timer timer;
40   timer.mark();
41   do
42   {
43     glDrawPixels(512, 512, pack_type, pix_type, global_data);
44     ++draws;
45     elapsed = timer.real();
46   } while (elapsed < 3000);
47   return draws * 1000.0 / elapsed;
48 }
49 
50 
51 #ifdef HAS_HERMES
52 #  include <Hermes/Hermes.h>
53 double
fps_hermes(float src_scale,float dest_scale,HermesFormat * src_format,XImage * backbuffer)54 fps_hermes(float src_scale, float dest_scale, HermesFormat * src_format, XImage * backbuffer)
55 {
56   HermesFormat * dest_format = Hermes_FormatNew(
57     backbuffer->bits_per_pixel, backbuffer->red_mask, backbuffer->green_mask, backbuffer->blue_mask, 0, 0);
58   HermesHandle converter = Hermes_ConverterInstance(HERMES_CONVERT_NORMAL);
59   Hermes_ConverterRequest(converter, src_format, dest_format);
60   int draws = 0;
61   int elapsed;
62   vul_timer timer;
63   int bytes_per_pixel = src_format->bits / 8;
64   int succeed;
65   do
66   {
67     succeed = Hermes_ConverterCopy(converter,
68                                    global_data,
69                                    0,
70                                    0,
71                                    (int)(src_scale * 512),
72                                    (int)(src_scale * 512),
73                                    512 * bytes_per_pixel,
74                                    backbuffer->data,
75                                    0,
76                                    0,
77                                    (int)(dest_scale * 512),
78                                    (int)(dest_scale * 512),
79                                    backbuffer->bytes_per_line);
80     if (!succeed)
81       return 0;
82     elapsed = timer.real();
83     ++draws;
84   } while (elapsed < 3000);
85   Hermes_ConverterReturn(converter);
86   Hermes_FormatFree(dest_format);
87   Hermes_FormatFree(src_format);
88   return draws * 1000.0 / elapsed;
89 }
90 
91 double
fps_hermes_grey(float src_scale,float dest_scale,XImage * backbuffer)92 fps_hermes_grey(float src_scale, float dest_scale, XImage * backbuffer)
93 {
94   // special paletted case for 8-bit mode
95   HermesHandle palette = Hermes_PaletteInstance();
96   HermesFormat * dest_format = Hermes_FormatNew(
97     backbuffer->bits_per_pixel, backbuffer->red_mask, backbuffer->green_mask, backbuffer->blue_mask, 0, 0);
98   HermesFormat * src_format = Hermes_FormatNew(8, 0, 0, 0, 0, 1);
99   HermesHandle converter = Hermes_ConverterInstance(HERMES_CONVERT_NORMAL);
100   Hermes_ConverterRequest(converter, src_format, dest_format);
101   Hermes_ConverterPalette(converter, palette, palette); // last param is a dummy
102   int draws = 0;
103   int elapsed;
104   vul_timer timer;
105   int succeed;
106   do
107   {
108     succeed = Hermes_ConverterCopy(converter,
109                                    global_data,
110                                    0,
111                                    0,
112                                    (int)(src_scale * 512),
113                                    (int)(src_scale * 512),
114                                    512 * 1,
115                                    backbuffer->data,
116                                    0,
117                                    0,
118                                    (int)(dest_scale * 512),
119                                    (int)(dest_scale * 512),
120                                    backbuffer->bytes_per_line);
121     if (!succeed)
122       return 0;
123     elapsed = timer.real();
124     ++draws;
125   } while (elapsed < 3000);
126   Hermes_ConverterReturn(converter);
127   Hermes_PaletteReturn(palette);
128   Hermes_FormatFree(src_format);
129   Hermes_FormatFree(dest_format);
130   return draws * 1000.0 / elapsed;
131 }
132 
133 #endif // HAS_HERMES
134 
135 void
pattern_grey(unsigned char * data)136 pattern_grey(unsigned char * data)
137 {
138   for (int y = 0; y < 512; ++y)
139   {
140     for (int x = 0; x < 256; ++x)
141     {
142       data[y * 512 + 2 * x] = data[y * 512 + 2 * x + 1] = static_cast<unsigned char>(x);
143     }
144   }
145 }
146 
147 void
pattern_RGB16(unsigned char * data,bool little_endian)148 pattern_RGB16(unsigned char * data, bool little_endian)
149 {
150   unsigned short r, g, b;
151   unsigned short * my_data = (unsigned short *)data;
152   if (little_endian)
153   {
154     r = 0x001f;
155     g = 0x07e0;
156     b = 0xf800;
157   }
158   else
159   {
160     r = 0xf800;
161     g = 0x07e0;
162     b = 0x001f;
163   }
164   for (int y = 0; y < 512; ++y)
165   {
166     for (int x = 0; x < 170; ++x)
167     {
168       my_data[y * 512 + x] = r;
169       my_data[y * 512 + 170 + x] = g;
170       my_data[y * 512 + 340 + x] = b;
171     }
172   }
173 }
174 
175 void
pattern_RGB24(unsigned char * data,bool)176 pattern_RGB24(unsigned char * data, bool /*little_endian*/)
177 {
178   for (int n = 0; n < 512 * 512 * 3; ++n)
179     data[n] = 0;
180 
181   for (int y = 0; y < 512; ++y)
182   {
183     for (int x = 0; x < 170; ++x)
184     {
185       data[y * 512 * 3 + 3 * x] = 255;
186       data[y * 512 * 3 + 170 * 3 + 3 * x + 1] = 255;
187       data[y * 512 * 3 + 340 * 3 + 3 * x + 2] = 255;
188     }
189   }
190 }
191 
192 void
pattern_RGB32(unsigned char * data,bool little_endian)193 pattern_RGB32(unsigned char * data, bool little_endian)
194 {
195   unsigned long r, g, b;
196   unsigned long * my_data = (unsigned long *)data;
197   if (little_endian)
198   {
199     r = 0x000000ff;
200     g = 0x0000ff00;
201     b = 0x00ff0000;
202   }
203   else
204   {
205     r = 0xff000000;
206     g = 0x00ff0000;
207     b = 0x0000ff00;
208   }
209   for (int y = 0; y < 512; ++y)
210   {
211     for (int x = 0; x < 170; ++x)
212     {
213       my_data[y * 512 + x] = r;
214       my_data[y * 512 + 170 + x] = g;
215       my_data[y * 512 + 340 + x] = b;
216     }
217   }
218 }
219 
220 
221 // Try to do the #ifdef .. #endif madness once and for all here :
222 static struct
223 {
224   GLenum format;
225   GLenum type;
226   char const * nfixed;
227   char const * pretty;
228 }
229 
230 ft_tab[] = { { GL_LUMINANCE, GL_UNSIGNED_BYTE, "LUM   ", "8bit greyscale" },
231              { GL_RGB, GL_UNSIGNED_BYTE, "RGB   ", "24bit 888 RGB" },
232              { GL_RGBA, GL_UNSIGNED_BYTE, "RGBA  ", "32bit 8888 RGBA" },
233 #if defined(GL_VERSION_1_2)
234              { GLenum(GL_RGB), GLenum(GL_UNSIGNED_SHORT_5_6_5), "RGB565", "16bit 565 RGB" },
235              { GLenum(GL_BGR), GLenum(GL_UNSIGNED_BYTE), "BGR   ", "24bit 888 BGR" },
236              { GLenum(GL_BGRA), GLenum(GL_UNSIGNED_BYTE), "BGRA  ", "32bit 8888 BGRA" },
237 #endif
238 #if defined(GL_ABGR_EXT) || defined(GL_EXT_abgr)
239              { GLenum(GL_ABGR_EXT), GLenum(GL_UNSIGNED_BYTE), "ABGR  ", "32bit ABGR" },
240 #endif
241              { GL_NONE, GL_NONE, 0, 0 } };
242 
243 static const int ft_size = sizeof(ft_tab) / sizeof(ft_tab[0]) - 1;
244 
245 
246 int
main()247 main()
248 {
249   // GLX window code straight out of http://www.eecs.tulane.edu/www/graphics/doc/OpenGL-Man-Pages/glXIntro.html
250   std::cerr << "Opening double-buffered, RGBA GLX context...\n\n";
251   Display * display = XOpenDisplay(0);
252   XVisualInfo * visualinfo = glXChooseVisual(display, DefaultScreen(display), attribs);
253   GLXContext context = glXCreateContext(display, visualinfo, 0, GL_TRUE);
254 
255   Colormap cmap = XCreateColormap(display, RootWindow(display, visualinfo->screen), visualinfo->visual, AllocNone);
256 
257   // create a window
258   XSetWindowAttributes swa;
259   swa.colormap = cmap;
260   swa.border_pixel = 0;
261   swa.event_mask = StructureNotifyMask;
262   Window window = XCreateWindow(display,
263                                 RootWindow(display, visualinfo->screen),
264                                 0,
265                                 0,
266                                 512,
267                                 512,
268                                 0,
269                                 visualinfo->depth,
270                                 InputOutput,
271                                 visualinfo->visual,
272                                 CWBorderPixel | CWColormap | CWEventMask,
273                                 &swa);
274 
275   glXMakeCurrent(display, window, context);
276 
277   bool little_endian = (ImageByteOrder(display) == LSBFirst);
278   std::cerr << "GL_VERSION : " << (const char *)glGetString(GL_VERSION) << '\n'
279             << "GL_RENDERER : " << (const char *)glGetString(GL_RENDERER) << "\n\n"
280             << "X Display -\n"
281             << "      byte-order : " << (little_endian ? "little" : "big") << "-endian\n\n"
282             << "XVisualInfo -\n"
283             << "           depth : " << visualinfo->depth << std::endl
284             << "        red-mask : " << std::hex << visualinfo->red_mask << '\n'
285             << "      green-mask : " << std::hex << visualinfo->green_mask << '\n'
286             << "       blue-mask : " << std::hex << visualinfo->blue_mask << "\n\n"
287             << "GL Gets -\n";
288   GLint data_int;
289   glGetIntegerv(GL_RED_BITS, &data_int);
290   std::cerr << "        red-bits : " << data_int << std::endl;
291   glGetIntegerv(GL_GREEN_BITS, &data_int);
292   std::cerr << "      green-bits : " << data_int << std::endl;
293   glGetIntegerv(GL_BLUE_BITS, &data_int);
294   std::cerr << "       blue-bits : " << data_int << std::endl;
295   glGetIntegerv(GL_ALPHA_BITS, &data_int);
296   std::cerr << "      alpha-bits : " << data_int << std::endl;
297 
298 #if VGUI_MESA
299   {
300     std::cerr << std::endl;
301     XMesaBuffer mesabuf = XMesaGetCurrentBuffer();
302     Pixmap p;
303     XImage * backbuffer;
304     XMesaGetBackBuffer(mesabuf, &p, &backbuffer);
305 
306     bool little_endian = (backbuffer->byte_order == LSBFirst);
307     std::cerr << "Mesa backbuffer XImage -\n"
308               << "           depth : " << backbuffer->depth << std::endl
309               << "  bits-per-pixel : " << backbuffer->bits_per_pixel << std::endl
310               << "      byte_order : " << (little_endian ? "little" : "big") << "-endian\n"
311               << "  bytes-per-line : " << backbuffer->bytes_per_line << std::endl
312               << "        red-mask : " << std::hex << backbuffer->red_mask << '\n'
313               << "      green-mask : " << std::hex << backbuffer->green_mask << '\n'
314               << "       blue-mask : " << std::hex << backbuffer->blue_mask << '\n';
315   }
316 #endif
317 
318   vgui_utils::set_glViewport(0, 0, 512, 512);
319   glMatrixMode(GL_PROJECTION);
320   glLoadIdentity();
321   glOrtho(0.0, 512, 0.0, 512, -1.0, 1.0);
322   glMatrixMode(GL_MODELVIEW);
323   glLoadIdentity();
324 
325   glRasterPos2i(0, 0);
326 
327   glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
328   glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
329   glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // gl_direct_DrawPixels needs this set to 1 !!
330   glPixelStorei(GL_UNPACK_ROW_LENGTH, 512);
331 
332   glDisable(GL_ALPHA_TEST);
333   glDisable(GL_BLEND);
334   glDisable(GL_DEPTH_TEST);
335 
336   vgui_utils::set_glPixelZoom(1.0, 1.0);
337   glDrawBuffer(GL_BACK_LEFT);
338 
339 #if 0 // commented out
340   // Render from all formats to check endian settings
341   XMapWindow(display, window);
342   XEvent event;
343   XIfEvent(display, &event, WaitForNotify, (char*)window);
344   std::cerr << "Rendering from 8-bit grey-level...\n";
345   pattern_grey(global_data);
346   glDrawPixels(512,512,GL_LUMINANCE,GL_UNSIGNED_BYTE,global_data);
347   glXSwapBuffers(display, window);
348   vpl_sleep(1);
349 #  if defined(GL_VERSION_1_2)
350   std::cerr << "Rendering from 16-bit 565 RGB...\n";
351   pattern_RGB16(global_data, little_endian);
352   glDrawPixels(512,512,GL_RGB,GL_UNSIGNED_SHORT_5_6_5,global_data);
353   glXSwapBuffers(display, window);
354   vpl_sleep(1);
355 #  endif
356   std::cerr << "Rendering from 24-bit 888 RGB...\n";
357   pattern_RGB24(global_data, little_endian);
358   glDrawPixels(512,512,GL_RGB,GL_UNSIGNED_BYTE,global_data);
359   glXSwapBuffers(display, window);
360   vpl_sleep(1);
361   std::cerr << "Rendering from 32-bit 8888 RGBA...\n";
362   pattern_RGB32(global_data, little_endian);
363   glDrawPixels(512,512,GL_RGBA,GL_UNSIGNED_BYTE,global_data);
364   glXSwapBuffers(display, window);
365   vpl_sleep(1);
366 #endif // end commented out
367 
368   {
369     std::cerr << "\nglClear - ";
370     int draws = 0;
371     int elapsed;
372     vul_timer timer;
373     do
374     {
375       glClear(GL_COLOR_BUFFER_BIT);
376       elapsed = timer.real();
377       ++draws;
378     } while (elapsed < 5000);
379     std::cerr << 512 * 512 * draws / (elapsed / 1000.0) << " pixels per second\n";
380   }
381   {
382     std::cerr << "\nglDrawPixels -\n";
383     double fps;
384     std::cerr << "source -";
385     for (int i = 0; i < ft_size; ++i)
386       std::cerr << "    " << ft_tab[i].nfixed;
387     std::cerr << std::endl
388               << "source -    LUM       RGB565    RGB       BGR       RGBA      BGRA      ABGR\n"
389               << "zoom 1.00x  ";
390     for (int i = 0; i < ft_size; ++i)
391     {
392       fps = fps_gl(ft_tab[i].format, ft_tab[i].type);
393       std::cerr << 512 * 512 * fps << "   ";
394     }
395     std::cerr << "\nzoom 1.90x  ";
396     vgui_utils::set_glPixelZoom(1.9f, 1.9f);
397     for (int i = 0; i < ft_size; ++i)
398     {
399       fps = fps_gl(ft_tab[i].format, ft_tab[i].type);
400       std::cerr << 512 * 512 * fps << "   ";
401     }
402     std::cerr << "\nzoom 0.51x  ";
403     vgui_utils::set_glPixelZoom(0.51f, 0.51f);
404     for (int i = 0; i < ft_size; ++i)
405     {
406       fps = fps_gl(ft_tab[i].format, ft_tab[i].type);
407       std::cerr << 0.51 * 0.51 * 512 * 512 * fps << "   ";
408     }
409     std::cerr << std::endl;
410   }
411 
412 #if defined(HAS_HERMES) && VGUI_MESA
413   {
414     XMesaBuffer mesabuf = XMesaGetCurrentBuffer();
415     Pixmap p;
416     XImage * backbuffer;
417     XMesaGetBackBuffer(mesabuf, &p, &backbuffer);
418 
419     Hermes_Init();
420     HermesFormat * dest_format = Hermes_FormatNew(
421       backbuffer->bits_per_pixel, backbuffer->red_mask, backbuffer->green_mask, backbuffer->blue_mask, 0, 0);
422     {
423       std::cerr << "\nHermesClear - ";
424       HermesHandle clearer = Hermes_ClearerInstance();
425       Hermes_ClearerRequest(clearer, dest_format);
426       int draws = 0;
427       int elapsed;
428       vul_timer timer;
429       do
430       {
431         Hermes_ClearerClear(clearer, backbuffer->data, 0, 0, 512, 512, backbuffer->bytes_per_line, 0, 0, 0, 0);
432         elapsed = timer.real();
433         ++draws;
434       } while (elapsed < 3000);
435       std::cerr << (512 * 512 * draws) / (elapsed / 1000.0) << " pixels per second\n";
436       Hermes_ClearerReturn(clearer);
437     }
438     {
439       std::cerr << "\nHermesConverter -\n";
440       HermesFormat * src_format;
441       double fps;
442       std::cerr << "source -    LUM      OxRGB565 OxRGB    OxBGR    Ox_RGB   0x_BGR\n";
443 
444       std::cerr << "zoom 1.00x  ";
445       fps = fps_hermes_grey(1.0, 1.0, backbuffer);
446       std::cerr << 12 * 512 * fps << "  ";
447 
448       src_format = Hermes_FormatNew(16, 0xf800, 0x07e0, 0x001f, 0, 0);
449       fps = fps_hermes(1.0, 1.0, src_format, backbuffer);
450       std::cerr << 12 * 512 * fps << "  ";
451       src_format = Hermes_FormatNew(24, 0xff0000, 0xff00, 0xff, 0, 0);
452       fps = fps_hermes(1.0, 1.0, src_format, backbuffer);
453       std::cerr << 12 * 512 * fps << "  ";
454       src_format = Hermes_FormatNew(24, 0xff, 0xff00, 0xff0000, 0, 0);
455       fps = fps_hermes(1.0, 1.0, src_format, backbuffer);
456       std::cerr << 12 * 512 * fps << "  ";
457       src_format = Hermes_FormatNew(32, 0xff0000, 0xff00, 0xff, 0, 0);
458       fps = fps_hermes(1.0, 1.0, src_format, backbuffer);
459       std::cerr << 12 * 512 * fps << "  ";
460       src_format = Hermes_FormatNew(32, 0xff, 0xff00, 0xff0000, 0, 0);
461       fps = fps_hermes(1.0, 1.0, src_format, backbuffer);
462       std::cerr << 12 * 512 * fps << '\n';
463 
464       std::cerr << "zoom 1.90x  ";
465       fps = fps_hermes_grey(0.526, 1.0, backbuffer);
466       std::cerr << 12 * 512 * fps << "  ";
467 
468       src_format = Hermes_FormatNew(16, 0xf800, 0x07e0, 0x001f, 0, 0);
469       fps = fps_hermes(0.526, 1.0, src_format, backbuffer);
470       std::cerr << 12 * 512 * fps << "  ";
471       src_format = Hermes_FormatNew(24, 0xff0000, 0xff00, 0xff, 0, 0);
472       fps = fps_hermes(0.526, 1.0, src_format, backbuffer);
473       std::cerr << 12 * 512 * fps << "  ";
474       src_format = Hermes_FormatNew(24, 0xff, 0xff00, 0xff0000, 0, 0);
475       fps = fps_hermes(0.526, 1.0, src_format, backbuffer);
476       std::cerr << 12 * 512 * fps << "  ";
477       src_format = Hermes_FormatNew(32, 0xff0000, 0xff00, 0xff, 0, 0);
478       fps = fps_hermes(0.526, 1.0, src_format, backbuffer);
479       std::cerr << 12 * 512 * fps << "  ";
480       src_format = Hermes_FormatNew(32, 0xff, 0xff00, 0xff0000, 0, 0);
481       fps = fps_hermes(0.526, 1.0, src_format, backbuffer);
482       std::cerr << 12 * 512 * fps << '\n';
483 
484       std::cerr << "zoom 0.51x  ";
485       fps = fps_hermes_grey(1.0, 0.51, backbuffer);
486       std::cerr << .51 * 0.51 * 512 * 512 * fps << "  ";
487 
488       src_format = Hermes_FormatNew(16, 0xf800, 0x07e0, 0x001f, 0, 0);
489       fps = fps_hermes(1.0, 0.51, src_format, backbuffer);
490       std::cerr << .51 * 0.51 * 512 * 512 * fps << "  ";
491       src_format = Hermes_FormatNew(24, 0xff0000, 0xff00, 0xff, 0, 0);
492       fps = fps_hermes(1.0, 0.51, src_format, backbuffer);
493       std::cerr << .51 * 0.51 * 512 * 512 * fps << "  ";
494       src_format = Hermes_FormatNew(24, 0xff, 0xff00, 0xff0000, 0, 0);
495       fps = fps_hermes(1.0, 0.51, src_format, backbuffer);
496       std::cerr << .51 * 0.51 * 512 * 512 * fps << "  ";
497       src_format = Hermes_FormatNew(32, 0xff0000, 0xff00, 0xff, 0, 0);
498       fps = fps_hermes(1.0, 0.51, src_format, backbuffer);
499       std::cerr << .51 * 0.51 * 512 * 512 * fps << "  ";
500       src_format = Hermes_FormatNew(32, 0xff, 0xff00, 0xff0000, 0, 0);
501       fps = fps_hermes(1.0, 0.51, src_format, backbuffer);
502       std::cerr << .51 * 0.51 * 512 * 512 * fps << '\n';
503     }
504     Hermes_Done();
505   }
506 #endif
507   vpl_sleep(5);
508   return 0;
509 }
510