blob: 5b3b8c2985e4b016b16d07c5f6c066af1e593b56 [file] [log] [blame]
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -06001// 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"
Chia-I Wua6bc0ce2014-12-29 14:38:28 +080024#include "xglrenderframework.h"
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -060025#include "GL/freeglut_std.h"
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -060026//#include "ShaderLang.h"
27#include "GlslangToBil.h"
Tony Barbour4ab45422014-12-10 17:00:20 -070028#include <limits.h>
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -060029#include <math.h>
Chia-I Wuec664fa2014-12-02 11:54:24 +080030#include <wand/MagickWand.h>
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -060031
32// Command-line options
33enum TOptions {
34 EOptionNone = 0x000,
35 EOptionIntermediate = 0x001,
36 EOptionSuppressInfolog = 0x002,
37 EOptionMemoryLeakMode = 0x004,
38 EOptionRelaxedErrors = 0x008,
39 EOptionGiveWarnings = 0x010,
40 EOptionLinkProgram = 0x020,
41 EOptionMultiThreaded = 0x040,
42 EOptionDumpConfig = 0x080,
43 EOptionDumpReflection = 0x100,
44 EOptionSuppressWarnings = 0x200,
45 EOptionDumpVersions = 0x400,
46 EOptionBil = 0x800,
47 EOptionDefaultDesktop = 0x1000,
48};
49
50#ifndef _WIN32
51
52#include <errno.h>
53
54int fopen_s(
55 FILE** pFile,
56 const char* filename,
57 const char* mode
58)
59{
60 if (!pFile || !filename || !mode) {
61 return EINVAL;
62 }
63
64 FILE* f = fopen(filename, mode);
65 if (! f) {
66 if (errno != 0) {
67 return errno;
68 } else {
69 return ENOENT;
70 }
71 }
72 *pFile = f;
73
74 return 0;
75}
76
77#endif
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -060078
Courtney Goeltzenleuchtera0f74c52014-10-08 08:46:51 -060079// Set up environment for GLSL compiler
80// Must be done once per process
81void TestEnvironment::SetUp()
82{
83 // Initialize GLSL to BIL compiler utility
84 glslang::InitializeProcess();
Chia-I Wub76e0fa2014-12-28 14:27:28 +080085
86 xgl_testing::set_error_callback(test_error_callback);
Courtney Goeltzenleuchtera0f74c52014-10-08 08:46:51 -060087}
88
89void TestEnvironment::TearDown()
90{
91 glslang::FinalizeProcess();
92}
93
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -060094XglTestFramework::XglTestFramework() :
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -060095 m_compile_options( 0 ),
96 m_num_shader_strings( 0 )
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -060097{
Courtney Goeltzenleuchtera0f74c52014-10-08 08:46:51 -060098
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -060099}
100
101XglTestFramework::~XglTestFramework()
102{
Courtney Goeltzenleuchtera0f74c52014-10-08 08:46:51 -0600103
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600104}
105
106// Define all the static elements
107bool XglTestFramework::m_show_images = false;
108bool XglTestFramework::m_save_images = false;
Tony Barbour247bf372014-10-30 14:29:04 -0600109bool XglTestFramework::m_compare_images = false;
Courtney Goeltzenleuchterc44e3ee2014-10-31 14:13:33 -0600110bool XglTestFramework::m_use_bil = true;
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600111int XglTestFramework::m_width = 0;
112int XglTestFramework::m_height = 0;
113int XglTestFramework::m_window = 0;
Courtney Goeltzenleuchter02d33c12014-10-08 14:26:40 -0600114bool XglTestFramework::m_glut_initialized = false;
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600115std::list<XglTestImageRecord> XglTestFramework::m_images;
116std::list<XglTestImageRecord>::iterator XglTestFramework::m_display_image;
117int m_display_image_idx = 0;
118
119void XglTestFramework::InitArgs(int *argc, char *argv[])
120{
121 int i, n;
122
123 for (i=0, n=0; i< *argc; i++) {
124 if (strncmp("--show-images", argv[i], 13) == 0) {
125 m_show_images = true;
126 continue;
127 }
128 if (strncmp("--save-images", argv[i], 13) == 0) {
129 m_save_images = true;
130 continue;
131 }
132
Courtney Goeltzenleuchterb666dc62014-10-09 09:13:56 -0600133 if (strncmp("--use-BIL", argv[i], 13) == 0) {
134 m_use_bil = true;
135 continue;
136 }
137
Courtney Goeltzenleuchterc44e3ee2014-10-31 14:13:33 -0600138 if (strncmp("--no-BIL", argv[i], 13) == 0) {
139 m_use_bil = false;
140 continue;
141 }
142
Tony Barbour247bf372014-10-30 14:29:04 -0600143 if (strncmp("--compare-images", argv[i], 16) == 0) {
144 m_compare_images = true;
145 continue;
146 }
147
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600148 /*
149 * Since the above "consume" inputs, update argv
150 * so that it contains the trimmed list of args for glutInit
151 */
Tony Barboura98d3932014-12-11 09:52:49 -0700152 if (strncmp("--help", argv[i], 6) == 0 || strncmp("-h", argv[i], 2) == 0) {
Courtney Goeltzenleuchter31144b72014-12-02 13:13:10 -0700153 printf("\nOther options:\n");
154 printf("\t--show-images\n"
155 "\t\tDisplay test images in viewer after tests complete.\n");
156 printf("\t--save-images\n"
157 "\t\tSave tests images as ppm files in current working directory.\n"
158 "\t\tUsed to generate golden images for compare-images.\n");
159 printf("\t--compare-images\n"
160 "\t\tCompare test images to 'golden' image in golden folder.\n"
Tony Barboura98d3932014-12-11 09:52:49 -0700161 "\t\tAlso saves the generated test image in current working\n"
162 "\t\t\tdirectory but only if the image is different from the golden\n"
163 "\t\tSetting RENDERTEST_GOLDEN_DIR environment variable can specify\n"
164 "\t\t\tdifferent directory for golden images\n"
Courtney Goeltzenleuchter31144b72014-12-02 13:13:10 -0700165 "\t\tSignal test failure if different.\n");
166 printf("\t--use-BIL\n"
167 "\t\tUse BIL code path (default).\n");
168 printf("\t--no-BIL\n"
169 "\t\tUse built-in GLSL compiler rather than BIL code path.\n");
Tony Barbour4ab45422014-12-10 17:00:20 -0700170 exit(0);
Courtney Goeltzenleuchter31144b72014-12-02 13:13:10 -0700171 }
172
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600173 argv[n] = argv[i];
174 n++;
175 }
176
177 if (m_show_images) {
178 glutInit(argc, argv);
179 }
180}
181
182void XglTestFramework::Reshape( int w, int h )
183{
184 if (!m_show_images) return; // Do nothing except save info if not enabled
185
186 // Resize window to be large enough to handle biggest image we've seen
187 // TODO: Probably need some sort of limits for the Window system.
188 if (w > m_width) {
189 m_width = w;
190 }
191 if (h > m_height) {
192 m_height = h;
193 }
194
195 glutReshapeWindow(m_width, m_height);
196
197 glViewport( 0, 0, m_width, m_height );
198 glMatrixMode( GL_PROJECTION );
199 glLoadIdentity();
200 glOrtho( 0.0, m_width, 0.0, m_height, 0.0, 2.0 );
201 glMatrixMode( GL_MODELVIEW );
202 glLoadIdentity();
203
204// glScissor(width/4, height/4, width/2, height/2);
205}
206
207void XglTestFramework::WritePPM( const char *basename, XglImage *image )
208{
209 string filename;
210 XGL_RESULT err;
Courtney Goeltzenleuchter02d33c12014-10-08 14:26:40 -0600211 int x, y;
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600212
213 filename.append(basename);
214 filename.append(".ppm");
215
216 const XGL_IMAGE_SUBRESOURCE sr = {
217 XGL_IMAGE_ASPECT_COLOR, 0, 0
218 };
219 XGL_SUBRESOURCE_LAYOUT sr_layout;
Chia-I Wu99ff89d2014-12-27 14:14:50 +0800220 size_t data_size = sizeof(sr_layout);
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600221
222 err = xglGetImageSubresourceInfo( image->image(), &sr,
223 XGL_INFO_TYPE_SUBRESOURCE_LAYOUT,
224 &data_size, &sr_layout);
225 ASSERT_XGL_SUCCESS( err );
226 ASSERT_EQ(data_size, sizeof(sr_layout));
227
228 const char *ptr;
229
230 err = xglMapMemory( image->memory(), 0, (XGL_VOID **) &ptr );
231 ASSERT_XGL_SUCCESS( err );
232
233 ptr += sr_layout.offset;
234
235 ofstream file (filename.c_str());
236 ASSERT_TRUE(file.is_open()) << "Unable to open file: " << filename;
237
238 file << "P6\n";
239 file << image->width() << "\n";
240 file << image->height() << "\n";
241 file << 255 << "\n";
242
243 for (y = 0; y < image->height(); y++) {
244 const char *row = ptr;
245
246 for (x = 0; x < image->width(); x++) {
247 file.write(row, 3);
248 row += 4;
249 }
250
251 ptr += sr_layout.rowPitch;
252 }
253
254 file.close();
255
256 err = xglUnmapMemory( image->memory() );
257 ASSERT_XGL_SUCCESS( err );
258}
259
260void XglTestFramework::InitGLUT(int w, int h)
261{
262
263 if (!m_show_images) return;
264
265 if (!m_glut_initialized) {
266 glutInitWindowSize(w, h);
267
268 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
269 m_window = glutCreateWindow(NULL);
270 m_glut_initialized = true;
271 }
272
273 Reshape(w, h);
274}
Tony Barbour247bf372014-10-30 14:29:04 -0600275void XglTestFramework::Compare(const char *basename, XglImage *image )
276{
277
278 MagickWand *magick_wand_1;
279 MagickWand *magick_wand_2;
280 MagickWand *compare_wand;
281 MagickBooleanType status;
Tony Barbour4ab45422014-12-10 17:00:20 -0700282 char testimage[256],golden[PATH_MAX+256],golddir[PATH_MAX] = "./golden";
Tony Barbour247bf372014-10-30 14:29:04 -0600283 double differenz;
284
Tony Barbour4ab45422014-12-10 17:00:20 -0700285 if (getenv("RENDERTEST_GOLDEN_DIR"))
286 {
287 strcpy(golddir,getenv("RENDERTEST_GOLDEN_DIR"));
288 }
289
Tony Barbour247bf372014-10-30 14:29:04 -0600290 MagickWandGenesis();
291 magick_wand_1=NewMagickWand();
292 sprintf(testimage,"%s.ppm",basename);
293 status=MagickReadImage(magick_wand_1,testimage);
294 ASSERT_TRUE(status) << "Unable to open file: " << testimage;
295
296
297 MagickWandGenesis();
298 magick_wand_2=NewMagickWand();
Tony Barbour4ab45422014-12-10 17:00:20 -0700299 sprintf(golden,"%s/%s.ppm",golddir,basename);
Tony Barbour247bf372014-10-30 14:29:04 -0600300 status=MagickReadImage(magick_wand_2,golden);
301 ASSERT_TRUE(status) << "Unable to open file: " << golden;
302
303 compare_wand = NewMagickWand();
304 compare_wand=MagickCompareImages(magick_wand_1,magick_wand_2, MeanAbsoluteErrorMetric, &differenz);
305 if (differenz != 0.0)
306 {
307 char difference[256];
308
309 sprintf(difference,"%s-diff.ppm",basename);
310 status = MagickWriteImage(compare_wand, difference);
311 ASSERT_TRUE(differenz == 0.0) << "Image comparison failed - diff file written";
312 }
313 DestroyMagickWand(compare_wand);
314
315 DestroyMagickWand(magick_wand_1);
316 DestroyMagickWand(magick_wand_2);
317 MagickWandTerminus();
Courtney Goeltzenleuchterfcda72d2014-12-05 15:41:02 -0700318
319 if (differenz == 0.0)
320 {
321 /*
322 * If test image and golden image match, we do not need to
323 * keep around the test image.
324 */
325 remove(testimage);
326 }
Tony Barbour247bf372014-10-30 14:29:04 -0600327}
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600328
329void XglTestFramework::Show(const char *comment, XglImage *image)
330{
331 XGL_RESULT err;
332
333 const XGL_IMAGE_SUBRESOURCE sr = {
334 XGL_IMAGE_ASPECT_COLOR, 0, 0
335 };
336 XGL_SUBRESOURCE_LAYOUT sr_layout;
Chia-I Wu99ff89d2014-12-27 14:14:50 +0800337 size_t data_size = sizeof(sr_layout);
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600338
339 if (!m_show_images) return;
340
341 InitGLUT(image->width(), image->height());
342
343 err = xglGetImageSubresourceInfo( image->image(), &sr, XGL_INFO_TYPE_SUBRESOURCE_LAYOUT,
344 &data_size, &sr_layout);
345 ASSERT_XGL_SUCCESS( err );
346 ASSERT_EQ(data_size, sizeof(sr_layout));
347
348 const char *ptr;
349
350 err = image->MapMemory( (XGL_VOID **) &ptr );
351 ASSERT_XGL_SUCCESS( err );
352
353 ptr += sr_layout.offset;
354
355 XglTestImageRecord record;
356 record.m_title.append(comment);
357 record.m_width = image->width();
358 record.m_height = image->height();
359 // TODO: Need to make this more robust to handle different image formats
360 record.m_data_size = image->width()*image->height()*4;
361 record.m_data = malloc(record.m_data_size);
362 memcpy(record.m_data, ptr, record.m_data_size);
363 m_images.push_back(record);
364 m_display_image = --m_images.end();
365
Courtney Goeltzenleuchter02d33c12014-10-08 14:26:40 -0600366// Display();
367 glutPostRedisplay();
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600368
369 err = image->UnmapMemory();
370 ASSERT_XGL_SUCCESS( err );
371}
372
Tony Barbour247bf372014-10-30 14:29:04 -0600373void XglTestFramework::RecordImage(XglImage *image, char *tag)
374{
375 const ::testing::TestInfo* const test_info =
376 ::testing::UnitTest::GetInstance()->current_test_info();
377 ostringstream filestream;
378 string filename;
379
380 filestream << test_info->name() << "-" << tag;
381 filename = filestream.str();
382 // ToDo - scrub string for bad characters
383
384 if (m_save_images || m_compare_images) {
385 WritePPM(filename.c_str(), image);
386 if (m_compare_images) {
387 Compare(filename.c_str(), image);
388 }
389 }
390
391 if (m_show_images) {
392 Show(test_info->name(), image);
393 }
394}
395
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600396void XglTestFramework::RecordImage(XglImage *image)
397{
398 const ::testing::TestInfo* const test_info =
399 ::testing::UnitTest::GetInstance()->current_test_info();
Tony Barbour247bf372014-10-30 14:29:04 -0600400 ostringstream filestream;
401 string filename;
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600402
Tony Barbour247bf372014-10-30 14:29:04 -0600403 m_width = 40;
404
405 if (strcmp(test_info->name(), m_testName.c_str())) {
406 filestream << test_info->name();
407 m_testName.assign(test_info->name());
Tony Barboura0e2ee82014-11-18 17:02:36 -0700408 m_frameNum = 2;
409 filename = filestream.str();
Tony Barbour247bf372014-10-30 14:29:04 -0600410 }
411 else {
412 filestream << test_info->name() << "-" << m_frameNum;
413 m_frameNum++;
Tony Barboura0e2ee82014-11-18 17:02:36 -0700414 filename = filestream.str();
Tony Barbour247bf372014-10-30 14:29:04 -0600415 }
416
417
418 // ToDo - scrub string for bad characters
419
420 if (m_save_images || m_compare_images) {
421 WritePPM(filename.c_str(), image);
422 if (m_compare_images) {
423 Compare(filename.c_str(), image);
424 }
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600425 }
426
427 if (m_show_images) {
Courtney Goeltzenleuchter02d33c12014-10-08 14:26:40 -0600428 Show(test_info->name(), image);
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600429 }
430}
431
432void XglTestFramework::Display()
433{
434 glutSetWindowTitle(m_display_image->m_title.c_str());
435
436 glClearColor(0, 0, 0, 0);
437 glClear(GL_COLOR_BUFFER_BIT);
438 glRasterPos3f(0, 0, 0);
439 glBitmap(0, 0, 0, 0, 0, 0, NULL);
440 glDrawPixels(m_display_image->m_width, m_display_image->m_height,
441 GL_RGBA, GL_UNSIGNED_BYTE, m_display_image->m_data);
442
443 glutSwapBuffers();
444}
445
446void XglTestFramework::Key( unsigned char key, int x, int y )
447{
448 (void) x;
449 (void) y;
450 switch (key) {
451 case 27:
452 glutDestroyWindow(m_window);
453 exit(0);
454 break;
455 }
456 glutPostRedisplay();
457}
458
459void XglTestFramework::SpecialKey( int key, int x, int y )
460{
461 (void) x;
462 (void) y;
463 switch (key) {
464 case GLUT_KEY_UP:
465 case GLUT_KEY_RIGHT:
466 ++m_display_image;
467 if (m_display_image == m_images.end()) {
468 m_display_image = m_images.begin();
469 }
470 break;
471 case GLUT_KEY_DOWN:
472 case GLUT_KEY_LEFT:
473 if (m_display_image == m_images.begin()) {
474 m_display_image = --m_images.end();
475 } else {
476 --m_display_image;
477 }
478
479 break;
480 }
481 glutPostRedisplay();
482}
483
484void XglTestFramework::Finish()
485{
486 if (m_images.size() == 0) return;
487
488 glutReshapeFunc( Reshape );
489 glutKeyboardFunc( Key );
490 glutSpecialFunc( SpecialKey );
491 glutDisplayFunc( Display );
Courtney Goeltzenleuchter02d33c12014-10-08 14:26:40 -0600492 glutIdleFunc(NULL);
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600493
494 glutMainLoop();
495}
496
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -0600497//
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -0600498// These are the default resources for TBuiltInResources, used for both
499// - parsing this string for the case where the user didn't supply one
500// - dumping out a template for user construction of a config file
501//
502static const char* DefaultConfig =
503 "MaxLights 32\n"
504 "MaxClipPlanes 6\n"
505 "MaxTextureUnits 32\n"
506 "MaxTextureCoords 32\n"
507 "MaxVertexAttribs 64\n"
508 "MaxVertexUniformComponents 4096\n"
509 "MaxVaryingFloats 64\n"
510 "MaxVertexTextureImageUnits 32\n"
511 "MaxCombinedTextureImageUnits 80\n"
512 "MaxTextureImageUnits 32\n"
513 "MaxFragmentUniformComponents 4096\n"
514 "MaxDrawBuffers 32\n"
515 "MaxVertexUniformVectors 128\n"
516 "MaxVaryingVectors 8\n"
517 "MaxFragmentUniformVectors 16\n"
518 "MaxVertexOutputVectors 16\n"
519 "MaxFragmentInputVectors 15\n"
520 "MinProgramTexelOffset -8\n"
521 "MaxProgramTexelOffset 7\n"
522 "MaxClipDistances 8\n"
523 "MaxComputeWorkGroupCountX 65535\n"
524 "MaxComputeWorkGroupCountY 65535\n"
525 "MaxComputeWorkGroupCountZ 65535\n"
526 "MaxComputeWorkGroupSizeX 1024\n"
527 "MaxComputeWorkGroupSizeY 1024\n"
528 "MaxComputeWorkGroupSizeZ 64\n"
529 "MaxComputeUniformComponents 1024\n"
530 "MaxComputeTextureImageUnits 16\n"
531 "MaxComputeImageUniforms 8\n"
532 "MaxComputeAtomicCounters 8\n"
533 "MaxComputeAtomicCounterBuffers 1\n"
534 "MaxVaryingComponents 60\n"
535 "MaxVertexOutputComponents 64\n"
536 "MaxGeometryInputComponents 64\n"
537 "MaxGeometryOutputComponents 128\n"
538 "MaxFragmentInputComponents 128\n"
539 "MaxImageUnits 8\n"
540 "MaxCombinedImageUnitsAndFragmentOutputs 8\n"
541 "MaxCombinedShaderOutputResources 8\n"
542 "MaxImageSamples 0\n"
543 "MaxVertexImageUniforms 0\n"
544 "MaxTessControlImageUniforms 0\n"
545 "MaxTessEvaluationImageUniforms 0\n"
546 "MaxGeometryImageUniforms 0\n"
547 "MaxFragmentImageUniforms 8\n"
548 "MaxCombinedImageUniforms 8\n"
549 "MaxGeometryTextureImageUnits 16\n"
550 "MaxGeometryOutputVertices 256\n"
551 "MaxGeometryTotalOutputComponents 1024\n"
552 "MaxGeometryUniformComponents 1024\n"
553 "MaxGeometryVaryingComponents 64\n"
554 "MaxTessControlInputComponents 128\n"
555 "MaxTessControlOutputComponents 128\n"
556 "MaxTessControlTextureImageUnits 16\n"
557 "MaxTessControlUniformComponents 1024\n"
558 "MaxTessControlTotalOutputComponents 4096\n"
559 "MaxTessEvaluationInputComponents 128\n"
560 "MaxTessEvaluationOutputComponents 128\n"
561 "MaxTessEvaluationTextureImageUnits 16\n"
562 "MaxTessEvaluationUniformComponents 1024\n"
563 "MaxTessPatchComponents 120\n"
564 "MaxPatchVertices 32\n"
565 "MaxTessGenLevel 64\n"
566 "MaxViewports 16\n"
567 "MaxVertexAtomicCounters 0\n"
568 "MaxTessControlAtomicCounters 0\n"
569 "MaxTessEvaluationAtomicCounters 0\n"
570 "MaxGeometryAtomicCounters 0\n"
571 "MaxFragmentAtomicCounters 8\n"
572 "MaxCombinedAtomicCounters 8\n"
573 "MaxAtomicCounterBindings 1\n"
574 "MaxVertexAtomicCounterBuffers 0\n"
575 "MaxTessControlAtomicCounterBuffers 0\n"
576 "MaxTessEvaluationAtomicCounterBuffers 0\n"
577 "MaxGeometryAtomicCounterBuffers 0\n"
578 "MaxFragmentAtomicCounterBuffers 1\n"
579 "MaxCombinedAtomicCounterBuffers 1\n"
580 "MaxAtomicCounterBufferSize 16384\n"
581 "MaxTransformFeedbackBuffers 4\n"
582 "MaxTransformFeedbackInterleavedComponents 64\n"
583 "MaxCullDistances 8\n"
584 "MaxCombinedClipAndCullDistances 8\n"
585 "MaxSamples 4\n"
586
587 "nonInductiveForLoops 1\n"
588 "whileLoops 1\n"
589 "doWhileLoops 1\n"
590 "generalUniformIndexing 1\n"
591 "generalAttributeMatrixVectorIndexing 1\n"
592 "generalVaryingIndexing 1\n"
593 "generalSamplerIndexing 1\n"
594 "generalVariableIndexing 1\n"
595 "generalConstantMatrixVectorIndexing 1\n"
596 ;
597
598//
599// *.conf => this is a config file that can set limits/resources
600//
601bool XglTestFramework::SetConfigFile(const std::string& name)
602{
603 if (name.size() < 5)
604 return false;
605
606 if (name.compare(name.size() - 5, 5, ".conf") == 0) {
607 ConfigFile = name;
608 return true;
609 }
610
611 return false;
612}
613
614//
615// Parse either a .conf file provided by the user or the default string above.
616//
617void XglTestFramework::ProcessConfigFile()
618{
619 char** configStrings = 0;
620 char* config = 0;
621 if (ConfigFile.size() > 0) {
622 configStrings = ReadFileData(ConfigFile.c_str());
623 if (configStrings)
624 config = *configStrings;
625 else {
626 printf("Error opening configuration file; will instead use the default configuration\n");
627 }
628 }
629
630 if (config == 0) {
631 config = new char[strlen(DefaultConfig) + 1];
632 strcpy(config, DefaultConfig);
633 }
634
635 const char* delims = " \t\n\r";
636 const char* token = strtok(config, delims);
637 while (token) {
638 const char* valueStr = strtok(0, delims);
639 if (valueStr == 0 || ! (valueStr[0] == '-' || (valueStr[0] >= '0' && valueStr[0] <= '9'))) {
640 printf("Error: '%s' bad .conf file. Each name must be followed by one number.\n", valueStr ? valueStr : "");
641 return;
642 }
643 int value = atoi(valueStr);
644
645 if (strcmp(token, "MaxLights") == 0)
646 Resources.maxLights = value;
647 else if (strcmp(token, "MaxClipPlanes") == 0)
648 Resources.maxClipPlanes = value;
649 else if (strcmp(token, "MaxTextureUnits") == 0)
650 Resources.maxTextureUnits = value;
651 else if (strcmp(token, "MaxTextureCoords") == 0)
652 Resources.maxTextureCoords = value;
653 else if (strcmp(token, "MaxVertexAttribs") == 0)
654 Resources.maxVertexAttribs = value;
655 else if (strcmp(token, "MaxVertexUniformComponents") == 0)
656 Resources.maxVertexUniformComponents = value;
657 else if (strcmp(token, "MaxVaryingFloats") == 0)
658 Resources.maxVaryingFloats = value;
659 else if (strcmp(token, "MaxVertexTextureImageUnits") == 0)
660 Resources.maxVertexTextureImageUnits = value;
661 else if (strcmp(token, "MaxCombinedTextureImageUnits") == 0)
662 Resources.maxCombinedTextureImageUnits = value;
663 else if (strcmp(token, "MaxTextureImageUnits") == 0)
664 Resources.maxTextureImageUnits = value;
665 else if (strcmp(token, "MaxFragmentUniformComponents") == 0)
666 Resources.maxFragmentUniformComponents = value;
667 else if (strcmp(token, "MaxDrawBuffers") == 0)
668 Resources.maxDrawBuffers = value;
669 else if (strcmp(token, "MaxVertexUniformVectors") == 0)
670 Resources.maxVertexUniformVectors = value;
671 else if (strcmp(token, "MaxVaryingVectors") == 0)
672 Resources.maxVaryingVectors = value;
673 else if (strcmp(token, "MaxFragmentUniformVectors") == 0)
674 Resources.maxFragmentUniformVectors = value;
675 else if (strcmp(token, "MaxVertexOutputVectors") == 0)
676 Resources.maxVertexOutputVectors = value;
677 else if (strcmp(token, "MaxFragmentInputVectors") == 0)
678 Resources.maxFragmentInputVectors = value;
679 else if (strcmp(token, "MinProgramTexelOffset") == 0)
680 Resources.minProgramTexelOffset = value;
681 else if (strcmp(token, "MaxProgramTexelOffset") == 0)
682 Resources.maxProgramTexelOffset = value;
683 else if (strcmp(token, "MaxClipDistances") == 0)
684 Resources.maxClipDistances = value;
685 else if (strcmp(token, "MaxComputeWorkGroupCountX") == 0)
686 Resources.maxComputeWorkGroupCountX = value;
687 else if (strcmp(token, "MaxComputeWorkGroupCountY") == 0)
688 Resources.maxComputeWorkGroupCountY = value;
689 else if (strcmp(token, "MaxComputeWorkGroupCountZ") == 0)
690 Resources.maxComputeWorkGroupCountZ = value;
691 else if (strcmp(token, "MaxComputeWorkGroupSizeX") == 0)
692 Resources.maxComputeWorkGroupSizeX = value;
693 else if (strcmp(token, "MaxComputeWorkGroupSizeY") == 0)
694 Resources.maxComputeWorkGroupSizeY = value;
695 else if (strcmp(token, "MaxComputeWorkGroupSizeZ") == 0)
696 Resources.maxComputeWorkGroupSizeZ = value;
697 else if (strcmp(token, "MaxComputeUniformComponents") == 0)
698 Resources.maxComputeUniformComponents = value;
699 else if (strcmp(token, "MaxComputeTextureImageUnits") == 0)
700 Resources.maxComputeTextureImageUnits = value;
701 else if (strcmp(token, "MaxComputeImageUniforms") == 0)
702 Resources.maxComputeImageUniforms = value;
703 else if (strcmp(token, "MaxComputeAtomicCounters") == 0)
704 Resources.maxComputeAtomicCounters = value;
705 else if (strcmp(token, "MaxComputeAtomicCounterBuffers") == 0)
706 Resources.maxComputeAtomicCounterBuffers = value;
707 else if (strcmp(token, "MaxVaryingComponents") == 0)
708 Resources.maxVaryingComponents = value;
709 else if (strcmp(token, "MaxVertexOutputComponents") == 0)
710 Resources.maxVertexOutputComponents = value;
711 else if (strcmp(token, "MaxGeometryInputComponents") == 0)
712 Resources.maxGeometryInputComponents = value;
713 else if (strcmp(token, "MaxGeometryOutputComponents") == 0)
714 Resources.maxGeometryOutputComponents = value;
715 else if (strcmp(token, "MaxFragmentInputComponents") == 0)
716 Resources.maxFragmentInputComponents = value;
717 else if (strcmp(token, "MaxImageUnits") == 0)
718 Resources.maxImageUnits = value;
719 else if (strcmp(token, "MaxCombinedImageUnitsAndFragmentOutputs") == 0)
720 Resources.maxCombinedImageUnitsAndFragmentOutputs = value;
721 else if (strcmp(token, "MaxCombinedShaderOutputResources") == 0)
722 Resources.maxCombinedShaderOutputResources = value;
723 else if (strcmp(token, "MaxImageSamples") == 0)
724 Resources.maxImageSamples = value;
725 else if (strcmp(token, "MaxVertexImageUniforms") == 0)
726 Resources.maxVertexImageUniforms = value;
727 else if (strcmp(token, "MaxTessControlImageUniforms") == 0)
728 Resources.maxTessControlImageUniforms = value;
729 else if (strcmp(token, "MaxTessEvaluationImageUniforms") == 0)
730 Resources.maxTessEvaluationImageUniforms = value;
731 else if (strcmp(token, "MaxGeometryImageUniforms") == 0)
732 Resources.maxGeometryImageUniforms = value;
733 else if (strcmp(token, "MaxFragmentImageUniforms") == 0)
734 Resources.maxFragmentImageUniforms = value;
735 else if (strcmp(token, "MaxCombinedImageUniforms") == 0)
736 Resources.maxCombinedImageUniforms = value;
737 else if (strcmp(token, "MaxGeometryTextureImageUnits") == 0)
738 Resources.maxGeometryTextureImageUnits = value;
739 else if (strcmp(token, "MaxGeometryOutputVertices") == 0)
740 Resources.maxGeometryOutputVertices = value;
741 else if (strcmp(token, "MaxGeometryTotalOutputComponents") == 0)
742 Resources.maxGeometryTotalOutputComponents = value;
743 else if (strcmp(token, "MaxGeometryUniformComponents") == 0)
744 Resources.maxGeometryUniformComponents = value;
745 else if (strcmp(token, "MaxGeometryVaryingComponents") == 0)
746 Resources.maxGeometryVaryingComponents = value;
747 else if (strcmp(token, "MaxTessControlInputComponents") == 0)
748 Resources.maxTessControlInputComponents = value;
749 else if (strcmp(token, "MaxTessControlOutputComponents") == 0)
750 Resources.maxTessControlOutputComponents = value;
751 else if (strcmp(token, "MaxTessControlTextureImageUnits") == 0)
752 Resources.maxTessControlTextureImageUnits = value;
753 else if (strcmp(token, "MaxTessControlUniformComponents") == 0)
754 Resources.maxTessControlUniformComponents = value;
755 else if (strcmp(token, "MaxTessControlTotalOutputComponents") == 0)
756 Resources.maxTessControlTotalOutputComponents = value;
757 else if (strcmp(token, "MaxTessEvaluationInputComponents") == 0)
758 Resources.maxTessEvaluationInputComponents = value;
759 else if (strcmp(token, "MaxTessEvaluationOutputComponents") == 0)
760 Resources.maxTessEvaluationOutputComponents = value;
761 else if (strcmp(token, "MaxTessEvaluationTextureImageUnits") == 0)
762 Resources.maxTessEvaluationTextureImageUnits = value;
763 else if (strcmp(token, "MaxTessEvaluationUniformComponents") == 0)
764 Resources.maxTessEvaluationUniformComponents = value;
765 else if (strcmp(token, "MaxTessPatchComponents") == 0)
766 Resources.maxTessPatchComponents = value;
767 else if (strcmp(token, "MaxPatchVertices") == 0)
768 Resources.maxPatchVertices = value;
769 else if (strcmp(token, "MaxTessGenLevel") == 0)
770 Resources.maxTessGenLevel = value;
771 else if (strcmp(token, "MaxViewports") == 0)
772 Resources.maxViewports = value;
773 else if (strcmp(token, "MaxVertexAtomicCounters") == 0)
774 Resources.maxVertexAtomicCounters = value;
775 else if (strcmp(token, "MaxTessControlAtomicCounters") == 0)
776 Resources.maxTessControlAtomicCounters = value;
777 else if (strcmp(token, "MaxTessEvaluationAtomicCounters") == 0)
778 Resources.maxTessEvaluationAtomicCounters = value;
779 else if (strcmp(token, "MaxGeometryAtomicCounters") == 0)
780 Resources.maxGeometryAtomicCounters = value;
781 else if (strcmp(token, "MaxFragmentAtomicCounters") == 0)
782 Resources.maxFragmentAtomicCounters = value;
783 else if (strcmp(token, "MaxCombinedAtomicCounters") == 0)
784 Resources.maxCombinedAtomicCounters = value;
785 else if (strcmp(token, "MaxAtomicCounterBindings") == 0)
786 Resources.maxAtomicCounterBindings = value;
787 else if (strcmp(token, "MaxVertexAtomicCounterBuffers") == 0)
788 Resources.maxVertexAtomicCounterBuffers = value;
789 else if (strcmp(token, "MaxTessControlAtomicCounterBuffers") == 0)
790 Resources.maxTessControlAtomicCounterBuffers = value;
791 else if (strcmp(token, "MaxTessEvaluationAtomicCounterBuffers") == 0)
792 Resources.maxTessEvaluationAtomicCounterBuffers = value;
793 else if (strcmp(token, "MaxGeometryAtomicCounterBuffers") == 0)
794 Resources.maxGeometryAtomicCounterBuffers = value;
795 else if (strcmp(token, "MaxFragmentAtomicCounterBuffers") == 0)
796 Resources.maxFragmentAtomicCounterBuffers = value;
797 else if (strcmp(token, "MaxCombinedAtomicCounterBuffers") == 0)
798 Resources.maxCombinedAtomicCounterBuffers = value;
799 else if (strcmp(token, "MaxAtomicCounterBufferSize") == 0)
800 Resources.maxAtomicCounterBufferSize = value;
801 else if (strcmp(token, "MaxTransformFeedbackBuffers") == 0)
802 Resources.maxTransformFeedbackBuffers = value;
803 else if (strcmp(token, "MaxTransformFeedbackInterleavedComponents") == 0)
804 Resources.maxTransformFeedbackInterleavedComponents = value;
805 else if (strcmp(token, "MaxCullDistances") == 0)
806 Resources.maxCullDistances = value;
807 else if (strcmp(token, "MaxCombinedClipAndCullDistances") == 0)
808 Resources.maxCombinedClipAndCullDistances = value;
809 else if (strcmp(token, "MaxSamples") == 0)
810 Resources.maxSamples = value;
811
812 else if (strcmp(token, "nonInductiveForLoops") == 0)
813 Resources.limits.nonInductiveForLoops = (value != 0);
814 else if (strcmp(token, "whileLoops") == 0)
815 Resources.limits.whileLoops = (value != 0);
816 else if (strcmp(token, "doWhileLoops") == 0)
817 Resources.limits.doWhileLoops = (value != 0);
818 else if (strcmp(token, "generalUniformIndexing") == 0)
819 Resources.limits.generalUniformIndexing = (value != 0);
820 else if (strcmp(token, "generalAttributeMatrixVectorIndexing") == 0)
821 Resources.limits.generalAttributeMatrixVectorIndexing = (value != 0);
822 else if (strcmp(token, "generalVaryingIndexing") == 0)
823 Resources.limits.generalVaryingIndexing = (value != 0);
824 else if (strcmp(token, "generalSamplerIndexing") == 0)
825 Resources.limits.generalSamplerIndexing = (value != 0);
826 else if (strcmp(token, "generalVariableIndexing") == 0)
827 Resources.limits.generalVariableIndexing = (value != 0);
828 else if (strcmp(token, "generalConstantMatrixVectorIndexing") == 0)
829 Resources.limits.generalConstantMatrixVectorIndexing = (value != 0);
830 else
831 printf("Warning: unrecognized limit (%s) in configuration file.\n", token);
832
833 token = strtok(0, delims);
834 }
835 if (configStrings)
836 FreeFileData(configStrings);
837}
838
839void XglTestFramework::SetMessageOptions(EShMessages& messages)
840{
841 if (m_compile_options & EOptionRelaxedErrors)
842 messages = (EShMessages)(messages | EShMsgRelaxedErrors);
843 if (m_compile_options & EOptionIntermediate)
844 messages = (EShMessages)(messages | EShMsgAST);
845 if (m_compile_options & EOptionSuppressWarnings)
846 messages = (EShMessages)(messages | EShMsgSuppressWarnings);
847}
848
849//
850// Malloc a string of sufficient size and read a string into it.
851//
852char** XglTestFramework::ReadFileData(const char* fileName)
853{
854 FILE *in;
855 #if defined(_WIN32) && defined(__GNUC__)
856 in = fopen(fileName, "r");
857 int errorCode = in ? 0 : 1;
858 #else
859 int errorCode = fopen_s(&in, fileName, "r");
860 #endif
861
862 char *fdata;
863 int count = 0;
864 const int maxSourceStrings = 5;
865 char** return_data = (char**)malloc(sizeof(char *) * (maxSourceStrings+1));
866
867 if (errorCode) {
868 printf("Error: unable to open input file: %s\n", fileName);
869 return 0;
870 }
871
872 while (fgetc(in) != EOF)
873 count++;
874
875 fseek(in, 0, SEEK_SET);
876
877 if (!(fdata = (char*)malloc(count+2))) {
878 printf("Error allocating memory\n");
879 return 0;
880 }
881 if (fread(fdata,1,count, in)!=count) {
882 printf("Error reading input file: %s\n", fileName);
883 return 0;
884 }
885 fdata[count] = '\0';
886 fclose(in);
887 if (count == 0) {
888 return_data[0]=(char*)malloc(count+2);
889 return_data[0][0]='\0';
890 m_num_shader_strings = 0;
891 return return_data;
892 } else
893 m_num_shader_strings = 1;
894
895 int len = (int)(ceil)((float)count/(float)m_num_shader_strings);
896 int ptr_len=0,i=0;
897 while(count>0){
898 return_data[i]=(char*)malloc(len+2);
899 memcpy(return_data[i],fdata+ptr_len,len);
900 return_data[i][len]='\0';
901 count-=(len);
902 ptr_len+=(len);
903 if(count<len){
904 if(count==0){
905 m_num_shader_strings=(i+1);
906 break;
907 }
908 len = count;
909 }
910 ++i;
911 }
912 return return_data;
913}
914
915void XglTestFramework::FreeFileData(char** data)
916{
917 for(int i=0;i<m_num_shader_strings;i++)
918 free(data[i]);
919}
920
921//
922// Deduce the language from the filename. Files must end in one of the
923// following extensions:
924//
925// .vert = vertex
926// .tesc = tessellation control
927// .tese = tessellation evaluation
928// .geom = geometry
929// .frag = fragment
930// .comp = compute
931//
932EShLanguage XglTestFramework::FindLanguage(const std::string& name)
933{
934 size_t ext = name.rfind('.');
935 if (ext == std::string::npos) {
936 return EShLangVertex;
937 }
938
939 std::string suffix = name.substr(ext + 1, std::string::npos);
940 if (suffix == "vert")
941 return EShLangVertex;
942 else if (suffix == "tesc")
943 return EShLangTessControl;
944 else if (suffix == "tese")
945 return EShLangTessEvaluation;
946 else if (suffix == "geom")
947 return EShLangGeometry;
948 else if (suffix == "frag")
949 return EShLangFragment;
950 else if (suffix == "comp")
951 return EShLangCompute;
952
953 return EShLangVertex;
954}
955
956//
957// Convert XGL shader type to compiler's
958//
959EShLanguage XglTestFramework::FindLanguage(const XGL_PIPELINE_SHADER_STAGE shader_type)
960{
961 switch (shader_type) {
962 case XGL_SHADER_STAGE_VERTEX:
963 return EShLangVertex;
964
965 case XGL_SHADER_STAGE_TESS_CONTROL:
966 return EShLangTessControl;
967
968 case XGL_SHADER_STAGE_TESS_EVALUATION:
969 return EShLangTessEvaluation;
970
971 case XGL_SHADER_STAGE_GEOMETRY:
972 return EShLangGeometry;
973
974 case XGL_SHADER_STAGE_FRAGMENT:
975 return EShLangFragment;
976
977 case XGL_SHADER_STAGE_COMPUTE:
978 return EShLangCompute;
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -0600979
Chia-I Wub4c2aa42014-12-15 23:50:11 +0800980 default:
981 return EShLangVertex;
982 }
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -0600983}
984
985
986//
987// Compile a given string containing GLSL into BIL for use by XGL
988// Return value of false means an error was encountered.
989//
990bool XglTestFramework::GLSLtoBIL(const XGL_PIPELINE_SHADER_STAGE shader_type,
991 const char *pshader,
992 std::vector<unsigned int> &bil)
993{
994 glslang::TProgram& program = *new glslang::TProgram;
995 const char *shaderStrings[1];
996
997 // TODO: Do we want to load a special config file depending on the
998 // shader source? Optional name maybe?
999 // SetConfigFile(fileName);
1000
1001 ProcessConfigFile();
1002
1003 EShMessages messages = EShMsgDefault;
1004 SetMessageOptions(messages);
1005
1006 EShLanguage stage = FindLanguage(shader_type);
1007 glslang::TShader* shader = new glslang::TShader(stage);
1008
1009 shaderStrings[0] = pshader;
1010 shader->setStrings(shaderStrings, 1);
1011
1012 if (! shader->parse(&Resources, (m_compile_options & EOptionDefaultDesktop) ? 110 : 100, false, messages)) {
1013
Cody Northrop195d6622014-11-03 12:54:37 -07001014 if (! (m_compile_options & EOptionSuppressInfolog)) {
1015 puts(shader->getInfoLog());
1016 puts(shader->getInfoDebugLog());
1017 }
1018
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -06001019 return false; // something didn't work
1020 }
1021
1022 program.addShader(shader);
1023
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -06001024
1025 //
1026 // Program-level processing...
1027 //
1028
Cody Northrop195d6622014-11-03 12:54:37 -07001029 if (! program.link(messages)) {
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -06001030
Cody Northrop195d6622014-11-03 12:54:37 -07001031 if (! (m_compile_options & EOptionSuppressInfolog)) {
1032 puts(shader->getInfoLog());
1033 puts(shader->getInfoDebugLog());
1034 }
1035
1036 return false;
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -06001037 }
1038
1039 if (m_compile_options & EOptionDumpReflection) {
1040 program.buildReflection();
1041 program.dumpReflection();
1042 }
1043
1044 glslang::GlslangToBil(*program.getIntermediate(stage), bil);
1045
1046 return true;
1047}
1048
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -06001049
1050
1051XglTestImageRecord::XglTestImageRecord() : // Constructor
1052 m_width( 0 ),
1053 m_height( 0 ),
Chia-I Wu837f9952014-12-15 23:29:34 +08001054 m_data( NULL ),
1055 m_data_size( 0 )
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -06001056{
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -06001057}
1058
1059XglTestImageRecord::~XglTestImageRecord()
1060{
1061
1062}
1063
1064XglTestImageRecord::XglTestImageRecord(const XglTestImageRecord &copyin) // Copy constructor to handle pass by value.
1065{
1066 m_title = copyin.m_title;
1067 m_width = copyin.m_width;
1068 m_height = copyin.m_height;
1069 m_data_size = copyin.m_data_size;
1070 m_data = copyin.m_data; // TODO: Do we need to copy the data or is pointer okay?
1071}
1072
1073ostream &operator<<(ostream &output, const XglTestImageRecord &XglTestImageRecord)
1074{
1075 output << XglTestImageRecord.m_title << " (" << XglTestImageRecord.m_width <<
1076 "," << XglTestImageRecord.m_height << ")" << endl;
1077 return output;
1078}
1079
1080XglTestImageRecord& XglTestImageRecord::operator=(const XglTestImageRecord &rhs)
1081{
1082 m_title = rhs.m_title;
1083 m_width = rhs.m_width;
1084 m_height = rhs.m_height;
1085 m_data_size = rhs.m_data_size;
1086 m_data = rhs.m_data;
1087 return *this;
1088}
1089
1090int XglTestImageRecord::operator==(const XglTestImageRecord &rhs) const
1091{
1092 if( this->m_data != rhs.m_data) return 0;
1093 return 1;
1094}
1095
1096// This function is required for built-in STL list functions like sort
1097int XglTestImageRecord::operator<(const XglTestImageRecord &rhs) const
1098{
1099 if( this->m_data_size < rhs.m_data_size ) return 1;
1100 return 0;
1101}
1102