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