blob: f2722457452d1a41d3ea5e03260fa81e2a95e501 [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"
Chia-I Wua6bc0ce2014-12-29 14:38:28 +080024#include "xglrenderframework.h"
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -060025#include "GL/freeglut_std.h"
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -060026//#include "ShaderLang.h"
27#include "GlslangToBil.h"
Tony Barbour4ab45422014-12-10 17:00:20 -070028#include <limits.h>
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -060029#include <math.h>
Chia-I Wuec664fa2014-12-02 11:54:24 +080030#include <wand/MagickWand.h>
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -060031
32// Command-line options
33enum TOptions {
34 EOptionNone = 0x000,
35 EOptionIntermediate = 0x001,
36 EOptionSuppressInfolog = 0x002,
37 EOptionMemoryLeakMode = 0x004,
38 EOptionRelaxedErrors = 0x008,
39 EOptionGiveWarnings = 0x010,
40 EOptionLinkProgram = 0x020,
41 EOptionMultiThreaded = 0x040,
42 EOptionDumpConfig = 0x080,
43 EOptionDumpReflection = 0x100,
44 EOptionSuppressWarnings = 0x200,
45 EOptionDumpVersions = 0x400,
46 EOptionBil = 0x800,
47 EOptionDefaultDesktop = 0x1000,
48};
49
50#ifndef _WIN32
51
52#include <errno.h>
53
54int fopen_s(
55 FILE** pFile,
56 const char* filename,
57 const char* mode
58)
59{
60 if (!pFile || !filename || !mode) {
61 return EINVAL;
62 }
63
64 FILE* f = fopen(filename, mode);
65 if (! f) {
66 if (errno != 0) {
67 return errno;
68 } else {
69 return ENOENT;
70 }
71 }
72 *pFile = f;
73
74 return 0;
75}
76
77#endif
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -060078
Courtney Goeltzenleuchtera0f74c52014-10-08 08:46:51 -060079// Set up environment for GLSL compiler
80// Must be done once per process
81void TestEnvironment::SetUp()
82{
83 // Initialize GLSL to BIL compiler utility
84 glslang::InitializeProcess();
Chia-I Wub76e0fa2014-12-28 14:27:28 +080085
86 xgl_testing::set_error_callback(test_error_callback);
Courtney Goeltzenleuchtera0f74c52014-10-08 08:46:51 -060087}
88
89void TestEnvironment::TearDown()
90{
91 glslang::FinalizeProcess();
92}
93
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -060094XglTestFramework::XglTestFramework() :
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -060095 m_compile_options( 0 ),
96 m_num_shader_strings( 0 )
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -060097{
Courtney Goeltzenleuchtera0f74c52014-10-08 08:46:51 -060098
Courtney Goeltzenleuchter9818f782014-10-03 09:53:32 -060099}
100
101XglTestFramework::~XglTestFramework()
102{
Courtney Goeltzenleuchtera0f74c52014-10-08 08:46:51 -0600103
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600104}
105
106// Define all the static elements
107bool XglTestFramework::m_show_images = false;
108bool XglTestFramework::m_save_images = false;
Tony Barbour247bf372014-10-30 14:29:04 -0600109bool XglTestFramework::m_compare_images = false;
Courtney Goeltzenleuchterc44e3ee2014-10-31 14:13:33 -0600110bool XglTestFramework::m_use_bil = true;
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600111int XglTestFramework::m_width = 0;
112int XglTestFramework::m_height = 0;
113int XglTestFramework::m_window = 0;
Courtney Goeltzenleuchter02d33c12014-10-08 14:26:40 -0600114bool XglTestFramework::m_glut_initialized = false;
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600115std::list<XglTestImageRecord> XglTestFramework::m_images;
116std::list<XglTestImageRecord>::iterator XglTestFramework::m_display_image;
117int m_display_image_idx = 0;
118
119void XglTestFramework::InitArgs(int *argc, char *argv[])
120{
121 int i, n;
122
123 for (i=0, n=0; i< *argc; i++) {
124 if (strncmp("--show-images", argv[i], 13) == 0) {
125 m_show_images = true;
126 continue;
127 }
128 if (strncmp("--save-images", argv[i], 13) == 0) {
129 m_save_images = true;
130 continue;
131 }
132
Courtney Goeltzenleuchterb666dc62014-10-09 09:13:56 -0600133 if (strncmp("--use-BIL", argv[i], 13) == 0) {
134 m_use_bil = true;
135 continue;
136 }
137
Courtney Goeltzenleuchterc44e3ee2014-10-31 14:13:33 -0600138 if (strncmp("--no-BIL", argv[i], 13) == 0) {
139 m_use_bil = false;
140 continue;
141 }
142
Tony Barbour247bf372014-10-30 14:29:04 -0600143 if (strncmp("--compare-images", argv[i], 16) == 0) {
144 m_compare_images = true;
145 continue;
146 }
147
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600148 /*
149 * Since the above "consume" inputs, update argv
150 * so that it contains the trimmed list of args for glutInit
151 */
Tony Barboura98d3932014-12-11 09:52:49 -0700152 if (strncmp("--help", argv[i], 6) == 0 || strncmp("-h", argv[i], 2) == 0) {
Courtney Goeltzenleuchter31144b72014-12-02 13:13:10 -0700153 printf("\nOther options:\n");
154 printf("\t--show-images\n"
155 "\t\tDisplay test images in viewer after tests complete.\n");
156 printf("\t--save-images\n"
157 "\t\tSave tests images as ppm files in current working directory.\n"
158 "\t\tUsed to generate golden images for compare-images.\n");
159 printf("\t--compare-images\n"
160 "\t\tCompare test images to 'golden' image in golden folder.\n"
Tony Barboura98d3932014-12-11 09:52:49 -0700161 "\t\tAlso saves the generated test image in current working\n"
162 "\t\t\tdirectory but only if the image is different from the golden\n"
163 "\t\tSetting RENDERTEST_GOLDEN_DIR environment variable can specify\n"
164 "\t\t\tdifferent directory for golden images\n"
Courtney Goeltzenleuchter31144b72014-12-02 13:13:10 -0700165 "\t\tSignal test failure if different.\n");
166 printf("\t--use-BIL\n"
167 "\t\tUse BIL code path (default).\n");
168 printf("\t--no-BIL\n"
169 "\t\tUse built-in GLSL compiler rather than BIL code path.\n");
Tony Barbour4ab45422014-12-10 17:00:20 -0700170 exit(0);
Courtney Goeltzenleuchter31144b72014-12-02 13:13:10 -0700171 }
172
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600173 argv[n] = argv[i];
174 n++;
175 }
176
177 if (m_show_images) {
178 glutInit(argc, argv);
179 }
180}
181
182void XglTestFramework::Reshape( int w, int h )
183{
184 if (!m_show_images) return; // Do nothing except save info if not enabled
185
186 // Resize window to be large enough to handle biggest image we've seen
187 // TODO: Probably need some sort of limits for the Window system.
188 if (w > m_width) {
189 m_width = w;
190 }
191 if (h > m_height) {
192 m_height = h;
193 }
194
195 glutReshapeWindow(m_width, m_height);
196
197 glViewport( 0, 0, m_width, m_height );
198 glMatrixMode( GL_PROJECTION );
199 glLoadIdentity();
200 glOrtho( 0.0, m_width, 0.0, m_height, 0.0, 2.0 );
201 glMatrixMode( GL_MODELVIEW );
202 glLoadIdentity();
203
204// glScissor(width/4, height/4, width/2, height/2);
205}
206
207void XglTestFramework::WritePPM( const char *basename, XglImage *image )
208{
209 string filename;
210 XGL_RESULT err;
Courtney Goeltzenleuchter02d33c12014-10-08 14:26:40 -0600211 int x, y;
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600212
213 filename.append(basename);
214 filename.append(".ppm");
215
216 const XGL_IMAGE_SUBRESOURCE sr = {
217 XGL_IMAGE_ASPECT_COLOR, 0, 0
218 };
219 XGL_SUBRESOURCE_LAYOUT sr_layout;
Chia-I Wu99ff89d2014-12-27 14:14:50 +0800220 size_t data_size = sizeof(sr_layout);
Courtney Goeltzenleuchter30e9dc42014-09-04 16:24:19 -0600221
222 err = xglGetImageSubresourceInfo( image->image(), &sr,
223 XGL_INFO_TYPE_SUBRESOURCE_LAYOUT,
224 &data_size, &sr_layout);
225 ASSERT_XGL_SUCCESS( err );
226 ASSERT_EQ(data_size, sizeof(sr_layout));
227
228 const char *ptr;
229
230 err = xglMapMemory( image->memory(), 0, (XGL_VOID **) &ptr );
231 ASSERT_XGL_SUCCESS( err );
232
233 ptr += sr_layout.offset;
234
235 ofstream file (filename.c_str());
236 ASSERT_TRUE(file.is_open()) << "Unable to open file: " << filename;
237
238 file << "P6\n";
239 file << image->width() << "\n";
240 file << image->height() << "\n";
241 file << 255 << "\n";
242
243 for (y = 0; y < image->height(); y++) {
244 const char *row = ptr;
245
246 for (x = 0; x < image->width(); x++) {
247 file.write(row, 3);
248 row += 4;
249 }
250
251 ptr += sr_layout.rowPitch;
252 }
253
254 file.close();
255
256 err = xglUnmapMemory( image->memory() );
257 ASSERT_XGL_SUCCESS( err );
258}
259
260void XglTestFramework::InitGLUT(int w, int h)
261{
262
263 if (!m_show_images) return;
264
265 if (!m_glut_initialized) {
266 glutInitWindowSize(w, h);
267
268 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
269 m_window = glutCreateWindow(NULL);
270 m_glut_initialized = true;
271 }
272
273 Reshape(w, h);
274}
Tony Barbour247bf372014-10-30 14:29:04 -0600275void XglTestFramework::Compare(const char *basename, XglImage *image )
276{
277
278 MagickWand *magick_wand_1;
279 MagickWand *magick_wand_2;
280 MagickWand *compare_wand;
281 MagickBooleanType status;
Tony Barbour4ab45422014-12-10 17:00:20 -0700282 char testimage[256],golden[PATH_MAX+256],golddir[PATH_MAX] = "./golden";
Tony Barbour247bf372014-10-30 14:29:04 -0600283 double differenz;
284
Tony Barbour4ab45422014-12-10 17:00:20 -0700285 if (getenv("RENDERTEST_GOLDEN_DIR"))
286 {
287 strcpy(golddir,getenv("RENDERTEST_GOLDEN_DIR"));
288 }
289
Tony Barbour247bf372014-10-30 14:29:04 -0600290 MagickWandGenesis();
291 magick_wand_1=NewMagickWand();
292 sprintf(testimage,"%s.ppm",basename);
293 status=MagickReadImage(magick_wand_1,testimage);
294 ASSERT_TRUE(status) << "Unable to open file: " << testimage;
295
296
297 MagickWandGenesis();
298 magick_wand_2=NewMagickWand();
Tony Barbour4ab45422014-12-10 17:00:20 -0700299 sprintf(golden,"%s/%s.ppm",golddir,basename);
Tony Barbour247bf372014-10-30 14:29:04 -0600300 status=MagickReadImage(magick_wand_2,golden);
301 ASSERT_TRUE(status) << "Unable to open file: " << golden;
302
Tony Barbour247bf372014-10-30 14:29:04 -0600303 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