Courtney Goeltzenleuchter | 30e9dc4 | 2014-09-04 16:24:19 -0600 | [diff] [blame] | 1 | // XGL tests |
| 2 | // |
| 3 | // Copyright (C) 2014 LunarG, Inc. |
| 4 | // |
| 5 | // Permission is hereby granted, free of charge, to any person obtaining a |
| 6 | // copy of this software and associated documentation files (the "Software"), |
| 7 | // to deal in the Software without restriction, including without limitation |
| 8 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| 9 | // and/or sell copies of the Software, and to permit persons to whom the |
| 10 | // Software is furnished to do so, subject to the following conditions: |
| 11 | // |
| 12 | // The above copyright notice and this permission notice shall be included |
| 13 | // in all copies or substantial portions of the Software. |
| 14 | // |
| 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
| 20 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
| 21 | // DEALINGS IN THE SOFTWARE. |
| 22 | |
| 23 | #include "xgltestframework.h" |
| 24 | #include "GL/freeglut_std.h" |
| 25 | |
| 26 | XglTestFramework::XglTestFramework() : |
| 27 | m_glut_initialized( false ) |
| 28 | { |
| 29 | } |
| 30 | |
| 31 | // Define all the static elements |
| 32 | bool XglTestFramework::m_show_images = false; |
| 33 | bool XglTestFramework::m_save_images = false; |
| 34 | int XglTestFramework::m_width = 0; |
| 35 | int XglTestFramework::m_height = 0; |
| 36 | int XglTestFramework::m_window = 0; |
| 37 | std::list<XglTestImageRecord> XglTestFramework::m_images; |
| 38 | std::list<XglTestImageRecord>::iterator XglTestFramework::m_display_image; |
| 39 | int m_display_image_idx = 0; |
| 40 | |
| 41 | void XglTestFramework::InitArgs(int *argc, char *argv[]) |
| 42 | { |
| 43 | int i, n; |
| 44 | |
| 45 | for (i=0, n=0; i< *argc; i++) { |
| 46 | if (strncmp("--show-images", argv[i], 13) == 0) { |
| 47 | m_show_images = true; |
| 48 | continue; |
| 49 | } |
| 50 | if (strncmp("--save-images", argv[i], 13) == 0) { |
| 51 | m_save_images = true; |
| 52 | continue; |
| 53 | } |
| 54 | |
| 55 | /* |
| 56 | * Since the above "consume" inputs, update argv |
| 57 | * so that it contains the trimmed list of args for glutInit |
| 58 | */ |
| 59 | argv[n] = argv[i]; |
| 60 | n++; |
| 61 | } |
| 62 | |
| 63 | if (m_show_images) { |
| 64 | glutInit(argc, argv); |
| 65 | } |
| 66 | } |
| 67 | |
| 68 | void XglTestFramework::Reshape( int w, int h ) |
| 69 | { |
| 70 | if (!m_show_images) return; // Do nothing except save info if not enabled |
| 71 | |
| 72 | // Resize window to be large enough to handle biggest image we've seen |
| 73 | // TODO: Probably need some sort of limits for the Window system. |
| 74 | if (w > m_width) { |
| 75 | m_width = w; |
| 76 | } |
| 77 | if (h > m_height) { |
| 78 | m_height = h; |
| 79 | } |
| 80 | |
| 81 | glutReshapeWindow(m_width, m_height); |
| 82 | |
| 83 | glViewport( 0, 0, m_width, m_height ); |
| 84 | glMatrixMode( GL_PROJECTION ); |
| 85 | glLoadIdentity(); |
| 86 | glOrtho( 0.0, m_width, 0.0, m_height, 0.0, 2.0 ); |
| 87 | glMatrixMode( GL_MODELVIEW ); |
| 88 | glLoadIdentity(); |
| 89 | |
| 90 | // glScissor(width/4, height/4, width/2, height/2); |
| 91 | } |
| 92 | |
| 93 | void XglTestFramework::WritePPM( const char *basename, XglImage *image ) |
| 94 | { |
| 95 | string filename; |
| 96 | XGL_RESULT err; |
| 97 | int x, y; |
| 98 | |
| 99 | filename.append(basename); |
| 100 | filename.append(".ppm"); |
| 101 | |
| 102 | const XGL_IMAGE_SUBRESOURCE sr = { |
| 103 | XGL_IMAGE_ASPECT_COLOR, 0, 0 |
| 104 | }; |
| 105 | XGL_SUBRESOURCE_LAYOUT sr_layout; |
Jon Ashburn | e494a1a | 2014-09-25 14:36:58 -0600 | [diff] [blame^] | 106 | XGL_UINT data_size = sizeof(sr_layout); |
Courtney Goeltzenleuchter | 30e9dc4 | 2014-09-04 16:24:19 -0600 | [diff] [blame] | 107 | |
| 108 | err = xglGetImageSubresourceInfo( image->image(), &sr, |
| 109 | XGL_INFO_TYPE_SUBRESOURCE_LAYOUT, |
| 110 | &data_size, &sr_layout); |
| 111 | ASSERT_XGL_SUCCESS( err ); |
| 112 | ASSERT_EQ(data_size, sizeof(sr_layout)); |
| 113 | |
| 114 | const char *ptr; |
| 115 | |
| 116 | err = xglMapMemory( image->memory(), 0, (XGL_VOID **) &ptr ); |
| 117 | ASSERT_XGL_SUCCESS( err ); |
| 118 | |
| 119 | ptr += sr_layout.offset; |
| 120 | |
| 121 | ofstream file (filename.c_str()); |
| 122 | ASSERT_TRUE(file.is_open()) << "Unable to open file: " << filename; |
| 123 | |
| 124 | file << "P6\n"; |
| 125 | file << image->width() << "\n"; |
| 126 | file << image->height() << "\n"; |
| 127 | file << 255 << "\n"; |
| 128 | |
| 129 | for (y = 0; y < image->height(); y++) { |
| 130 | const char *row = ptr; |
| 131 | |
| 132 | for (x = 0; x < image->width(); x++) { |
| 133 | file.write(row, 3); |
| 134 | row += 4; |
| 135 | } |
| 136 | |
| 137 | ptr += sr_layout.rowPitch; |
| 138 | } |
| 139 | |
| 140 | file.close(); |
| 141 | |
| 142 | err = xglUnmapMemory( image->memory() ); |
| 143 | ASSERT_XGL_SUCCESS( err ); |
| 144 | } |
| 145 | |
| 146 | void XglTestFramework::InitGLUT(int w, int h) |
| 147 | { |
| 148 | |
| 149 | if (!m_show_images) return; |
| 150 | |
| 151 | if (!m_glut_initialized) { |
| 152 | glutInitWindowSize(w, h); |
| 153 | |
| 154 | glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); |
| 155 | m_window = glutCreateWindow(NULL); |
| 156 | m_glut_initialized = true; |
| 157 | } |
| 158 | |
| 159 | Reshape(w, h); |
| 160 | } |
| 161 | |
| 162 | void XglTestFramework::Show(const char *comment, XglImage *image) |
| 163 | { |
| 164 | XGL_RESULT err; |
| 165 | |
| 166 | const XGL_IMAGE_SUBRESOURCE sr = { |
| 167 | XGL_IMAGE_ASPECT_COLOR, 0, 0 |
| 168 | }; |
| 169 | XGL_SUBRESOURCE_LAYOUT sr_layout; |
Jon Ashburn | e494a1a | 2014-09-25 14:36:58 -0600 | [diff] [blame^] | 170 | XGL_UINT data_size = sizeof(sr_layout); |
Courtney Goeltzenleuchter | 30e9dc4 | 2014-09-04 16:24:19 -0600 | [diff] [blame] | 171 | |
| 172 | if (!m_show_images) return; |
| 173 | |
| 174 | InitGLUT(image->width(), image->height()); |
| 175 | |
| 176 | err = xglGetImageSubresourceInfo( image->image(), &sr, XGL_INFO_TYPE_SUBRESOURCE_LAYOUT, |
| 177 | &data_size, &sr_layout); |
| 178 | ASSERT_XGL_SUCCESS( err ); |
| 179 | ASSERT_EQ(data_size, sizeof(sr_layout)); |
| 180 | |
| 181 | const char *ptr; |
| 182 | |
| 183 | err = image->MapMemory( (XGL_VOID **) &ptr ); |
| 184 | ASSERT_XGL_SUCCESS( err ); |
| 185 | |
| 186 | ptr += sr_layout.offset; |
| 187 | |
| 188 | XglTestImageRecord record; |
| 189 | record.m_title.append(comment); |
| 190 | record.m_width = image->width(); |
| 191 | record.m_height = image->height(); |
| 192 | // TODO: Need to make this more robust to handle different image formats |
| 193 | record.m_data_size = image->width()*image->height()*4; |
| 194 | record.m_data = malloc(record.m_data_size); |
| 195 | memcpy(record.m_data, ptr, record.m_data_size); |
| 196 | m_images.push_back(record); |
| 197 | m_display_image = --m_images.end(); |
| 198 | |
| 199 | Display(); |
| 200 | |
| 201 | err = image->UnmapMemory(); |
| 202 | ASSERT_XGL_SUCCESS( err ); |
| 203 | } |
| 204 | |
| 205 | void XglTestFramework::RecordImage(XglImage *image) |
| 206 | { |
| 207 | const ::testing::TestInfo* const test_info = |
| 208 | ::testing::UnitTest::GetInstance()->current_test_info(); |
| 209 | |
| 210 | if (m_save_images) { |
| 211 | WritePPM(test_info->test_case_name(), image); |
| 212 | } |
| 213 | |
| 214 | if (m_show_images) { |
| 215 | Show(test_info->test_case_name(), image); |
| 216 | } |
| 217 | } |
| 218 | |
| 219 | void XglTestFramework::Display() |
| 220 | { |
| 221 | glutSetWindowTitle(m_display_image->m_title.c_str()); |
| 222 | |
| 223 | glClearColor(0, 0, 0, 0); |
| 224 | glClear(GL_COLOR_BUFFER_BIT); |
| 225 | glRasterPos3f(0, 0, 0); |
| 226 | glBitmap(0, 0, 0, 0, 0, 0, NULL); |
| 227 | glDrawPixels(m_display_image->m_width, m_display_image->m_height, |
| 228 | GL_RGBA, GL_UNSIGNED_BYTE, m_display_image->m_data); |
| 229 | |
| 230 | glutSwapBuffers(); |
| 231 | } |
| 232 | |
| 233 | void XglTestFramework::Key( unsigned char key, int x, int y ) |
| 234 | { |
| 235 | (void) x; |
| 236 | (void) y; |
| 237 | switch (key) { |
| 238 | case 27: |
| 239 | glutDestroyWindow(m_window); |
| 240 | exit(0); |
| 241 | break; |
| 242 | } |
| 243 | glutPostRedisplay(); |
| 244 | } |
| 245 | |
| 246 | void XglTestFramework::SpecialKey( int key, int x, int y ) |
| 247 | { |
| 248 | (void) x; |
| 249 | (void) y; |
| 250 | switch (key) { |
| 251 | case GLUT_KEY_UP: |
| 252 | case GLUT_KEY_RIGHT: |
| 253 | ++m_display_image; |
| 254 | if (m_display_image == m_images.end()) { |
| 255 | m_display_image = m_images.begin(); |
| 256 | } |
| 257 | break; |
| 258 | case GLUT_KEY_DOWN: |
| 259 | case GLUT_KEY_LEFT: |
| 260 | if (m_display_image == m_images.begin()) { |
| 261 | m_display_image = --m_images.end(); |
| 262 | } else { |
| 263 | --m_display_image; |
| 264 | } |
| 265 | |
| 266 | break; |
| 267 | } |
| 268 | glutPostRedisplay(); |
| 269 | } |
| 270 | |
| 271 | void XglTestFramework::Finish() |
| 272 | { |
| 273 | if (m_images.size() == 0) return; |
| 274 | |
| 275 | glutReshapeFunc( Reshape ); |
| 276 | glutKeyboardFunc( Key ); |
| 277 | glutSpecialFunc( SpecialKey ); |
| 278 | glutDisplayFunc( Display ); |
| 279 | |
| 280 | glutMainLoop(); |
| 281 | } |
| 282 | |
| 283 | |
| 284 | |
| 285 | XglTestImageRecord::XglTestImageRecord() : // Constructor |
| 286 | m_width( 0 ), |
| 287 | m_height( 0 ), |
| 288 | m_data( NULL ) |
| 289 | { |
| 290 | m_data_size = 0; |
| 291 | } |
| 292 | |
| 293 | XglTestImageRecord::~XglTestImageRecord() |
| 294 | { |
| 295 | |
| 296 | } |
| 297 | |
| 298 | XglTestImageRecord::XglTestImageRecord(const XglTestImageRecord ©in) // Copy constructor to handle pass by value. |
| 299 | { |
| 300 | m_title = copyin.m_title; |
| 301 | m_width = copyin.m_width; |
| 302 | m_height = copyin.m_height; |
| 303 | m_data_size = copyin.m_data_size; |
| 304 | m_data = copyin.m_data; // TODO: Do we need to copy the data or is pointer okay? |
| 305 | } |
| 306 | |
| 307 | ostream &operator<<(ostream &output, const XglTestImageRecord &XglTestImageRecord) |
| 308 | { |
| 309 | output << XglTestImageRecord.m_title << " (" << XglTestImageRecord.m_width << |
| 310 | "," << XglTestImageRecord.m_height << ")" << endl; |
| 311 | return output; |
| 312 | } |
| 313 | |
| 314 | XglTestImageRecord& XglTestImageRecord::operator=(const XglTestImageRecord &rhs) |
| 315 | { |
| 316 | m_title = rhs.m_title; |
| 317 | m_width = rhs.m_width; |
| 318 | m_height = rhs.m_height; |
| 319 | m_data_size = rhs.m_data_size; |
| 320 | m_data = rhs.m_data; |
| 321 | return *this; |
| 322 | } |
| 323 | |
| 324 | int XglTestImageRecord::operator==(const XglTestImageRecord &rhs) const |
| 325 | { |
| 326 | if( this->m_data != rhs.m_data) return 0; |
| 327 | return 1; |
| 328 | } |
| 329 | |
| 330 | // This function is required for built-in STL list functions like sort |
| 331 | int XglTestImageRecord::operator<(const XglTestImageRecord &rhs) const |
| 332 | { |
| 333 | if( this->m_data_size < rhs.m_data_size ) return 1; |
| 334 | return 0; |
| 335 | } |
| 336 | |