blob: 2903aff3fc9a9aa453498d6405084c0a7efc8919 [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>
Tony Barbour247bf372014-10-30 14:29:04 -060028#include <ImageMagick/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 */
148 argv[n] = argv[i];
149 n++;
150 }
151
152 if (m_show_images) {
153 glutInit(argc, argv);
154 }
155}
156
157void XglTestFramework::Reshape( int w, int h )
158{
159 if (!m_show_images) return; // Do nothing except save info if not enabled
160
161 // Resize window to be large enough to handle biggest image we've seen
162 // TODO: Probably need some sort of limits for the Window system.
163 if (w > m_width) {
164 m_width = w;
165 }
166 if (h > m_height) {
167 m_height = h;
168 }
169
170 glutReshapeWindow(m_width, m_height);
171
172 glViewport( 0, 0, m_width, m_height );
173 glMatrixMode( GL_PROJECTION );
174 glLoadIdentity();
175 glOrtho( 0.0, m_width, 0.0, m_height, 0.0, 2.0 );
176 glMatrixMode( GL_MODELVIEW );
177 glLoadIdentity();
178
179// glScissor(width/4, height/4, width/2, height/2);
180}
181
182void XglTestFramework::WritePPM( const char *basename, XglImage *image )
183{
184 string filename;
185 XGL_RESULT err;
Courtney Goeltzenleuchter02d33c12014-10-08 14:26:40 -0600186 int x, y;
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600187
188 filename.append(basename);
189 filename.append(".ppm");
190
191 const XGL_IMAGE_SUBRESOURCE sr = {
192 XGL_IMAGE_ASPECT_COLOR, 0, 0
193 };
194 XGL_SUBRESOURCE_LAYOUT sr_layout;
Jon Ashburne494a1a2014-09-25 14:36:58 -0600195 XGL_UINT data_size = sizeof(sr_layout);
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600196
197 err = xglGetImageSubresourceInfo( image->image(), &sr,
198 XGL_INFO_TYPE_SUBRESOURCE_LAYOUT,
199 &data_size, &sr_layout);
200 ASSERT_XGL_SUCCESS( err );
201 ASSERT_EQ(data_size, sizeof(sr_layout));
202
203 const char *ptr;
204
205 err = xglMapMemory( image->memory(), 0, (XGL_VOID **) &ptr );
206 ASSERT_XGL_SUCCESS( err );
207
208 ptr += sr_layout.offset;
209
210 ofstream file (filename.c_str());
211 ASSERT_TRUE(file.is_open()) << "Unable to open file: " << filename;
212
213 file << "P6\n";
214 file << image->width() << "\n";
215 file << image->height() << "\n";
216 file << 255 << "\n";
217
218 for (y = 0; y < image->height(); y++) {
219 const char *row = ptr;
220
221 for (x = 0; x < image->width(); x++) {
222 file.write(row, 3);
223 row += 4;
224 }
225
226 ptr += sr_layout.rowPitch;
227 }
228
229 file.close();
230
231 err = xglUnmapMemory( image->memory() );
232 ASSERT_XGL_SUCCESS( err );
233}
234
235void XglTestFramework::InitGLUT(int w, int h)
236{
237
238 if (!m_show_images) return;
239
240 if (!m_glut_initialized) {
241 glutInitWindowSize(w, h);
242
243 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
244 m_window = glutCreateWindow(NULL);
245 m_glut_initialized = true;
246 }
247
248 Reshape(w, h);
249}
Tony Barbour247bf372014-10-30 14:29:04 -0600250void XglTestFramework::Compare(const char *basename, XglImage *image )
251{
252
253 MagickWand *magick_wand_1;
254 MagickWand *magick_wand_2;
255 MagickWand *compare_wand;
256 MagickBooleanType status;
257 char testimage[256],golden[256];
258 double differenz;
259
260 MagickWandGenesis();
261 magick_wand_1=NewMagickWand();
262 sprintf(testimage,"%s.ppm",basename);
263 status=MagickReadImage(magick_wand_1,testimage);
264 ASSERT_TRUE(status) << "Unable to open file: " << testimage;
265
266
267 MagickWandGenesis();
268 magick_wand_2=NewMagickWand();
269 sprintf(golden,"golden/%s.ppm",basename);
270 status=MagickReadImage(magick_wand_2,golden);
271 ASSERT_TRUE(status) << "Unable to open file: " << golden;
272
273 compare_wand = NewMagickWand();
274 compare_wand=MagickCompareImages(magick_wand_1,magick_wand_2, MeanAbsoluteErrorMetric, &differenz);
275 if (differenz != 0.0)
276 {
277 char difference[256];
278
279 sprintf(difference,"%s-diff.ppm",basename);
280 status = MagickWriteImage(compare_wand, difference);
281 ASSERT_TRUE(differenz == 0.0) << "Image comparison failed - diff file written";
282 }
283 DestroyMagickWand(compare_wand);
284
285 DestroyMagickWand(magick_wand_1);
286 DestroyMagickWand(magick_wand_2);
287 MagickWandTerminus();
288}
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600289
290void XglTestFramework::Show(const char *comment, XglImage *image)
291{
292 XGL_RESULT err;
293
294 const XGL_IMAGE_SUBRESOURCE sr = {
295 XGL_IMAGE_ASPECT_COLOR, 0, 0
296 };
297 XGL_SUBRESOURCE_LAYOUT sr_layout;
Jon Ashburne494a1a2014-09-25 14:36:58 -0600298 XGL_UINT data_size = sizeof(sr_layout);
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600299
300 if (!m_show_images) return;
301
302 InitGLUT(image->width(), image->height());
303
304 err = xglGetImageSubresourceInfo( image->image(), &sr, XGL_INFO_TYPE_SUBRESOURCE_LAYOUT,
305 &data_size, &sr_layout);
306 ASSERT_XGL_SUCCESS( err );
307 ASSERT_EQ(data_size, sizeof(sr_layout));
308
309 const char *ptr;
310
311 err = image->MapMemory( (XGL_VOID **) &ptr );
312 ASSERT_XGL_SUCCESS( err );
313
314 ptr += sr_layout.offset;
315
316 XglTestImageRecord record;
317 record.m_title.append(comment);
318 record.m_width = image->width();
319 record.m_height = image->height();
320 // TODO: Need to make this more robust to handle different image formats
321 record.m_data_size = image->width()*image->height()*4;
322 record.m_data = malloc(record.m_data_size);
323 memcpy(record.m_data, ptr, record.m_data_size);
324 m_images.push_back(record);
325 m_display_image = --m_images.end();
326
Courtney Goeltzenleuchter02d33c12014-10-08 14:26:40 -0600327// Display();
328 glutPostRedisplay();
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600329
330 err = image->UnmapMemory();
331 ASSERT_XGL_SUCCESS( err );
332}
333
Tony Barbour247bf372014-10-30 14:29:04 -0600334void XglTestFramework::RecordImage(XglImage *image, char *tag)
335{
336 const ::testing::TestInfo* const test_info =
337 ::testing::UnitTest::GetInstance()->current_test_info();
338 ostringstream filestream;
339 string filename;
340
341 filestream << test_info->name() << "-" << tag;
342 filename = filestream.str();
343 // ToDo - scrub string for bad characters
344
345 if (m_save_images || m_compare_images) {
346 WritePPM(filename.c_str(), image);
347 if (m_compare_images) {
348 Compare(filename.c_str(), image);
349 }
350 }
351
352 if (m_show_images) {
353 Show(test_info->name(), image);
354 }
355}
356
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600357void XglTestFramework::RecordImage(XglImage *image)
358{
359 const ::testing::TestInfo* const test_info =
360 ::testing::UnitTest::GetInstance()->current_test_info();
Tony Barbour247bf372014-10-30 14:29:04 -0600361 ostringstream filestream;
362 string filename;
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600363
Tony Barbour247bf372014-10-30 14:29:04 -0600364 m_width = 40;
365
366 if (strcmp(test_info->name(), m_testName.c_str())) {
367 filestream << test_info->name();
368 m_testName.assign(test_info->name());
369 m_frameNum = 1;
370 }
371 else {
372 filestream << test_info->name() << "-" << m_frameNum;
373 m_frameNum++;
374 }
375
376
377 // ToDo - scrub string for bad characters
378
379 if (m_save_images || m_compare_images) {
380 WritePPM(filename.c_str(), image);
381 if (m_compare_images) {
382 Compare(filename.c_str(), image);
383 }
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600384 }
385
386 if (m_show_images) {
Courtney Goeltzenleuchter02d33c12014-10-08 14:26:40 -0600387 Show(test_info->name(), image);
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600388 }
389}
390
391void XglTestFramework::Display()
392{
393 glutSetWindowTitle(m_display_image->m_title.c_str());
394
395 glClearColor(0, 0, 0, 0);
396 glClear(GL_COLOR_BUFFER_BIT);
397 glRasterPos3f(0, 0, 0);
398 glBitmap(0, 0, 0, 0, 0, 0, NULL);
399 glDrawPixels(m_display_image->m_width, m_display_image->m_height,
400 GL_RGBA, GL_UNSIGNED_BYTE, m_display_image->m_data);
401
402 glutSwapBuffers();
403}
404
405void XglTestFramework::Key( unsigned char key, int x, int y )
406{
407 (void) x;
408 (void) y;
409 switch (key) {
410 case 27:
411 glutDestroyWindow(m_window);
412 exit(0);
413 break;
414 }
415 glutPostRedisplay();
416}
417
418void XglTestFramework::SpecialKey( int key, int x, int y )
419{
420 (void) x;
421 (void) y;
422 switch (key) {
423 case GLUT_KEY_UP:
424 case GLUT_KEY_RIGHT:
425 ++m_display_image;
426 if (m_display_image == m_images.end()) {
427 m_display_image = m_images.begin();
428 }
429 break;
430 case GLUT_KEY_DOWN:
431 case GLUT_KEY_LEFT:
432 if (m_display_image == m_images.begin()) {
433 m_display_image = --m_images.end();
434 } else {
435 --m_display_image;
436 }
437
438 break;
439 }
440 glutPostRedisplay();
441}
442
443void XglTestFramework::Finish()
444{
445 if (m_images.size() == 0) return;
446
447 glutReshapeFunc( Reshape );
448 glutKeyboardFunc( Key );
449 glutSpecialFunc( SpecialKey );
450 glutDisplayFunc( Display );
Courtney Goeltzenleuchter02d33c12014-10-08 14:26:40 -0600451 glutIdleFunc(NULL);
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600452
453 glutMainLoop();
454}
455
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -0600456//
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -0600457// These are the default resources for TBuiltInResources, used for both
458// - parsing this string for the case where the user didn't supply one
459// - dumping out a template for user construction of a config file
460//
461static const char* DefaultConfig =
462 "MaxLights 32\n"
463 "MaxClipPlanes 6\n"
464 "MaxTextureUnits 32\n"
465 "MaxTextureCoords 32\n"
466 "MaxVertexAttribs 64\n"
467 "MaxVertexUniformComponents 4096\n"
468 "MaxVaryingFloats 64\n"
469 "MaxVertexTextureImageUnits 32\n"
470 "MaxCombinedTextureImageUnits 80\n"
471 "MaxTextureImageUnits 32\n"
472 "MaxFragmentUniformComponents 4096\n"
473 "MaxDrawBuffers 32\n"
474 "MaxVertexUniformVectors 128\n"
475 "MaxVaryingVectors 8\n"
476 "MaxFragmentUniformVectors 16\n"
477 "MaxVertexOutputVectors 16\n"
478 "MaxFragmentInputVectors 15\n"
479 "MinProgramTexelOffset -8\n"
480 "MaxProgramTexelOffset 7\n"
481 "MaxClipDistances 8\n"
482 "MaxComputeWorkGroupCountX 65535\n"
483 "MaxComputeWorkGroupCountY 65535\n"
484 "MaxComputeWorkGroupCountZ 65535\n"
485 "MaxComputeWorkGroupSizeX 1024\n"
486 "MaxComputeWorkGroupSizeY 1024\n"
487 "MaxComputeWorkGroupSizeZ 64\n"
488 "MaxComputeUniformComponents 1024\n"
489 "MaxComputeTextureImageUnits 16\n"
490 "MaxComputeImageUniforms 8\n"
491 "MaxComputeAtomicCounters 8\n"
492 "MaxComputeAtomicCounterBuffers 1\n"
493 "MaxVaryingComponents 60\n"
494 "MaxVertexOutputComponents 64\n"
495 "MaxGeometryInputComponents 64\n"
496 "MaxGeometryOutputComponents 128\n"
497 "MaxFragmentInputComponents 128\n"
498 "MaxImageUnits 8\n"
499 "MaxCombinedImageUnitsAndFragmentOutputs 8\n"
500 "MaxCombinedShaderOutputResources 8\n"
501 "MaxImageSamples 0\n"
502 "MaxVertexImageUniforms 0\n"
503 "MaxTessControlImageUniforms 0\n"
504 "MaxTessEvaluationImageUniforms 0\n"
505 "MaxGeometryImageUniforms 0\n"
506 "MaxFragmentImageUniforms 8\n"
507 "MaxCombinedImageUniforms 8\n"
508 "MaxGeometryTextureImageUnits 16\n"
509 "MaxGeometryOutputVertices 256\n"
510 "MaxGeometryTotalOutputComponents 1024\n"
511 "MaxGeometryUniformComponents 1024\n"
512 "MaxGeometryVaryingComponents 64\n"
513 "MaxTessControlInputComponents 128\n"
514 "MaxTessControlOutputComponents 128\n"
515 "MaxTessControlTextureImageUnits 16\n"
516 "MaxTessControlUniformComponents 1024\n"
517 "MaxTessControlTotalOutputComponents 4096\n"
518 "MaxTessEvaluationInputComponents 128\n"
519 "MaxTessEvaluationOutputComponents 128\n"
520 "MaxTessEvaluationTextureImageUnits 16\n"
521 "MaxTessEvaluationUniformComponents 1024\n"
522 "MaxTessPatchComponents 120\n"
523 "MaxPatchVertices 32\n"
524 "MaxTessGenLevel 64\n"
525 "MaxViewports 16\n"
526 "MaxVertexAtomicCounters 0\n"
527 "MaxTessControlAtomicCounters 0\n"
528 "MaxTessEvaluationAtomicCounters 0\n"
529 "MaxGeometryAtomicCounters 0\n"
530 "MaxFragmentAtomicCounters 8\n"
531 "MaxCombinedAtomicCounters 8\n"
532 "MaxAtomicCounterBindings 1\n"
533 "MaxVertexAtomicCounterBuffers 0\n"
534 "MaxTessControlAtomicCounterBuffers 0\n"
535 "MaxTessEvaluationAtomicCounterBuffers 0\n"
536 "MaxGeometryAtomicCounterBuffers 0\n"
537 "MaxFragmentAtomicCounterBuffers 1\n"
538 "MaxCombinedAtomicCounterBuffers 1\n"
539 "MaxAtomicCounterBufferSize 16384\n"
540 "MaxTransformFeedbackBuffers 4\n"
541 "MaxTransformFeedbackInterleavedComponents 64\n"
542 "MaxCullDistances 8\n"
543 "MaxCombinedClipAndCullDistances 8\n"
544 "MaxSamples 4\n"
545
546 "nonInductiveForLoops 1\n"
547 "whileLoops 1\n"
548 "doWhileLoops 1\n"
549 "generalUniformIndexing 1\n"
550 "generalAttributeMatrixVectorIndexing 1\n"
551 "generalVaryingIndexing 1\n"
552 "generalSamplerIndexing 1\n"
553 "generalVariableIndexing 1\n"
554 "generalConstantMatrixVectorIndexing 1\n"
555 ;
556
557//
558// *.conf => this is a config file that can set limits/resources
559//
560bool XglTestFramework::SetConfigFile(const std::string& name)
561{
562 if (name.size() < 5)
563 return false;
564
565 if (name.compare(name.size() - 5, 5, ".conf") == 0) {
566 ConfigFile = name;
567 return true;
568 }
569
570 return false;
571}
572
573//
574// Parse either a .conf file provided by the user or the default string above.
575//
576void XglTestFramework::ProcessConfigFile()
577{
578 char** configStrings = 0;
579 char* config = 0;
580 if (ConfigFile.size() > 0) {
581 configStrings = ReadFileData(ConfigFile.c_str());
582 if (configStrings)
583 config = *configStrings;
584 else {
585 printf("Error opening configuration file; will instead use the default configuration\n");
586 }
587 }
588
589 if (config == 0) {
590 config = new char[strlen(DefaultConfig) + 1];
591 strcpy(config, DefaultConfig);
592 }
593
594 const char* delims = " \t\n\r";
595 const char* token = strtok(config, delims);
596 while (token) {
597 const char* valueStr = strtok(0, delims);
598 if (valueStr == 0 || ! (valueStr[0] == '-' || (valueStr[0] >= '0' && valueStr[0] <= '9'))) {
599 printf("Error: '%s' bad .conf file. Each name must be followed by one number.\n", valueStr ? valueStr : "");
600 return;
601 }
602 int value = atoi(valueStr);
603
604 if (strcmp(token, "MaxLights") == 0)
605 Resources.maxLights = value;
606 else if (strcmp(token, "MaxClipPlanes") == 0)
607 Resources.maxClipPlanes = value;
608 else if (strcmp(token, "MaxTextureUnits") == 0)
609 Resources.maxTextureUnits = value;
610 else if (strcmp(token, "MaxTextureCoords") == 0)
611 Resources.maxTextureCoords = value;
612 else if (strcmp(token, "MaxVertexAttribs") == 0)
613 Resources.maxVertexAttribs = value;
614 else if (strcmp(token, "MaxVertexUniformComponents") == 0)
615 Resources.maxVertexUniformComponents = value;
616 else if (strcmp(token, "MaxVaryingFloats") == 0)
617 Resources.maxVaryingFloats = value;
618 else if (strcmp(token, "MaxVertexTextureImageUnits") == 0)
619 Resources.maxVertexTextureImageUnits = value;
620 else if (strcmp(token, "MaxCombinedTextureImageUnits") == 0)
621 Resources.maxCombinedTextureImageUnits = value;
622 else if (strcmp(token, "MaxTextureImageUnits") == 0)
623 Resources.maxTextureImageUnits = value;
624 else if (strcmp(token, "MaxFragmentUniformComponents") == 0)
625 Resources.maxFragmentUniformComponents = value;
626 else if (strcmp(token, "MaxDrawBuffers") == 0)
627 Resources.maxDrawBuffers = value;
628 else if (strcmp(token, "MaxVertexUniformVectors") == 0)
629 Resources.maxVertexUniformVectors = value;
630 else if (strcmp(token, "MaxVaryingVectors") == 0)
631 Resources.maxVaryingVectors = value;
632 else if (strcmp(token, "MaxFragmentUniformVectors") == 0)
633 Resources.maxFragmentUniformVectors = value;
634 else if (strcmp(token, "MaxVertexOutputVectors") == 0)
635 Resources.maxVertexOutputVectors = value;
636 else if (strcmp(token, "MaxFragmentInputVectors") == 0)
637 Resources.maxFragmentInputVectors = value;
638 else if (strcmp(token, "MinProgramTexelOffset") == 0)
639 Resources.minProgramTexelOffset = value;
640 else if (strcmp(token, "MaxProgramTexelOffset") == 0)
641 Resources.maxProgramTexelOffset = value;
642 else if (strcmp(token, "MaxClipDistances") == 0)
643 Resources.maxClipDistances = value;
644 else if (strcmp(token, "MaxComputeWorkGroupCountX") == 0)
645 Resources.maxComputeWorkGroupCountX = value;
646 else if (strcmp(token, "MaxComputeWorkGroupCountY") == 0)
647 Resources.maxComputeWorkGroupCountY = value;
648 else if (strcmp(token, "MaxComputeWorkGroupCountZ") == 0)
649 Resources.maxComputeWorkGroupCountZ = value;
650 else if (strcmp(token, "MaxComputeWorkGroupSizeX") == 0)
651 Resources.maxComputeWorkGroupSizeX = value;
652 else if (strcmp(token, "MaxComputeWorkGroupSizeY") == 0)
653 Resources.maxComputeWorkGroupSizeY = value;
654 else if (strcmp(token, "MaxComputeWorkGroupSizeZ") == 0)
655 Resources.maxComputeWorkGroupSizeZ = value;
656 else if (strcmp(token, "MaxComputeUniformComponents") == 0)
657 Resources.maxComputeUniformComponents = value;
658 else if (strcmp(token, "MaxComputeTextureImageUnits") == 0)
659 Resources.maxComputeTextureImageUnits = value;
660 else if (strcmp(token, "MaxComputeImageUniforms") == 0)
661 Resources.maxComputeImageUniforms = value;
662 else if (strcmp(token, "MaxComputeAtomicCounters") == 0)
663 Resources.maxComputeAtomicCounters = value;
664 else if (strcmp(token, "MaxComputeAtomicCounterBuffers") == 0)
665 Resources.maxComputeAtomicCounterBuffers = value;
666 else if (strcmp(token, "MaxVaryingComponents") == 0)
667 Resources.maxVaryingComponents = value;
668 else if (strcmp(token, "MaxVertexOutputComponents") == 0)
669 Resources.maxVertexOutputComponents = value;
670 else if (strcmp(token, "MaxGeometryInputComponents") == 0)
671 Resources.maxGeometryInputComponents = value;
672 else if (strcmp(token, "MaxGeometryOutputComponents") == 0)
673 Resources.maxGeometryOutputComponents = value;
674 else if (strcmp(token, "MaxFragmentInputComponents") == 0)
675 Resources.maxFragmentInputComponents = value;
676 else if (strcmp(token, "MaxImageUnits") == 0)
677 Resources.maxImageUnits = value;
678 else if (strcmp(token, "MaxCombinedImageUnitsAndFragmentOutputs") == 0)
679 Resources.maxCombinedImageUnitsAndFragmentOutputs = value;
680 else if (strcmp(token, "MaxCombinedShaderOutputResources") == 0)
681 Resources.maxCombinedShaderOutputResources = value;
682 else if (strcmp(token, "MaxImageSamples") == 0)
683 Resources.maxImageSamples = value;
684 else if (strcmp(token, "MaxVertexImageUniforms") == 0)
685 Resources.maxVertexImageUniforms = value;
686 else if (strcmp(token, "MaxTessControlImageUniforms") == 0)
687 Resources.maxTessControlImageUniforms = value;
688 else if (strcmp(token, "MaxTessEvaluationImageUniforms") == 0)
689 Resources.maxTessEvaluationImageUniforms = value;
690 else if (strcmp(token, "MaxGeometryImageUniforms") == 0)
691 Resources.maxGeometryImageUniforms = value;
692 else if (strcmp(token, "MaxFragmentImageUniforms") == 0)
693 Resources.maxFragmentImageUniforms = value;
694 else if (strcmp(token, "MaxCombinedImageUniforms") == 0)
695 Resources.maxCombinedImageUniforms = value;
696 else if (strcmp(token, "MaxGeometryTextureImageUnits") == 0)
697 Resources.maxGeometryTextureImageUnits = value;
698 else if (strcmp(token, "MaxGeometryOutputVertices") == 0)
699 Resources.maxGeometryOutputVertices = value;
700 else if (strcmp(token, "MaxGeometryTotalOutputComponents") == 0)
701 Resources.maxGeometryTotalOutputComponents = value;
702 else if (strcmp(token, "MaxGeometryUniformComponents") == 0)
703 Resources.maxGeometryUniformComponents = value;
704 else if (strcmp(token, "MaxGeometryVaryingComponents") == 0)
705 Resources.maxGeometryVaryingComponents = value;
706 else if (strcmp(token, "MaxTessControlInputComponents") == 0)
707 Resources.maxTessControlInputComponents = value;
708 else if (strcmp(token, "MaxTessControlOutputComponents") == 0)
709 Resources.maxTessControlOutputComponents = value;
710 else if (strcmp(token, "MaxTessControlTextureImageUnits") == 0)
711 Resources.maxTessControlTextureImageUnits = value;
712 else if (strcmp(token, "MaxTessControlUniformComponents") == 0)
713 Resources.maxTessControlUniformComponents = value;
714 else if (strcmp(token, "MaxTessControlTotalOutputComponents") == 0)
715 Resources.maxTessControlTotalOutputComponents = value;
716 else if (strcmp(token, "MaxTessEvaluationInputComponents") == 0)
717 Resources.maxTessEvaluationInputComponents = value;
718 else if (strcmp(token, "MaxTessEvaluationOutputComponents") == 0)
719 Resources.maxTessEvaluationOutputComponents = value;
720 else if (strcmp(token, "MaxTessEvaluationTextureImageUnits") == 0)
721 Resources.maxTessEvaluationTextureImageUnits = value;
722 else if (strcmp(token, "MaxTessEvaluationUniformComponents") == 0)
723 Resources.maxTessEvaluationUniformComponents = value;
724 else if (strcmp(token, "MaxTessPatchComponents") == 0)
725 Resources.maxTessPatchComponents = value;
726 else if (strcmp(token, "MaxPatchVertices") == 0)
727 Resources.maxPatchVertices = value;
728 else if (strcmp(token, "MaxTessGenLevel") == 0)
729 Resources.maxTessGenLevel = value;
730 else if (strcmp(token, "MaxViewports") == 0)
731 Resources.maxViewports = value;
732 else if (strcmp(token, "MaxVertexAtomicCounters") == 0)
733 Resources.maxVertexAtomicCounters = value;
734 else if (strcmp(token, "MaxTessControlAtomicCounters") == 0)
735 Resources.maxTessControlAtomicCounters = value;
736 else if (strcmp(token, "MaxTessEvaluationAtomicCounters") == 0)
737 Resources.maxTessEvaluationAtomicCounters = value;
738 else if (strcmp(token, "MaxGeometryAtomicCounters") == 0)
739 Resources.maxGeometryAtomicCounters = value;
740 else if (strcmp(token, "MaxFragmentAtomicCounters") == 0)
741 Resources.maxFragmentAtomicCounters = value;
742 else if (strcmp(token, "MaxCombinedAtomicCounters") == 0)
743 Resources.maxCombinedAtomicCounters = value;
744 else if (strcmp(token, "MaxAtomicCounterBindings") == 0)
745 Resources.maxAtomicCounterBindings = value;
746 else if (strcmp(token, "MaxVertexAtomicCounterBuffers") == 0)
747 Resources.maxVertexAtomicCounterBuffers = value;
748 else if (strcmp(token, "MaxTessControlAtomicCounterBuffers") == 0)
749 Resources.maxTessControlAtomicCounterBuffers = value;
750 else if (strcmp(token, "MaxTessEvaluationAtomicCounterBuffers") == 0)
751 Resources.maxTessEvaluationAtomicCounterBuffers = value;
752 else if (strcmp(token, "MaxGeometryAtomicCounterBuffers") == 0)
753 Resources.maxGeometryAtomicCounterBuffers = value;
754 else if (strcmp(token, "MaxFragmentAtomicCounterBuffers") == 0)
755 Resources.maxFragmentAtomicCounterBuffers = value;
756 else if (strcmp(token, "MaxCombinedAtomicCounterBuffers") == 0)
757 Resources.maxCombinedAtomicCounterBuffers = value;
758 else if (strcmp(token, "MaxAtomicCounterBufferSize") == 0)
759 Resources.maxAtomicCounterBufferSize = value;
760 else if (strcmp(token, "MaxTransformFeedbackBuffers") == 0)
761 Resources.maxTransformFeedbackBuffers = value;
762 else if (strcmp(token, "MaxTransformFeedbackInterleavedComponents") == 0)
763 Resources.maxTransformFeedbackInterleavedComponents = value;
764 else if (strcmp(token, "MaxCullDistances") == 0)
765 Resources.maxCullDistances = value;
766 else if (strcmp(token, "MaxCombinedClipAndCullDistances") == 0)
767 Resources.maxCombinedClipAndCullDistances = value;
768 else if (strcmp(token, "MaxSamples") == 0)
769 Resources.maxSamples = value;
770
771 else if (strcmp(token, "nonInductiveForLoops") == 0)
772 Resources.limits.nonInductiveForLoops = (value != 0);
773 else if (strcmp(token, "whileLoops") == 0)
774 Resources.limits.whileLoops = (value != 0);
775 else if (strcmp(token, "doWhileLoops") == 0)
776 Resources.limits.doWhileLoops = (value != 0);
777 else if (strcmp(token, "generalUniformIndexing") == 0)
778 Resources.limits.generalUniformIndexing = (value != 0);
779 else if (strcmp(token, "generalAttributeMatrixVectorIndexing") == 0)
780 Resources.limits.generalAttributeMatrixVectorIndexing = (value != 0);
781 else if (strcmp(token, "generalVaryingIndexing") == 0)
782 Resources.limits.generalVaryingIndexing = (value != 0);
783 else if (strcmp(token, "generalSamplerIndexing") == 0)
784 Resources.limits.generalSamplerIndexing = (value != 0);
785 else if (strcmp(token, "generalVariableIndexing") == 0)
786 Resources.limits.generalVariableIndexing = (value != 0);
787 else if (strcmp(token, "generalConstantMatrixVectorIndexing") == 0)
788 Resources.limits.generalConstantMatrixVectorIndexing = (value != 0);
789 else
790 printf("Warning: unrecognized limit (%s) in configuration file.\n", token);
791
792 token = strtok(0, delims);
793 }
794 if (configStrings)
795 FreeFileData(configStrings);
796}
797
798void XglTestFramework::SetMessageOptions(EShMessages& messages)
799{
800 if (m_compile_options & EOptionRelaxedErrors)
801 messages = (EShMessages)(messages | EShMsgRelaxedErrors);
802 if (m_compile_options & EOptionIntermediate)
803 messages = (EShMessages)(messages | EShMsgAST);
804 if (m_compile_options & EOptionSuppressWarnings)
805 messages = (EShMessages)(messages | EShMsgSuppressWarnings);
806}
807
808//
809// Malloc a string of sufficient size and read a string into it.
810//
811char** XglTestFramework::ReadFileData(const char* fileName)
812{
813 FILE *in;
814 #if defined(_WIN32) && defined(__GNUC__)
815 in = fopen(fileName, "r");
816 int errorCode = in ? 0 : 1;
817 #else
818 int errorCode = fopen_s(&in, fileName, "r");
819 #endif
820
821 char *fdata;
822 int count = 0;
823 const int maxSourceStrings = 5;
824 char** return_data = (char**)malloc(sizeof(char *) * (maxSourceStrings+1));
825
826 if (errorCode) {
827 printf("Error: unable to open input file: %s\n", fileName);
828 return 0;
829 }
830
831 while (fgetc(in) != EOF)
832 count++;
833
834 fseek(in, 0, SEEK_SET);
835
836 if (!(fdata = (char*)malloc(count+2))) {
837 printf("Error allocating memory\n");
838 return 0;
839 }
840 if (fread(fdata,1,count, in)!=count) {
841 printf("Error reading input file: %s\n", fileName);
842 return 0;
843 }
844 fdata[count] = '\0';
845 fclose(in);
846 if (count == 0) {
847 return_data[0]=(char*)malloc(count+2);
848 return_data[0][0]='\0';
849 m_num_shader_strings = 0;
850 return return_data;
851 } else
852 m_num_shader_strings = 1;
853
854 int len = (int)(ceil)((float)count/(float)m_num_shader_strings);
855 int ptr_len=0,i=0;
856 while(count>0){
857 return_data[i]=(char*)malloc(len+2);
858 memcpy(return_data[i],fdata+ptr_len,len);
859 return_data[i][len]='\0';
860 count-=(len);
861 ptr_len+=(len);
862 if(count<len){
863 if(count==0){
864 m_num_shader_strings=(i+1);
865 break;
866 }
867 len = count;
868 }
869 ++i;
870 }
871 return return_data;
872}
873
874void XglTestFramework::FreeFileData(char** data)
875{
876 for(int i=0;i<m_num_shader_strings;i++)
877 free(data[i]);
878}
879
880//
881// Deduce the language from the filename. Files must end in one of the
882// following extensions:
883//
884// .vert = vertex
885// .tesc = tessellation control
886// .tese = tessellation evaluation
887// .geom = geometry
888// .frag = fragment
889// .comp = compute
890//
891EShLanguage XglTestFramework::FindLanguage(const std::string& name)
892{
893 size_t ext = name.rfind('.');
894 if (ext == std::string::npos) {
895 return EShLangVertex;
896 }
897
898 std::string suffix = name.substr(ext + 1, std::string::npos);
899 if (suffix == "vert")
900 return EShLangVertex;
901 else if (suffix == "tesc")
902 return EShLangTessControl;
903 else if (suffix == "tese")
904 return EShLangTessEvaluation;
905 else if (suffix == "geom")
906 return EShLangGeometry;
907 else if (suffix == "frag")
908 return EShLangFragment;
909 else if (suffix == "comp")
910 return EShLangCompute;
911
912 return EShLangVertex;
913}
914
915//
916// Convert XGL shader type to compiler's
917//
918EShLanguage XglTestFramework::FindLanguage(const XGL_PIPELINE_SHADER_STAGE shader_type)
919{
920 switch (shader_type) {
921 case XGL_SHADER_STAGE_VERTEX:
922 return EShLangVertex;
923
924 case XGL_SHADER_STAGE_TESS_CONTROL:
925 return EShLangTessControl;
926
927 case XGL_SHADER_STAGE_TESS_EVALUATION:
928 return EShLangTessEvaluation;
929
930 case XGL_SHADER_STAGE_GEOMETRY:
931 return EShLangGeometry;
932
933 case XGL_SHADER_STAGE_FRAGMENT:
934 return EShLangFragment;
935
936 case XGL_SHADER_STAGE_COMPUTE:
937 return EShLangCompute;
938 }
939
940 return EShLangVertex;
941}
942
943
944//
945// Compile a given string containing GLSL into BIL for use by XGL
946// Return value of false means an error was encountered.
947//
948bool XglTestFramework::GLSLtoBIL(const XGL_PIPELINE_SHADER_STAGE shader_type,
949 const char *pshader,
950 std::vector<unsigned int> &bil)
951{
952 glslang::TProgram& program = *new glslang::TProgram;
953 const char *shaderStrings[1];
954
955 // TODO: Do we want to load a special config file depending on the
956 // shader source? Optional name maybe?
957 // SetConfigFile(fileName);
958
959 ProcessConfigFile();
960
961 EShMessages messages = EShMsgDefault;
962 SetMessageOptions(messages);
963
964 EShLanguage stage = FindLanguage(shader_type);
965 glslang::TShader* shader = new glslang::TShader(stage);
966
967 shaderStrings[0] = pshader;
968 shader->setStrings(shaderStrings, 1);
969
970 if (! shader->parse(&Resources, (m_compile_options & EOptionDefaultDesktop) ? 110 : 100, false, messages)) {
971
Cody Northrop195d6622014-11-03 12:54:37 -0700972 if (! (m_compile_options & EOptionSuppressInfolog)) {
973 puts(shader->getInfoLog());
974 puts(shader->getInfoDebugLog());
975 }
976
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -0600977 return false; // something didn't work
978 }
979
980 program.addShader(shader);
981
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -0600982
983 //
984 // Program-level processing...
985 //
986
Cody Northrop195d6622014-11-03 12:54:37 -0700987 if (! program.link(messages)) {
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -0600988
Cody Northrop195d6622014-11-03 12:54:37 -0700989 if (! (m_compile_options & EOptionSuppressInfolog)) {
990 puts(shader->getInfoLog());
991 puts(shader->getInfoDebugLog());
992 }
993
994 return false;
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -0600995 }
996
997 if (m_compile_options & EOptionDumpReflection) {
998 program.buildReflection();
999 program.dumpReflection();
1000 }
1001
1002 glslang::GlslangToBil(*program.getIntermediate(stage), bil);
1003
1004 return true;
1005}
1006
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -06001007
1008
1009XglTestImageRecord::XglTestImageRecord() : // Constructor
1010 m_width( 0 ),
1011 m_height( 0 ),
1012 m_data( NULL )
1013{
1014 m_data_size = 0;
1015}
1016
1017XglTestImageRecord::~XglTestImageRecord()
1018{
1019
1020}
1021
1022XglTestImageRecord::XglTestImageRecord(const XglTestImageRecord &copyin) // Copy constructor to handle pass by value.
1023{
1024 m_title = copyin.m_title;
1025 m_width = copyin.m_width;
1026 m_height = copyin.m_height;
1027 m_data_size = copyin.m_data_size;
1028 m_data = copyin.m_data; // TODO: Do we need to copy the data or is pointer okay?
1029}
1030
1031ostream &operator<<(ostream &output, const XglTestImageRecord &XglTestImageRecord)
1032{
1033 output << XglTestImageRecord.m_title << " (" << XglTestImageRecord.m_width <<
1034 "," << XglTestImageRecord.m_height << ")" << endl;
1035 return output;
1036}
1037
1038XglTestImageRecord& XglTestImageRecord::operator=(const XglTestImageRecord &rhs)
1039{
1040 m_title = rhs.m_title;
1041 m_width = rhs.m_width;
1042 m_height = rhs.m_height;
1043 m_data_size = rhs.m_data_size;
1044 m_data = rhs.m_data;
1045 return *this;
1046}
1047
1048int XglTestImageRecord::operator==(const XglTestImageRecord &rhs) const
1049{
1050 if( this->m_data != rhs.m_data) return 0;
1051 return 1;
1052}
1053
1054// This function is required for built-in STL list functions like sort
1055int XglTestImageRecord::operator<(const XglTestImageRecord &rhs) const
1056{
1057 if( this->m_data_size < rhs.m_data_size ) return 1;
1058 return 0;
1059}
1060