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