Add more structure constructor tests.
[piglit/hramrach.git] / tests / glean / treadpixperf.cpp
blob7ad3d42d720e6a2914836cf4378cf28eb079e53c
1 // BEGIN_COPYRIGHT -*- glean -*-
2 //
3 // Copyright (C) 1999 Allen Akin All Rights Reserved.
4 //
5 // Permission is hereby granted, free of charge, to any person
6 // obtaining a copy of this software and associated documentation
7 // files (the "Software"), to deal in the Software without
8 // restriction, including without limitation the rights to use,
9 // copy, modify, merge, publish, distribute, sublicense, and/or
10 // sell copies of the Software, and to permit persons to whom the
11 // Software is furnished to do so, subject to the following
12 // conditions:
13 //
14 // The above copyright notice and this permission notice shall be
15 // included in all copies or substantial portions of the
16 // Software.
17 //
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
19 // KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
20 // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
21 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
22 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 // AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
24 // OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 // DEALINGS IN THE SOFTWARE.
26 //
27 // END_COPYRIGHT
30 #include "treadpixperf.h"
31 #include "rand.h"
32 #include "timer.h"
33 #include "image.h"
34 #include <cassert>
35 #include <cmath>
36 #include <cstring>
38 namespace GLEAN {
41 static PFNGLBINDBUFFERARBPROC BindBuffer = NULL;
42 static PFNGLBUFFERDATAARBPROC BufferData = NULL;
43 static PFNGLMAPBUFFERARBPROC MapBuffer = NULL;
44 static PFNGLUNMAPBUFFERARBPROC UnmapBuffer = NULL;
45 static PFNGLGETBUFFERSUBDATAARBPROC GetBufferSubData = NULL;
47 const GLuint PBO1 = 42, PBO2 = 43;
49 const double minInterval = 1.0; // seconds
52 struct ImageFormat
54 const char *Name;
55 GLuint Bytes; // per pixel
56 GLenum Format;
57 GLenum Type;
61 static ImageFormat Formats[] =
63 { "GL_RGB, GL_UNSIGNED_BYTE", 3, GL_RGB, GL_UNSIGNED_BYTE },
64 { "GL_BGR, GL_UNSIGNED_BYTE", 3, GL_BGR, GL_UNSIGNED_BYTE },
65 { "GL_RGBA, GL_UNSIGNED_BYTE", 4, GL_RGBA, GL_UNSIGNED_BYTE },
66 { "GL_BGRA, GL_UNSIGNED_BYTE", 4, GL_BGRA, GL_UNSIGNED_BYTE },
67 { "GL_ABGR, GL_UNSIGNED_BYTE", 4, GL_ABGR_EXT, GL_UNSIGNED_BYTE },
68 { "GL_RGBA, GL_UNSIGNED_INT_8_8_8_8", 4, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8 },
69 { "GL_BGRA, GL_UNSIGNED_INT_8_8_8_8", 4, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8 },
70 { "GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV", 4, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV },
71 #ifdef GL_EXT_packed_depth_stencil
72 { "GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8", 4, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT },
73 #endif
74 { "GL_DEPTH_COMPONENT, GL_FLOAT", 4, GL_DEPTH_COMPONENT, GL_FLOAT },
75 { "GL_DEPTH_COMPONENT, GL_UNSIGNED_INT", 4, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT },
76 { "GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT", 2, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT },
77 { NULL, 0, 0, 0 } // end of list marker
81 static GLenum PBOmodes[4] =
83 GL_NONE,
84 #ifdef GL_ARB_pixel_buffer_object
85 GL_STREAM_READ_ARB,
86 GL_STATIC_READ_ARB,
87 GL_DYNAMIC_READ_ARB
88 #endif
91 static const char *PBOmodeStrings[4] =
93 "No PBO",
94 "GL_STREAM_READ PBO",
95 "GL_STATIC_READ PBO",
96 "GL_DYNAMIC_READ PBO"
100 static bool
101 isDepthFormat(GLenum format)
103 switch (format) {
104 case GL_DEPTH_COMPONENT:
105 #ifdef GL_EXT_packed_depth_stencil
106 case GL_DEPTH_STENCIL_EXT:
107 #endif
108 return true;
109 default:
110 return false;
115 static bool
116 isStencilFormat(GLenum format)
118 switch (format) {
119 case GL_STENCIL_INDEX:
120 #ifdef GL_EXT_packed_depth_stencil
121 case GL_DEPTH_STENCIL_EXT:
122 #endif
123 return true;
124 default:
125 return false;
130 static bool
131 isDepthStencilFormat(GLenum format)
133 #ifdef GL_EXT_packed_depth_stencil
134 if (format == GL_DEPTH_STENCIL_EXT)
135 return true;
136 #endif
137 return false;
142 // print a SubResult test description in human-readable form
143 void
144 ReadpixPerfResult::SubResult::sprint(char *s) const
146 sprintf(s, "glReadPixels(%d x %d, %s), %s, %s, GL_READ_BUFFER=%s",
147 width, height, Formats[formatNum].Name,
148 PBOmodeStrings[pboMode],
149 work ? "pixel sum" : "no pixel sum",
150 readBuf);
154 void
155 ReadpixPerfResult::SubResult::print(Environment *env) const
157 char descrip[1000], str[1000];
158 sprint(descrip);
159 sprintf(str, "\t%.3f Mpixels/second: %s\n", rate, descrip);
160 env->log << str;
164 static void
165 SimpleRender()
167 glBegin(GL_POINTS);
168 glVertex2f(0, 0);
169 glEnd();
173 // Exercise glReadPixels for a particular image size, format and type.
174 // Return read rate in megapixels / second
175 double
176 ReadpixPerfTest::runNonPBOtest(int formatNum, GLsizei width, GLsizei height,
177 GLuint *sumOut)
179 const GLint bufferSize = width * height * Formats[formatNum].Bytes;
180 GLubyte *buffer = new GLubyte [bufferSize];
182 glPixelStorei(GL_PACK_ALIGNMENT, 1);
184 Timer t;
185 double start = t.getClock();
186 double elapsedTime = 0.0;
187 int iter = 0;
189 do {
190 iter++;
191 if (sumOut) {
192 SimpleRender();
194 glReadPixels(0, 0, width, height,
195 Formats[formatNum].Format,
196 Formats[formatNum].Type, buffer);
197 if (sumOut) {
198 GLuint sum = 0;
199 for (int i = 0; i < bufferSize; i++) {
200 sum += buffer[i];
202 *sumOut = sum;
204 double finish = t.getClock();
205 elapsedTime = finish - start;
206 } while (elapsedTime < minInterval);
208 delete buffer;
210 double rate = width * height * iter / elapsedTime / 1000000.0;
211 return rate;
214 // use glMapBufferARB or glGetBufferSubDataARB:
215 #define MAP_BUFFER 1
217 double
218 ReadpixPerfTest::runPBOtest(int formatNum, GLsizei width, GLsizei height,
219 GLenum bufferUsage, GLuint *sumOut)
221 #ifdef GL_ARB_pixel_buffer_object
222 const GLint bufferSize = width * height * Formats[formatNum].Bytes / 2;
224 glPixelStorei(GL_PACK_ALIGNMENT, 1);
226 // setup PBOs
227 BindBuffer(GL_PIXEL_PACK_BUFFER_ARB, PBO1);
228 BufferData(GL_PIXEL_PACK_BUFFER_ARB, bufferSize, NULL, bufferUsage);
229 BindBuffer(GL_PIXEL_PACK_BUFFER_ARB, PBO2);
230 BufferData(GL_PIXEL_PACK_BUFFER_ARB, bufferSize, NULL, bufferUsage);
232 #if !MAP_BUFFER
233 GLubyte *b = new GLubyte [bufferSize];
234 #endif
236 Timer t;
237 double start = t.getClock();
238 double elapsedTime = 0.0;
239 int iter = 0;
241 do {
242 iter++;
243 if (sumOut) {
244 SimpleRender();
246 // read lower half
247 BindBuffer(GL_PIXEL_PACK_BUFFER_ARB, PBO1);
248 glReadPixels(0, 0, width, height / 2,
249 Formats[formatNum].Format,
250 Formats[formatNum].Type, NULL);
251 // read upper half
252 BindBuffer(GL_PIXEL_PACK_BUFFER_ARB, PBO2);
253 glReadPixels(0, height / 2, width, height / 2,
254 Formats[formatNum].Format,
255 Formats[formatNum].Type, NULL);
256 if (sumOut) {
257 GLuint sum = 0;
258 // sum lower half
259 BindBuffer(GL_PIXEL_PACK_BUFFER_ARB, PBO1);
260 #if MAP_BUFFER
261 GLubyte *b = (GLubyte *)
262 MapBuffer(GL_PIXEL_PACK_BUFFER_ARB,
263 GL_READ_ONLY);
264 #else
265 GetBufferSubData(GL_PIXEL_PACK_BUFFER_ARB,
266 0, bufferSize, b);
267 #endif
268 for (int i = 0; i < bufferSize; i++) {
269 sum += b[i];
271 #if MAP_BUFFER
272 UnmapBuffer(GL_PIXEL_PACK_BUFFER_ARB);
273 #endif
275 // sum upper half
276 BindBuffer(GL_PIXEL_PACK_BUFFER_ARB, PBO2);
277 #if MAP_BUFFER
278 b = (GLubyte *) MapBuffer(GL_PIXEL_PACK_BUFFER_ARB,
279 GL_READ_ONLY);
280 #else
281 GetBufferSubData(GL_PIXEL_PACK_BUFFER_ARB,
282 0, bufferSize, b);
283 #endif
284 for (int i = 0; i < bufferSize; i++) {
285 sum += b[i];
287 #if MAP_BUFFER
288 UnmapBuffer(GL_PIXEL_PACK_BUFFER_ARB);
289 #endif
290 *sumOut = sum;
292 double finish = t.getClock();
293 elapsedTime = finish - start;
294 } while (elapsedTime < minInterval);
296 BindBuffer(GL_PIXEL_PACK_BUFFER_ARB, 0);
298 #if !MAP_BUFFER
299 delete b;
300 #endif
302 double rate = width * height * iter / elapsedTime / 1000000.0;
303 return rate;
304 #else
305 return 0.0;
306 #endif /* GL_ARB_pixel_buffer_object */
311 // Per visual setup.
312 void
313 ReadpixPerfTest::setup(void)
315 env->log << name << ":\n";
317 glGetIntegerv(GL_DEPTH_BITS, &depthBits);
318 glGetIntegerv(GL_STENCIL_BITS, &stencilBits);
320 if (GLUtils::haveExtensions("GL_ARB_pixel_buffer_object")) {
321 BindBuffer = (PFNGLBINDBUFFERARBPROC)
322 GLUtils::getProcAddress("glBindBufferARB");
323 assert(BindBuffer);
324 BufferData = (PFNGLBUFFERDATAARBPROC)
325 GLUtils::getProcAddress("glBufferDataARB");
326 assert(BufferData);
327 MapBuffer = (PFNGLMAPBUFFERARBPROC)
328 GLUtils::getProcAddress("glMapBufferARB");
329 assert(MapBuffer);
330 UnmapBuffer = (PFNGLUNMAPBUFFERARBPROC)
331 GLUtils::getProcAddress("glUnmapBufferARB");
332 assert(UnmapBuffer);
333 GetBufferSubData = (PFNGLGETBUFFERSUBDATAARBPROC)
334 GLUtils::getProcAddress("glGetBufferSubDataARB");
335 assert(GetBufferSubData);
336 numPBOmodes = 4;
338 else {
339 numPBOmodes = 1;
342 // Fill colorbuffer with random data
343 GLubyte *buffer = new GLubyte [windowSize * windowSize * 4];
344 for (int i = 0; i < windowSize * windowSize * 4; i++)
345 buffer[i] = 5;
346 glDrawPixels(windowSize, windowSize, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
347 if (depthBits > 0) {
348 glEnable(GL_DEPTH_TEST);
349 glDepthFunc(GL_ALWAYS);
350 glDrawPixels(windowSize, windowSize,
351 GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, buffer);
353 if (stencilBits > 0) {
354 glDrawPixels(windowSize, windowSize,
355 GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, buffer);
357 delete buffer;
362 void
363 ReadpixPerfTest::runOne(ReadpixPerfResult &r, Window &w)
365 ReadpixPerfResult::SubResult res;
366 (void) w; // silence warning
368 setup();
369 assert(numPBOmodes > 0);
371 r.pass = true;
372 res.width = windowSize;
373 res.height = windowSize;
376 GLint readBuf;
377 glGetIntegerv(GL_READ_BUFFER, &readBuf);
378 if (readBuf == GL_FRONT)
379 strcpy(res.readBuf, "GL_FRONT");
380 else
381 strcpy(res.readBuf, "GL_BACK");
384 for (res.formatNum = 0; Formats[res.formatNum].Name; res.formatNum++) {
386 if (isDepthFormat(Formats[res.formatNum].Format) && depthBits == 0)
387 continue;
388 if (isStencilFormat(Formats[res.formatNum].Format) && stencilBits == 0)
389 continue;
391 if (isDepthStencilFormat(Formats[res.formatNum].Format) &&
392 !GLUtils::haveExtensions("GL_EXT_packed_depth_stencil"))
393 continue;
395 for (res.work = 0; res.work < 2; res.work++) {
396 GLuint firstSum = 0;
398 for (res.pboMode = 0; res.pboMode < numPBOmodes; res.pboMode++) {
399 GLuint sum = 0;
401 if (res.pboMode) {
402 GLenum usage = PBOmodes[res.pboMode];
403 res.rate = runPBOtest(res.formatNum, res.width, res.height, usage,
404 res.work ? &sum : NULL);
406 else {
407 res.rate = runNonPBOtest(res.formatNum, res.width, res.height,
408 res.work ? &sum : NULL);
411 res.print(env);
412 r.results.push_back(res);
414 // sanity check
415 if (res.pboMode == 0) {
416 firstSum = sum;
418 else if (firstSum != sum) {
419 // this should never happen, probably an OpenGL bug
420 char s0[1000];
421 res.sprint(s0);
422 env->log << name
423 << " Error: glReadPixels returned inconsistant data:\n"
424 << s0
425 << " returned "
426 << firstSum
427 << " but expected sum is "
428 << sum << "\n";
429 r.pass = false;
437 void
438 ReadpixPerfTest::logOne(ReadpixPerfResult &r)
440 logPassFail(r);
441 logConcise(r);
445 void
446 ReadpixPerfTest::compareOne(ReadpixPerfResult &oldR,
447 ReadpixPerfResult &newR)
449 const double threshold = 2.0; // percent
451 comparePassFail(oldR, newR);
453 if (newR.pass && oldR.pass) {
454 // if both tests failed, compare/report rates
455 ReadpixPerfResult::sub_iterator it_old = oldR.results.begin();
456 ReadpixPerfResult::sub_iterator it_new = newR.results.begin();
457 assert(oldR.results.size() == newR.results.size());
458 for ( ; it_old != oldR.results.end(); ++it_old, ++it_new) {
459 const ReadpixPerfResult::SubResult &oldres = *it_old;
460 const ReadpixPerfResult::SubResult &newres = *it_new;
462 double diff = (newres.rate - oldres.rate) / newres.rate;
463 diff *= 100.0;
464 if (fabs(diff) >= threshold) {
465 char descrip[1000];
466 newres.sprint(descrip);
467 env->log << name << ": Warning: rate for '"
468 << descrip
469 << "' changed by "
470 << diff
471 << " percent (new: "
472 << newres.rate
473 << " old: "
474 << oldres.rate
475 << " MPixels/sec)\n";
479 else {
480 // one test or the other failed
481 env->log << "\tNew: ";
482 env->log << (newR.pass ? "PASS" : "FAIL");
483 env->log << "\tOld: ";
484 env->log << (oldR.pass ? "PASS" : "FAIL");
489 // Write vector of sub results
490 void
491 ReadpixPerfResult::putresults(ostream &s) const
493 s << pass << '\n';
494 s << results.size() << '\n';
495 for (ReadpixPerfResult::sub_iterator it = results.begin();
496 it != results.end();
497 ++it) {
498 const ReadpixPerfResult::SubResult &res = *it;
499 s << res.rate << '\n';
500 s << res.width << '\n';
501 s << res.height << '\n';
502 s << res.formatNum << '\n';
503 s << res.pboMode << '\n';
504 s << res.readBuf << '\n';
505 s << res.work << '\n';
510 // Read vector of sub results
511 bool
512 ReadpixPerfResult::getresults(istream &s)
514 int count;
516 s >> pass
517 >> count;
519 results.reserve(count);
520 for (int i = 0; i < count; i++) {
521 ReadpixPerfResult::SubResult res;
522 s >> res.rate
523 >> res.width
524 >> res.height
525 >> res.formatNum
526 >> res.pboMode
527 >> res.readBuf
528 >> res.work;
529 results.push_back(res);
531 return s.good();
535 // The test object itself:
536 ReadpixPerfTest readpixperfTest("readpixPerf", "window, rgb",
538 "Test the performance of glReadPixels for a variety of pixel\n"
539 "formats and datatypes.\n"
540 "When GL_ARB_pixel_buffer_object is supported, we also test reading\n"
541 "pixels into a PBO using the three types of buffer usage modes:\n"
542 "GL_STREAM_READ_ARB, GL_STATIC_READ_ARB and GL_DYNAMIC_READ_ARB.\n"
543 "Furthermore, test effect of summing the value of all image bytes\n"
544 "to simulate host-based image processing.\n"
550 } // namespace GLEAN