blob: 18379ff28146a0b41dec114170f8f95277689393 [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();
305}
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600306
307void XglTestFramework::Show(const char *comment, XglImage *image)
308{
309 XGL_RESULT err;
310
311 const XGL_IMAGE_SUBRESOURCE sr = {
312 XGL_IMAGE_ASPECT_COLOR, 0, 0
313 };
314 XGL_SUBRESOURCE_LAYOUT sr_layout;
Jon Ashburne494a1a2014-09-25 14:36:58 -0600315 XGL_UINT data_size = sizeof(sr_layout);
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600316
317 if (!m_show_images) return;
318
319 InitGLUT(image->width(), image->height());
320
321 err = xglGetImageSubresourceInfo( image->image(), &sr, XGL_INFO_TYPE_SUBRESOURCE_LAYOUT,
322 &data_size, &sr_layout);
323 ASSERT_XGL_SUCCESS( err );
324 ASSERT_EQ(data_size, sizeof(sr_layout));
325
326 const char *ptr;
327
328 err = image->MapMemory( (XGL_VOID **) &ptr );
329 ASSERT_XGL_SUCCESS( err );
330
331 ptr += sr_layout.offset;
332
333 XglTestImageRecord record;
334 record.m_title.append(comment);
335 record.m_width = image->width();
336 record.m_height = image->height();
337 // TODO: Need to make this more robust to handle different image formats
338 record.m_data_size = image->width()*image->height()*4;
339 record.m_data = malloc(record.m_data_size);
340 memcpy(record.m_data, ptr, record.m_data_size);
341 m_images.push_back(record);
342 m_display_image = --m_images.end();
343
Courtney Goeltzenleuchter02d33c12014-10-08 14:26:40 -0600344// Display();
345 glutPostRedisplay();
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600346
347 err = image->UnmapMemory();
348 ASSERT_XGL_SUCCESS( err );
349}
350
Tony Barbour247bf372014-10-30 14:29:04 -0600351void XglTestFramework::RecordImage(XglImage *image, char *tag)
352{
353 const ::testing::TestInfo* const test_info =
354 ::testing::UnitTest::GetInstance()->current_test_info();
355 ostringstream filestream;
356 string filename;
357
358 filestream << test_info->name() << "-" << tag;
359 filename = filestream.str();
360 // ToDo - scrub string for bad characters
361
362 if (m_save_images || m_compare_images) {
363 WritePPM(filename.c_str(), image);
364 if (m_compare_images) {
365 Compare(filename.c_str(), image);
366 }
367 }
368
369 if (m_show_images) {
370 Show(test_info->name(), image);
371 }
372}
373
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600374void XglTestFramework::RecordImage(XglImage *image)
375{
376 const ::testing::TestInfo* const test_info =
377 ::testing::UnitTest::GetInstance()->current_test_info();
Tony Barbour247bf372014-10-30 14:29:04 -0600378 ostringstream filestream;
379 string filename;
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600380
Tony Barbour247bf372014-10-30 14:29:04 -0600381 m_width = 40;
382
383 if (strcmp(test_info->name(), m_testName.c_str())) {
384 filestream << test_info->name();
385 m_testName.assign(test_info->name());
Tony Barboura0e2ee82014-11-18 17:02:36 -0700386 m_frameNum = 2;
387 filename = filestream.str();
Tony Barbour247bf372014-10-30 14:29:04 -0600388 }
389 else {
390 filestream << test_info->name() << "-" << m_frameNum;
391 m_frameNum++;
Tony Barboura0e2ee82014-11-18 17:02:36 -0700392 filename = filestream.str();
Tony Barbour247bf372014-10-30 14:29:04 -0600393 }
394
395
396 // ToDo - scrub string for bad characters
397
398 if (m_save_images || m_compare_images) {
399 WritePPM(filename.c_str(), image);
400 if (m_compare_images) {
401 Compare(filename.c_str(), image);
402 }
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600403 }
404
405 if (m_show_images) {
Courtney Goeltzenleuchter02d33c12014-10-08 14:26:40 -0600406 Show(test_info->name(), image);
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600407 }
408}
409
410void XglTestFramework::Display()
411{
412 glutSetWindowTitle(m_display_image->m_title.c_str());
413
414 glClearColor(0, 0, 0, 0);
415 glClear(GL_COLOR_BUFFER_BIT);
416 glRasterPos3f(0, 0, 0);
417 glBitmap(0, 0, 0, 0, 0, 0, NULL);
418 glDrawPixels(m_display_image->m_width, m_display_image->m_height,
419 GL_RGBA, GL_UNSIGNED_BYTE, m_display_image->m_data);
420
421 glutSwapBuffers();
422}
423
424void XglTestFramework::Key( unsigned char key, int x, int y )
425{
426 (void) x;
427 (void) y;
428 switch (key) {
429 case 27:
430 glutDestroyWindow(m_window);
431 exit(0);
432 break;
433 }
434 glutPostRedisplay();
435}
436
437void XglTestFramework::SpecialKey( int key, int x, int y )
438{
439 (void) x;
440 (void) y;
441 switch (key) {
442 case GLUT_KEY_UP:
443 case GLUT_KEY_RIGHT:
444 ++m_display_image;
445 if (m_display_image == m_images.end()) {
446 m_display_image = m_images.begin();
447 }
448 break;
449 case GLUT_KEY_DOWN:
450 case GLUT_KEY_LEFT:
451 if (m_display_image == m_images.begin()) {
452 m_display_image = --m_images.end();
453 } else {
454 --m_display_image;
455 }
456
457 break;
458 }
459 glutPostRedisplay();
460}
461
462void XglTestFramework::Finish()
463{
464 if (m_images.size() == 0) return;
465
466 glutReshapeFunc( Reshape );
467 glutKeyboardFunc( Key );
468 glutSpecialFunc( SpecialKey );
469 glutDisplayFunc( Display );
Courtney Goeltzenleuchter02d33c12014-10-08 14:26:40 -0600470 glutIdleFunc(NULL);
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600471
472 glutMainLoop();
473}
474
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -0600475//
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -0600476// These are the default resources for TBuiltInResources, used for both
477// - parsing this string for the case where the user didn't supply one
478// - dumping out a template for user construction of a config file
479//
480static const char* DefaultConfig =
481 "MaxLights 32\n"
482 "MaxClipPlanes 6\n"
483 "MaxTextureUnits 32\n"
484 "MaxTextureCoords 32\n"
485 "MaxVertexAttribs 64\n"
486 "MaxVertexUniformComponents 4096\n"
487 "MaxVaryingFloats 64\n"
488 "MaxVertexTextureImageUnits 32\n"
489 "MaxCombinedTextureImageUnits 80\n"
490 "MaxTextureImageUnits 32\n"
491 "MaxFragmentUniformComponents 4096\n"
492 "MaxDrawBuffers 32\n"
493 "MaxVertexUniformVectors 128\n"
494 "MaxVaryingVectors 8\n"
495 "MaxFragmentUniformVectors 16\n"
496 "MaxVertexOutputVectors 16\n"
497 "MaxFragmentInputVectors 15\n"
498 "MinProgramTexelOffset -8\n"
499 "MaxProgramTexelOffset 7\n"
500 "MaxClipDistances 8\n"
501 "MaxComputeWorkGroupCountX 65535\n"
502 "MaxComputeWorkGroupCountY 65535\n"
503 "MaxComputeWorkGroupCountZ 65535\n"
504 "MaxComputeWorkGroupSizeX 1024\n"
505 "MaxComputeWorkGroupSizeY 1024\n"
506 "MaxComputeWorkGroupSizeZ 64\n"
507 "MaxComputeUniformComponents 1024\n"
508 "MaxComputeTextureImageUnits 16\n"
509 "MaxComputeImageUniforms 8\n"
510 "MaxComputeAtomicCounters 8\n"
511 "MaxComputeAtomicCounterBuffers 1\n"
512 "MaxVaryingComponents 60\n"
513 "MaxVertexOutputComponents 64\n"
514 "MaxGeometryInputComponents 64\n"
515 "MaxGeometryOutputComponents 128\n"
516 "MaxFragmentInputComponents 128\n"
517 "MaxImageUnits 8\n"
518 "MaxCombinedImageUnitsAndFragmentOutputs 8\n"
519 "MaxCombinedShaderOutputResources 8\n"
520 "MaxImageSamples 0\n"
521 "MaxVertexImageUniforms 0\n"
522 "MaxTessControlImageUniforms 0\n"
523 "MaxTessEvaluationImageUniforms 0\n"
524 "MaxGeometryImageUniforms 0\n"
525 "MaxFragmentImageUniforms 8\n"
526 "MaxCombinedImageUniforms 8\n"
527 "MaxGeometryTextureImageUnits 16\n"
528 "MaxGeometryOutputVertices 256\n"
529 "MaxGeometryTotalOutputComponents 1024\n"
530 "MaxGeometryUniformComponents 1024\n"
531 "MaxGeometryVaryingComponents 64\n"
532 "MaxTessControlInputComponents 128\n"
533 "MaxTessControlOutputComponents 128\n"
534 "MaxTessControlTextureImageUnits 16\n"
535 "MaxTessControlUniformComponents 1024\n"
536 "MaxTessControlTotalOutputComponents 4096\n"
537 "MaxTessEvaluationInputComponents 128\n"
538 "MaxTessEvaluationOutputComponents 128\n"
539 "MaxTessEvaluationTextureImageUnits 16\n"
540 "MaxTessEvaluationUniformComponents 1024\n"
541 "MaxTessPatchComponents 120\n"
542 "MaxPatchVertices 32\n"
543 "MaxTessGenLevel 64\n"
544 "MaxViewports 16\n"
545 "MaxVertexAtomicCounters 0\n"
546 "MaxTessControlAtomicCounters 0\n"
547 "MaxTessEvaluationAtomicCounters 0\n"
548 "MaxGeometryAtomicCounters 0\n"
549 "MaxFragmentAtomicCounters 8\n"
550 "MaxCombinedAtomicCounters 8\n"
551 "MaxAtomicCounterBindings 1\n"
552 "MaxVertexAtomicCounterBuffers 0\n"
553 "MaxTessControlAtomicCounterBuffers 0\n"
554 "MaxTessEvaluationAtomicCounterBuffers 0\n"
555 "MaxGeometryAtomicCounterBuffers 0\n"
556 "MaxFragmentAtomicCounterBuffers 1\n"
557 "MaxCombinedAtomicCounterBuffers 1\n"
558 "MaxAtomicCounterBufferSize 16384\n"
559 "MaxTransformFeedbackBuffers 4\n"
560 "MaxTransformFeedbackInterleavedComponents 64\n"
561 "MaxCullDistances 8\n"
562 "MaxCombinedClipAndCullDistances 8\n"
563 "MaxSamples 4\n"
564
565 "nonInductiveForLoops 1\n"
566 "whileLoops 1\n"
567 "doWhileLoops 1\n"
568 "generalUniformIndexing 1\n"
569 "generalAttributeMatrixVectorIndexing 1\n"
570 "generalVaryingIndexing 1\n"
571 "generalSamplerIndexing 1\n"
572 "generalVariableIndexing 1\n"
573 "generalConstantMatrixVectorIndexing 1\n"
574 ;
575
576//
577// *.conf => this is a config file that can set limits/resources
578//
579bool XglTestFramework::SetConfigFile(const std::string& name)
580{
581 if (name.size() < 5)
582 return false;
583
584 if (name.compare(name.size() - 5, 5, ".conf") == 0) {
585 ConfigFile = name;
586 return true;
587 }
588
589 return false;
590}
591
592//
593// Parse either a .conf file provided by the user or the default string above.
594//
595void XglTestFramework::ProcessConfigFile()
596{
597 char** configStrings = 0;
598 char* config = 0;
599 if (ConfigFile.size() > 0) {
600 configStrings = ReadFileData(ConfigFile.c_str());
601 if (configStrings)
602 config = *configStrings;
603 else {
604 printf("Error opening configuration file; will instead use the default configuration\n");
605 }
606 }
607
608 if (config == 0) {
609 config = new char[strlen(DefaultConfig) + 1];
610 strcpy(config, DefaultConfig);
611 }
612
613 const char* delims = " \t\n\r";
614 const char* token = strtok(config, delims);
615 while (token) {
616 const char* valueStr = strtok(0, delims);
617 if (valueStr == 0 || ! (valueStr[0] == '-' || (valueStr[0] >= '0' && valueStr[0] <= '9'))) {
618 printf("Error: '%s' bad .conf file. Each name must be followed by one number.\n", valueStr ? valueStr : "");
619 return;
620 }
621 int value = atoi(valueStr);
622
623 if (strcmp(token, "MaxLights") == 0)
624 Resources.maxLights = value;
625 else if (strcmp(token, "MaxClipPlanes") == 0)
626 Resources.maxClipPlanes = value;
627 else if (strcmp(token, "MaxTextureUnits") == 0)
628 Resources.maxTextureUnits = value;
629 else if (strcmp(token, "MaxTextureCoords") == 0)
630 Resources.maxTextureCoords = value;
631 else if (strcmp(token, "MaxVertexAttribs") == 0)
632 Resources.maxVertexAttribs = value;
633 else if (strcmp(token, "MaxVertexUniformComponents") == 0)
634 Resources.maxVertexUniformComponents = value;
635 else if (strcmp(token, "MaxVaryingFloats") == 0)
636 Resources.maxVaryingFloats = value;
637 else if (strcmp(token, "MaxVertexTextureImageUnits") == 0)
638 Resources.maxVertexTextureImageUnits = value;
639 else if (strcmp(token, "MaxCombinedTextureImageUnits") == 0)
640 Resources.maxCombinedTextureImageUnits = value;
641 else if (strcmp(token, "MaxTextureImageUnits") == 0)
642 Resources.maxTextureImageUnits = value;
643 else if (strcmp(token, "MaxFragmentUniformComponents") == 0)
644 Resources.maxFragmentUniformComponents = value;
645 else if (strcmp(token, "MaxDrawBuffers") == 0)
646 Resources.maxDrawBuffers = value;
647 else if (strcmp(token, "MaxVertexUniformVectors") == 0)
648 Resources.maxVertexUniformVectors = value;
649 else if (strcmp(token, "MaxVaryingVectors") == 0)
650 Resources.maxVaryingVectors = value;
651 else if (strcmp(token, "MaxFragmentUniformVectors") == 0)
652 Resources.maxFragmentUniformVectors = value;
653 else if (strcmp(token, "MaxVertexOutputVectors") == 0)
654 Resources.maxVertexOutputVectors = value;
655 else if (strcmp(token, "MaxFragmentInputVectors") == 0)
656 Resources.maxFragmentInputVectors = value;
657 else if (strcmp(token, "MinProgramTexelOffset") == 0)
658 Resources.minProgramTexelOffset = value;
659 else if (strcmp(token, "MaxProgramTexelOffset") == 0)
660 Resources.maxProgramTexelOffset = value;
661 else if (strcmp(token, "MaxClipDistances") == 0)
662 Resources.maxClipDistances = value;
663 else if (strcmp(token, "MaxComputeWorkGroupCountX") == 0)
664 Resources.maxComputeWorkGroupCountX = value;
665 else if (strcmp(token, "MaxComputeWorkGroupCountY") == 0)
666 Resources.maxComputeWorkGroupCountY = value;
667 else if (strcmp(token, "MaxComputeWorkGroupCountZ") == 0)
668 Resources.maxComputeWorkGroupCountZ = value;
669 else if (strcmp(token, "MaxComputeWorkGroupSizeX") == 0)
670 Resources.maxComputeWorkGroupSizeX = value;
671 else if (strcmp(token, "MaxComputeWorkGroupSizeY") == 0)
672 Resources.maxComputeWorkGroupSizeY = value;
673 else if (strcmp(token, "MaxComputeWorkGroupSizeZ") == 0)
674 Resources.maxComputeWorkGroupSizeZ = value;
675 else if (strcmp(token, "MaxComputeUniformComponents") == 0)
676 Resources.maxComputeUniformComponents = value;
677 else if (strcmp(token, "MaxComputeTextureImageUnits") == 0)
678 Resources.maxComputeTextureImageUnits = value;
679 else if (strcmp(token, "MaxComputeImageUniforms") == 0)
680 Resources.maxComputeImageUniforms = value;
681 else if (strcmp(token, "MaxComputeAtomicCounters") == 0)
682 Resources.maxComputeAtomicCounters = value;
683 else if (strcmp(token, "MaxComputeAtomicCounterBuffers") == 0)
684 Resources.maxComputeAtomicCounterBuffers = value;
685 else if (strcmp(token, "MaxVaryingComponents") == 0)
686 Resources.maxVaryingComponents = value;
687 else if (strcmp(token, "MaxVertexOutputComponents") == 0)
688 Resources.maxVertexOutputComponents = value;
689 else if (strcmp(token, "MaxGeometryInputComponents") == 0)
690 Resources.maxGeometryInputComponents = value;
691 else if (strcmp(token, "MaxGeometryOutputComponents") == 0)
692 Resources.maxGeometryOutputComponents = value;
693 else if (strcmp(token, "MaxFragmentInputComponents") == 0)
694 Resources.maxFragmentInputComponents = value;
695 else if (strcmp(token, "MaxImageUnits") == 0)
696 Resources.maxImageUnits = value;
697 else if (strcmp(token, "MaxCombinedImageUnitsAndFragmentOutputs") == 0)
698 Resources.maxCombinedImageUnitsAndFragmentOutputs = value;
699 else if (strcmp(token, "MaxCombinedShaderOutputResources") == 0)
700 Resources.maxCombinedShaderOutputResources = value;
701 else if (strcmp(token, "MaxImageSamples") == 0)
702 Resources.maxImageSamples = value;
703 else if (strcmp(token, "MaxVertexImageUniforms") == 0)
704 Resources.maxVertexImageUniforms = value;
705 else if (strcmp(token, "MaxTessControlImageUniforms") == 0)
706 Resources.maxTessControlImageUniforms = value;
707 else if (strcmp(token, "MaxTessEvaluationImageUniforms") == 0)
708 Resources.maxTessEvaluationImageUniforms = value;
709 else if (strcmp(token, "MaxGeometryImageUniforms") == 0)
710 Resources.maxGeometryImageUniforms = value;
711 else if (strcmp(token, "MaxFragmentImageUniforms") == 0)
712 Resources.maxFragmentImageUniforms = value;
713 else if (strcmp(token, "MaxCombinedImageUniforms") == 0)
714 Resources.maxCombinedImageUniforms = value;
715 else if (strcmp(token, "MaxGeometryTextureImageUnits") == 0)
716 Resources.maxGeometryTextureImageUnits = value;
717 else if (strcmp(token, "MaxGeometryOutputVertices") == 0)
718 Resources.maxGeometryOutputVertices = value;
719 else if (strcmp(token, "MaxGeometryTotalOutputComponents") == 0)
720 Resources.maxGeometryTotalOutputComponents = value;
721 else if (strcmp(token, "MaxGeometryUniformComponents") == 0)
722 Resources.maxGeometryUniformComponents = value;
723 else if (strcmp(token, "MaxGeometryVaryingComponents") == 0)
724 Resources.maxGeometryVaryingComponents = value;
725 else if (strcmp(token, "MaxTessControlInputComponents") == 0)
726 Resources.maxTessControlInputComponents = value;
727 else if (strcmp(token, "MaxTessControlOutputComponents") == 0)
728 Resources.maxTessControlOutputComponents = value;
729 else if (strcmp(token, "MaxTessControlTextureImageUnits") == 0)
730 Resources.maxTessControlTextureImageUnits = value;
731 else if (strcmp(token, "MaxTessControlUniformComponents") == 0)
732 Resources.maxTessControlUniformComponents = value;
733 else if (strcmp(token, "MaxTessControlTotalOutputComponents") == 0)
734 Resources.maxTessControlTotalOutputComponents = value;
735 else if (strcmp(token, "MaxTessEvaluationInputComponents") == 0)
736 Resources.maxTessEvaluationInputComponents = value;
737 else if (strcmp(token, "MaxTessEvaluationOutputComponents") == 0)
738 Resources.maxTessEvaluationOutputComponents = value;
739 else if (strcmp(token, "MaxTessEvaluationTextureImageUnits") == 0)
740 Resources.maxTessEvaluationTextureImageUnits = value;
741 else if (strcmp(token, "MaxTessEvaluationUniformComponents") == 0)
742 Resources.maxTessEvaluationUniformComponents = value;
743 else if (strcmp(token, "MaxTessPatchComponents") == 0)
744 Resources.maxTessPatchComponents = value;
745 else if (strcmp(token, "MaxPatchVertices") == 0)
746 Resources.maxPatchVertices = value;
747 else if (strcmp(token, "MaxTessGenLevel") == 0)
748 Resources.maxTessGenLevel = value;
749 else if (strcmp(token, "MaxViewports") == 0)
750 Resources.maxViewports = value;
751 else if (strcmp(token, "MaxVertexAtomicCounters") == 0)
752 Resources.maxVertexAtomicCounters = value;
753 else if (strcmp(token, "MaxTessControlAtomicCounters") == 0)
754 Resources.maxTessControlAtomicCounters = value;
755 else if (strcmp(token, "MaxTessEvaluationAtomicCounters") == 0)
756 Resources.maxTessEvaluationAtomicCounters = value;
757 else if (strcmp(token, "MaxGeometryAtomicCounters") == 0)
758 Resources.maxGeometryAtomicCounters = value;
759 else if (strcmp(token, "MaxFragmentAtomicCounters") == 0)
760 Resources.maxFragmentAtomicCounters = value;
761 else if (strcmp(token, "MaxCombinedAtomicCounters") == 0)
762 Resources.maxCombinedAtomicCounters = value;
763 else if (strcmp(token, "MaxAtomicCounterBindings") == 0)
764 Resources.maxAtomicCounterBindings = value;
765 else if (strcmp(token, "MaxVertexAtomicCounterBuffers") == 0)
766 Resources.maxVertexAtomicCounterBuffers = value;
767 else if (strcmp(token, "MaxTessControlAtomicCounterBuffers") == 0)
768 Resources.maxTessControlAtomicCounterBuffers = value;
769 else if (strcmp(token, "MaxTessEvaluationAtomicCounterBuffers") == 0)
770 Resources.maxTessEvaluationAtomicCounterBuffers = value;
771 else if (strcmp(token, "MaxGeometryAtomicCounterBuffers") == 0)
772 Resources.maxGeometryAtomicCounterBuffers = value;
773 else if (strcmp(token, "MaxFragmentAtomicCounterBuffers") == 0)
774 Resources.maxFragmentAtomicCounterBuffers = value;
775 else if (strcmp(token, "MaxCombinedAtomicCounterBuffers") == 0)
776 Resources.maxCombinedAtomicCounterBuffers = value;
777 else if (strcmp(token, "MaxAtomicCounterBufferSize") == 0)
778 Resources.maxAtomicCounterBufferSize = value;
779 else if (strcmp(token, "MaxTransformFeedbackBuffers") == 0)
780 Resources.maxTransformFeedbackBuffers = value;
781 else if (strcmp(token, "MaxTransformFeedbackInterleavedComponents") == 0)
782 Resources.maxTransformFeedbackInterleavedComponents = value;
783 else if (strcmp(token, "MaxCullDistances") == 0)
784 Resources.maxCullDistances = value;
785 else if (strcmp(token, "MaxCombinedClipAndCullDistances") == 0)
786 Resources.maxCombinedClipAndCullDistances = value;
787 else if (strcmp(token, "MaxSamples") == 0)
788 Resources.maxSamples = value;
789
790 else if (strcmp(token, "nonInductiveForLoops") == 0)
791 Resources.limits.nonInductiveForLoops = (value != 0);
792 else if (strcmp(token, "whileLoops") == 0)
793 Resources.limits.whileLoops = (value != 0);
794 else if (strcmp(token, "doWhileLoops") == 0)
795 Resources.limits.doWhileLoops = (value != 0);
796 else if (strcmp(token, "generalUniformIndexing") == 0)
797 Resources.limits.generalUniformIndexing = (value != 0);
798 else if (strcmp(token, "generalAttributeMatrixVectorIndexing") == 0)
799 Resources.limits.generalAttributeMatrixVectorIndexing = (value != 0);
800 else if (strcmp(token, "generalVaryingIndexing") == 0)
801 Resources.limits.generalVaryingIndexing = (value != 0);
802 else if (strcmp(token, "generalSamplerIndexing") == 0)
803 Resources.limits.generalSamplerIndexing = (value != 0);
804 else if (strcmp(token, "generalVariableIndexing") == 0)
805 Resources.limits.generalVariableIndexing = (value != 0);
806 else if (strcmp(token, "generalConstantMatrixVectorIndexing") == 0)
807 Resources.limits.generalConstantMatrixVectorIndexing = (value != 0);
808 else
809 printf("Warning: unrecognized limit (%s) in configuration file.\n", token);
810
811 token = strtok(0, delims);
812 }
813 if (configStrings)
814 FreeFileData(configStrings);
815}
816
817void XglTestFramework::SetMessageOptions(EShMessages& messages)
818{
819 if (m_compile_options & EOptionRelaxedErrors)
820 messages = (EShMessages)(messages | EShMsgRelaxedErrors);
821 if (m_compile_options & EOptionIntermediate)
822 messages = (EShMessages)(messages | EShMsgAST);
823 if (m_compile_options & EOptionSuppressWarnings)
824 messages = (EShMessages)(messages | EShMsgSuppressWarnings);
825}
826
827//
828// Malloc a string of sufficient size and read a string into it.
829//
830char** XglTestFramework::ReadFileData(const char* fileName)
831{
832 FILE *in;
833 #if defined(_WIN32) && defined(__GNUC__)
834 in = fopen(fileName, "r");
835 int errorCode = in ? 0 : 1;
836 #else
837 int errorCode = fopen_s(&in, fileName, "r");
838 #endif
839
840 char *fdata;
841 int count = 0;
842 const int maxSourceStrings = 5;
843 char** return_data = (char**)malloc(sizeof(char *) * (maxSourceStrings+1));
844
845 if (errorCode) {
846 printf("Error: unable to open input file: %s\n", fileName);
847 return 0;
848 }
849
850 while (fgetc(in) != EOF)
851 count++;
852
853 fseek(in, 0, SEEK_SET);
854
855 if (!(fdata = (char*)malloc(count+2))) {
856 printf("Error allocating memory\n");
857 return 0;
858 }
859 if (fread(fdata,1,count, in)!=count) {
860 printf("Error reading input file: %s\n", fileName);
861 return 0;
862 }
863 fdata[count] = '\0';
864 fclose(in);
865 if (count == 0) {
866 return_data[0]=(char*)malloc(count+2);
867 return_data[0][0]='\0';
868 m_num_shader_strings = 0;
869 return return_data;
870 } else
871 m_num_shader_strings = 1;
872
873 int len = (int)(ceil)((float)count/(float)m_num_shader_strings);
874 int ptr_len=0,i=0;
875 while(count>0){
876 return_data[i]=(char*)malloc(len+2);
877 memcpy(return_data[i],fdata+ptr_len,len);
878 return_data[i][len]='\0';
879 count-=(len);
880 ptr_len+=(len);
881 if(count<len){
882 if(count==0){
883 m_num_shader_strings=(i+1);
884 break;
885 }
886 len = count;
887 }
888 ++i;
889 }
890 return return_data;
891}
892
893void XglTestFramework::FreeFileData(char** data)
894{
895 for(int i=0;i<m_num_shader_strings;i++)
896 free(data[i]);
897}
898
899//
900// Deduce the language from the filename. Files must end in one of the
901// following extensions:
902//
903// .vert = vertex
904// .tesc = tessellation control
905// .tese = tessellation evaluation
906// .geom = geometry
907// .frag = fragment
908// .comp = compute
909//
910EShLanguage XglTestFramework::FindLanguage(const std::string& name)
911{
912 size_t ext = name.rfind('.');
913 if (ext == std::string::npos) {
914 return EShLangVertex;
915 }
916
917 std::string suffix = name.substr(ext + 1, std::string::npos);
918 if (suffix == "vert")
919 return EShLangVertex;
920 else if (suffix == "tesc")
921 return EShLangTessControl;
922 else if (suffix == "tese")
923 return EShLangTessEvaluation;
924 else if (suffix == "geom")
925 return EShLangGeometry;
926 else if (suffix == "frag")
927 return EShLangFragment;
928 else if (suffix == "comp")
929 return EShLangCompute;
930
931 return EShLangVertex;
932}
933
934//
935// Convert XGL shader type to compiler's
936//
937EShLanguage XglTestFramework::FindLanguage(const XGL_PIPELINE_SHADER_STAGE shader_type)
938{
939 switch (shader_type) {
940 case XGL_SHADER_STAGE_VERTEX:
941 return EShLangVertex;
942
943 case XGL_SHADER_STAGE_TESS_CONTROL:
944 return EShLangTessControl;
945
946 case XGL_SHADER_STAGE_TESS_EVALUATION:
947 return EShLangTessEvaluation;
948
949 case XGL_SHADER_STAGE_GEOMETRY:
950 return EShLangGeometry;
951
952 case XGL_SHADER_STAGE_FRAGMENT:
953 return EShLangFragment;
954
955 case XGL_SHADER_STAGE_COMPUTE:
956 return EShLangCompute;
957 }
958
959 return EShLangVertex;
960}
961
962
963//
964// Compile a given string containing GLSL into BIL for use by XGL
965// Return value of false means an error was encountered.
966//
967bool XglTestFramework::GLSLtoBIL(const XGL_PIPELINE_SHADER_STAGE shader_type,
968 const char *pshader,
969 std::vector<unsigned int> &bil)
970{
971 glslang::TProgram& program = *new glslang::TProgram;
972 const char *shaderStrings[1];
973
974 // TODO: Do we want to load a special config file depending on the
975 // shader source? Optional name maybe?
976 // SetConfigFile(fileName);
977
978 ProcessConfigFile();
979
980 EShMessages messages = EShMsgDefault;
981 SetMessageOptions(messages);
982
983 EShLanguage stage = FindLanguage(shader_type);
984 glslang::TShader* shader = new glslang::TShader(stage);
985
986 shaderStrings[0] = pshader;
987 shader->setStrings(shaderStrings, 1);
988
989 if (! shader->parse(&Resources, (m_compile_options & EOptionDefaultDesktop) ? 110 : 100, false, messages)) {
990
Cody Northrop195d6622014-11-03 12:54:37 -0700991 if (! (m_compile_options & EOptionSuppressInfolog)) {
992 puts(shader->getInfoLog());
993 puts(shader->getInfoDebugLog());
994 }
995
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -0600996 return false; // something didn't work
997 }
998
999 program.addShader(shader);
1000
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -06001001
1002 //
1003 // Program-level processing...
1004 //
1005
Cody Northrop195d6622014-11-03 12:54:37 -07001006 if (! program.link(messages)) {
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -06001007
Cody Northrop195d6622014-11-03 12:54:37 -07001008 if (! (m_compile_options & EOptionSuppressInfolog)) {
1009 puts(shader->getInfoLog());
1010 puts(shader->getInfoDebugLog());
1011 }
1012
1013 return false;
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -06001014 }
1015
1016 if (m_compile_options & EOptionDumpReflection) {
1017 program.buildReflection();
1018 program.dumpReflection();
1019 }
1020
1021 glslang::GlslangToBil(*program.getIntermediate(stage), bil);
1022
1023 return true;
1024}
1025
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -06001026
1027
1028XglTestImageRecord::XglTestImageRecord() : // Constructor
1029 m_width( 0 ),
1030 m_height( 0 ),
1031 m_data( NULL )
1032{
1033 m_data_size = 0;
1034}
1035
1036XglTestImageRecord::~XglTestImageRecord()
1037{
1038
1039}
1040
1041XglTestImageRecord::XglTestImageRecord(const XglTestImageRecord &copyin) // Copy constructor to handle pass by value.
1042{
1043 m_title = copyin.m_title;
1044 m_width = copyin.m_width;
1045 m_height = copyin.m_height;
1046 m_data_size = copyin.m_data_size;
1047 m_data = copyin.m_data; // TODO: Do we need to copy the data or is pointer okay?
1048}
1049
1050ostream &operator<<(ostream &output, const XglTestImageRecord &XglTestImageRecord)
1051{
1052 output << XglTestImageRecord.m_title << " (" << XglTestImageRecord.m_width <<
1053 "," << XglTestImageRecord.m_height << ")" << endl;
1054 return output;
1055}
1056
1057XglTestImageRecord& XglTestImageRecord::operator=(const XglTestImageRecord &rhs)
1058{
1059 m_title = rhs.m_title;
1060 m_width = rhs.m_width;
1061 m_height = rhs.m_height;
1062 m_data_size = rhs.m_data_size;
1063 m_data = rhs.m_data;
1064 return *this;
1065}
1066
1067int XglTestImageRecord::operator==(const XglTestImageRecord &rhs) const
1068{
1069 if( this->m_data != rhs.m_data) return 0;
1070 return 1;
1071}
1072
1073// This function is required for built-in STL list functions like sort
1074int XglTestImageRecord::operator<(const XglTestImageRecord &rhs) const
1075{
1076 if( this->m_data_size < rhs.m_data_size ) return 1;
1077 return 0;
1078}
1079