1 // BEGIN_COPYRIGHT -*- glean -*-
3 // Copyright (C) 1999 Allen Akin All Rights Reserved.
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
14 // The above copyright notice and this permission notice shall be
15 // included in all copies or substantial portions of the
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.
30 #include "treadpixperf.h"
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
55 GLuint Bytes
; // per pixel
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
},
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] =
84 #ifdef GL_ARB_pixel_buffer_object
91 static const char *PBOmodeStrings
[4] =
101 isDepthFormat(GLenum format
)
104 case GL_DEPTH_COMPONENT
:
105 #ifdef GL_EXT_packed_depth_stencil
106 case GL_DEPTH_STENCIL_EXT
:
116 isStencilFormat(GLenum format
)
119 case GL_STENCIL_INDEX
:
120 #ifdef GL_EXT_packed_depth_stencil
121 case GL_DEPTH_STENCIL_EXT
:
131 isDepthStencilFormat(GLenum format
)
133 #ifdef GL_EXT_packed_depth_stencil
134 if (format
== GL_DEPTH_STENCIL_EXT
)
142 // print a SubResult test description in human-readable form
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",
155 ReadpixPerfResult::SubResult::print(Environment
*env
) const
157 char descrip
[1000], str
[1000];
159 sprintf(str
, "\t%.3f Mpixels/second: %s\n", rate
, descrip
);
173 // Exercise glReadPixels for a particular image size, format and type.
174 // Return read rate in megapixels / second
176 ReadpixPerfTest::runNonPBOtest(int formatNum
, GLsizei width
, GLsizei height
,
179 const GLint bufferSize
= width
* height
* Formats
[formatNum
].Bytes
;
180 GLubyte
*buffer
= new GLubyte
[bufferSize
];
182 glPixelStorei(GL_PACK_ALIGNMENT
, 1);
185 double start
= t
.getClock();
186 double elapsedTime
= 0.0;
194 glReadPixels(0, 0, width
, height
,
195 Formats
[formatNum
].Format
,
196 Formats
[formatNum
].Type
, buffer
);
199 for (int i
= 0; i
< bufferSize
; i
++) {
204 double finish
= t
.getClock();
205 elapsedTime
= finish
- start
;
206 } while (elapsedTime
< minInterval
);
210 double rate
= width
* height
* iter
/ elapsedTime
/ 1000000.0;
214 // use glMapBufferARB or glGetBufferSubDataARB:
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);
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
);
233 GLubyte
*b
= new GLubyte
[bufferSize
];
237 double start
= t
.getClock();
238 double elapsedTime
= 0.0;
247 BindBuffer(GL_PIXEL_PACK_BUFFER_ARB
, PBO1
);
248 glReadPixels(0, 0, width
, height
/ 2,
249 Formats
[formatNum
].Format
,
250 Formats
[formatNum
].Type
, NULL
);
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
);
259 BindBuffer(GL_PIXEL_PACK_BUFFER_ARB
, PBO1
);
261 GLubyte
*b
= (GLubyte
*)
262 MapBuffer(GL_PIXEL_PACK_BUFFER_ARB
,
265 GetBufferSubData(GL_PIXEL_PACK_BUFFER_ARB
,
268 for (int i
= 0; i
< bufferSize
; i
++) {
272 UnmapBuffer(GL_PIXEL_PACK_BUFFER_ARB
);
276 BindBuffer(GL_PIXEL_PACK_BUFFER_ARB
, PBO2
);
278 b
= (GLubyte
*) MapBuffer(GL_PIXEL_PACK_BUFFER_ARB
,
281 GetBufferSubData(GL_PIXEL_PACK_BUFFER_ARB
,
284 for (int i
= 0; i
< bufferSize
; i
++) {
288 UnmapBuffer(GL_PIXEL_PACK_BUFFER_ARB
);
292 double finish
= t
.getClock();
293 elapsedTime
= finish
- start
;
294 } while (elapsedTime
< minInterval
);
296 BindBuffer(GL_PIXEL_PACK_BUFFER_ARB
, 0);
302 double rate
= width
* height
* iter
/ elapsedTime
/ 1000000.0;
306 #endif /* GL_ARB_pixel_buffer_object */
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");
324 BufferData
= (PFNGLBUFFERDATAARBPROC
)
325 GLUtils::getProcAddress("glBufferDataARB");
327 MapBuffer
= (PFNGLMAPBUFFERARBPROC
)
328 GLUtils::getProcAddress("glMapBufferARB");
330 UnmapBuffer
= (PFNGLUNMAPBUFFERARBPROC
)
331 GLUtils::getProcAddress("glUnmapBufferARB");
333 GetBufferSubData
= (PFNGLGETBUFFERSUBDATAARBPROC
)
334 GLUtils::getProcAddress("glGetBufferSubDataARB");
335 assert(GetBufferSubData
);
342 // Fill colorbuffer with random data
343 GLubyte
*buffer
= new GLubyte
[windowSize
* windowSize
* 4];
344 for (int i
= 0; i
< windowSize
* windowSize
* 4; i
++)
346 glDrawPixels(windowSize
, windowSize
, GL_RGBA
, GL_UNSIGNED_BYTE
, buffer
);
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
);
363 ReadpixPerfTest::runOne(ReadpixPerfResult
&r
, Window
&w
)
365 ReadpixPerfResult::SubResult res
;
366 (void) w
; // silence warning
369 assert(numPBOmodes
> 0);
372 res
.width
= windowSize
;
373 res
.height
= windowSize
;
377 glGetIntegerv(GL_READ_BUFFER
, &readBuf
);
378 if (readBuf
== GL_FRONT
)
379 strcpy(res
.readBuf
, "GL_FRONT");
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)
388 if (isStencilFormat(Formats
[res
.formatNum
].Format
) && stencilBits
== 0)
391 if (isDepthStencilFormat(Formats
[res
.formatNum
].Format
) &&
392 !GLUtils::haveExtensions("GL_EXT_packed_depth_stencil"))
395 for (res
.work
= 0; res
.work
< 2; res
.work
++) {
398 for (res
.pboMode
= 0; res
.pboMode
< numPBOmodes
; res
.pboMode
++) {
402 GLenum usage
= PBOmodes
[res
.pboMode
];
403 res
.rate
= runPBOtest(res
.formatNum
, res
.width
, res
.height
, usage
,
404 res
.work
? &sum
: NULL
);
407 res
.rate
= runNonPBOtest(res
.formatNum
, res
.width
, res
.height
,
408 res
.work
? &sum
: NULL
);
412 r
.results
.push_back(res
);
415 if (res
.pboMode
== 0) {
418 else if (firstSum
!= sum
) {
419 // this should never happen, probably an OpenGL bug
423 << " Error: glReadPixels returned inconsistant data:\n"
427 << " but expected sum is "
438 ReadpixPerfTest::logOne(ReadpixPerfResult
&r
)
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
;
464 if (fabs(diff
) >= threshold
) {
466 newres
.sprint(descrip
);
467 env
->log
<< name
<< ": Warning: rate for '"
475 << " MPixels/sec)\n";
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
491 ReadpixPerfResult::putresults(ostream
&s
) const
494 s
<< results
.size() << '\n';
495 for (ReadpixPerfResult::sub_iterator it
= results
.begin();
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
512 ReadpixPerfResult::getresults(istream
&s
)
519 results
.reserve(count
);
520 for (int i
= 0; i
< count
; i
++) {
521 ReadpixPerfResult::SubResult res
;
529 results
.push_back(res
);
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"