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