Home | History | Annotate | Download | only in tests
      1 /*
      2  * Copyright (c) 2015-2016 The Khronos Group Inc.
      3  * Copyright (c) 2015-2016 Valve Corporation
      4  * Copyright (c) 2015-2016 LunarG, Inc.
      5  *
      6  * Licensed under the Apache License, Version 2.0 (the "License");
      7  * you may not use this file except in compliance with the License.
      8  * You may obtain a copy of the License at
      9  *
     10  *     http://www.apache.org/licenses/LICENSE-2.0
     11  *
     12  * Unless required by applicable law or agreed to in writing, software
     13  * distributed under the License is distributed on an "AS IS" BASIS,
     14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     15  * See the License for the specific language governing permissions and
     16  * limitations under the License.
     17  *
     18  * Author: Chia-I Wu <olvaffe (at) gmail.com>
     19  * Author: Courtney Goeltzenleuchter <courtney (at) LunarG.com>
     20  * Author: Tony Barbour <tony (at) LunarG.com>
     21  */
     22 
     23 #include "vktestframework.h"
     24 #include "vkrenderframework.h"
     25 // TODO FIXME remove this once glslang doesn't define this
     26 #undef BadValue
     27 #include "SPIRV/GlslangToSpv.h"
     28 #include "SPIRV/SPVRemapper.h"
     29 #include <limits.h>
     30 #include <math.h>
     31 
     32 #if defined(PATH_MAX) && !defined(MAX_PATH)
     33 #define MAX_PATH PATH_MAX
     34 #endif
     35 
     36 #ifdef _WIN32
     37 #define ERR_EXIT(err_msg, err_class)                                                                                               \
     38     do {                                                                                                                           \
     39         MessageBox(NULL, err_msg, err_class, MB_OK);                                                                               \
     40         exit(1);                                                                                                                   \
     41     } while (0)
     42 #else // _WIN32
     43 
     44 #define ERR_EXIT(err_msg, err_class)                                                                                               \
     45     do {                                                                                                                           \
     46         printf(err_msg);                                                                                                           \
     47         fflush(stdout);                                                                                                            \
     48         exit(1);                                                                                                                   \
     49     } while (0)
     50 #endif // _WIN32
     51 
     52 #define GET_INSTANCE_PROC_ADDR(inst, entrypoint)                                                                                   \
     53     {                                                                                                                              \
     54         m_fp##entrypoint = (PFN_vk##entrypoint)vkGetInstanceProcAddr(inst, "vk" #entrypoint);                                      \
     55         if (m_fp##entrypoint == NULL) {                                                                                            \
     56             ERR_EXIT("vkGetInstanceProcAddr failed to find vk" #entrypoint, "vkGetInstanceProcAddr Failure");                      \
     57         }                                                                                                                          \
     58     }
     59 
     60 #define GET_DEVICE_PROC_ADDR(dev, entrypoint)                                                                                      \
     61     {                                                                                                                              \
     62         m_fp##entrypoint = (PFN_vk##entrypoint)vkGetDeviceProcAddr(dev, "vk" #entrypoint);                                         \
     63         if (m_fp##entrypoint == NULL) {                                                                                            \
     64             ERR_EXIT("vkGetDeviceProcAddr failed to find vk" #entrypoint, "vkGetDeviceProcAddr Failure");                          \
     65         }                                                                                                                          \
     66     }
     67 
     68 // Command-line options
     69 enum TOptions {
     70     EOptionNone = 0x000,
     71     EOptionIntermediate = 0x001,
     72     EOptionSuppressInfolog = 0x002,
     73     EOptionMemoryLeakMode = 0x004,
     74     EOptionRelaxedErrors = 0x008,
     75     EOptionGiveWarnings = 0x010,
     76     EOptionLinkProgram = 0x020,
     77     EOptionMultiThreaded = 0x040,
     78     EOptionDumpConfig = 0x080,
     79     EOptionDumpReflection = 0x100,
     80     EOptionSuppressWarnings = 0x200,
     81     EOptionDumpVersions = 0x400,
     82     EOptionSpv = 0x800,
     83     EOptionDefaultDesktop = 0x1000,
     84 };
     85 
     86 struct SwapchainBuffers {
     87     VkImage image;
     88     VkCommandBuffer cmd;
     89     VkImageView view;
     90 };
     91 
     92 #ifndef _WIN32
     93 
     94 #include <errno.h>
     95 
     96 int fopen_s(FILE **pFile, const char *filename, const char *mode) {
     97     if (!pFile || !filename || !mode) {
     98         return EINVAL;
     99     }
    100 
    101     FILE *f = fopen(filename, mode);
    102     if (!f) {
    103         if (errno != 0) {
    104             return errno;
    105         } else {
    106             return ENOENT;
    107         }
    108     }
    109     *pFile = f;
    110 
    111     return 0;
    112 }
    113 
    114 #endif
    115 
    116 // Set up environment for GLSL compiler
    117 // Must be done once per process
    118 void TestEnvironment::SetUp() {
    119     // Initialize GLSL to SPV compiler utility
    120     glslang::InitializeProcess();
    121 
    122     vk_testing::set_error_callback(test_error_callback);
    123 }
    124 
    125 void TestEnvironment::TearDown() { glslang::FinalizeProcess(); }
    126 
    127 VkTestFramework::VkTestFramework() : m_compile_options(0), m_num_shader_strings(0) {}
    128 
    129 VkTestFramework::~VkTestFramework() {}
    130 
    131 // Define all the static elements
    132 bool VkTestFramework::m_use_glsl = false;
    133 bool VkTestFramework::m_canonicalize_spv = false;
    134 bool VkTestFramework::m_strip_spv = false;
    135 bool VkTestFramework::m_do_everything_spv = false;
    136 int VkTestFramework::m_width = 0;
    137 int VkTestFramework::m_height = 0;
    138 
    139 bool VkTestFramework::optionMatch(const char *option, char *optionLine) {
    140     if (strncmp(option, optionLine, strlen(option)) == 0)
    141         return true;
    142     else
    143         return false;
    144 }
    145 
    146 void VkTestFramework::InitArgs(int *argc, char *argv[]) {
    147     int i, n;
    148 
    149     for (i = 1, n = 1; i < *argc; i++) {
    150         if (optionMatch("--no-SPV", argv[i]))
    151             m_use_glsl = true;
    152         else if (optionMatch("--strip-SPV", argv[i]))
    153             m_strip_spv = true;
    154         else if (optionMatch("--canonicalize-SPV", argv[i]))
    155             m_canonicalize_spv = true;
    156         else if (optionMatch("--help", argv[i]) || optionMatch("-h", argv[i])) {
    157             printf("\nOther options:\n");
    158             printf("\t--show-images\n"
    159                    "\t\tDisplay test images in viewer after tests complete.\n");
    160             printf("\t--save-images\n"
    161                    "\t\tSave tests images as ppm files in current working "
    162                    "directory.\n"
    163                    "\t\tUsed to generate golden images for compare-images.\n");
    164             printf("\t--compare-images\n"
    165                    "\t\tCompare test images to 'golden' image in golden folder.\n"
    166                    "\t\tAlso saves the generated test image in current working\n"
    167                    "\t\t\tdirectory but only if the image is different from the "
    168                    "golden\n"
    169                    "\t\tSetting RENDERTEST_GOLDEN_DIR environment variable can "
    170                    "specify\n"
    171                    "\t\t\tdifferent directory for golden images\n"
    172                    "\t\tSignal test failure if different.\n");
    173             printf("\t--no-SPV\n"
    174                    "\t\tUse built-in GLSL compiler rather than SPV code path.\n");
    175             printf("\t--strip-SPV\n"
    176                    "\t\tStrip SPIR-V debug information (line numbers, names, "
    177                    "etc).\n");
    178             printf("\t--canonicalize-SPV\n"
    179                    "\t\tRemap SPIR-V ids before submission to aid compression.\n");
    180             exit(0);
    181         } else {
    182             printf("\nUnrecognized option: %s\n", argv[i]);
    183             printf("\nUse --help or -h for option list.\n");
    184             exit(0);
    185         }
    186 
    187         /*
    188          * Since the above "consume" inputs, update argv
    189          * so that it contains the trimmed list of args for glutInit
    190          */
    191 
    192         argv[n] = argv[i];
    193         n++;
    194     }
    195 }
    196 
    197 VkFormat VkTestFramework::GetFormat(VkInstance instance, vk_testing::Device *device) {
    198     VkFormatProperties format_props;
    199 
    200     vkGetPhysicalDeviceFormatProperties(device->phy().handle(), VK_FORMAT_B8G8R8A8_UNORM, &format_props);
    201     if (format_props.linearTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT ||
    202         format_props.optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) {
    203         return VK_FORMAT_B8G8R8A8_UNORM;
    204     }
    205     vkGetPhysicalDeviceFormatProperties(device->phy().handle(), VK_FORMAT_R8G8B8A8_UNORM, &format_props);
    206     if (format_props.linearTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT ||
    207         format_props.optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) {
    208         return VK_FORMAT_R8G8B8A8_UNORM;
    209     }
    210     printf("Error - device does not support VK_FORMAT_B8G8R8A8_UNORM nor "
    211            "VK_FORMAT_R8G8B8A8_UNORM - exiting\n");
    212     exit(1);
    213 }
    214 
    215 void VkTestFramework::Finish() {}
    216 
    217 //
    218 // These are the default resources for TBuiltInResources, used for both
    219 //  - parsing this string for the case where the user didn't supply one
    220 //  - dumping out a template for user construction of a config file
    221 //
    222 static const char *DefaultConfig = "MaxLights 32\n"
    223                                    "MaxClipPlanes 6\n"
    224                                    "MaxTextureUnits 32\n"
    225                                    "MaxTextureCoords 32\n"
    226                                    "MaxVertexAttribs 64\n"
    227                                    "MaxVertexUniformComponents 4096\n"
    228                                    "MaxVaryingFloats 64\n"
    229                                    "MaxVertexTextureImageUnits 32\n"
    230                                    "MaxCombinedTextureImageUnits 80\n"
    231                                    "MaxTextureImageUnits 32\n"
    232                                    "MaxFragmentUniformComponents 4096\n"
    233                                    "MaxDrawBuffers 32\n"
    234                                    "MaxVertexUniformVectors 128\n"
    235                                    "MaxVaryingVectors 8\n"
    236                                    "MaxFragmentUniformVectors 16\n"
    237                                    "MaxVertexOutputVectors 16\n"
    238                                    "MaxFragmentInputVectors 15\n"
    239                                    "MinProgramTexelOffset -8\n"
    240                                    "MaxProgramTexelOffset 7\n"
    241                                    "MaxClipDistances 8\n"
    242                                    "MaxComputeWorkGroupCountX 65535\n"
    243                                    "MaxComputeWorkGroupCountY 65535\n"
    244                                    "MaxComputeWorkGroupCountZ 65535\n"
    245                                    "MaxComputeWorkGroupSizeX 1024\n"
    246                                    "MaxComputeWorkGroupSizeY 1024\n"
    247                                    "MaxComputeWorkGroupSizeZ 64\n"
    248                                    "MaxComputeUniformComponents 1024\n"
    249                                    "MaxComputeTextureImageUnits 16\n"
    250                                    "MaxComputeImageUniforms 8\n"
    251                                    "MaxComputeAtomicCounters 8\n"
    252                                    "MaxComputeAtomicCounterBuffers 1\n"
    253                                    "MaxVaryingComponents 60\n"
    254                                    "MaxVertexOutputComponents 64\n"
    255                                    "MaxGeometryInputComponents 64\n"
    256                                    "MaxGeometryOutputComponents 128\n"
    257                                    "MaxFragmentInputComponents 128\n"
    258                                    "MaxImageUnits 8\n"
    259                                    "MaxCombinedImageUnitsAndFragmentOutputs 8\n"
    260                                    "MaxCombinedShaderOutputResources 8\n"
    261                                    "MaxImageSamples 0\n"
    262                                    "MaxVertexImageUniforms 0\n"
    263                                    "MaxTessControlImageUniforms 0\n"
    264                                    "MaxTessEvaluationImageUniforms 0\n"
    265                                    "MaxGeometryImageUniforms 0\n"
    266                                    "MaxFragmentImageUniforms 8\n"
    267                                    "MaxCombinedImageUniforms 8\n"
    268                                    "MaxGeometryTextureImageUnits 16\n"
    269                                    "MaxGeometryOutputVertices 256\n"
    270                                    "MaxGeometryTotalOutputComponents 1024\n"
    271                                    "MaxGeometryUniformComponents 1024\n"
    272                                    "MaxGeometryVaryingComponents 64\n"
    273                                    "MaxTessControlInputComponents 128\n"
    274                                    "MaxTessControlOutputComponents 128\n"
    275                                    "MaxTessControlTextureImageUnits 16\n"
    276                                    "MaxTessControlUniformComponents 1024\n"
    277                                    "MaxTessControlTotalOutputComponents 4096\n"
    278                                    "MaxTessEvaluationInputComponents 128\n"
    279                                    "MaxTessEvaluationOutputComponents 128\n"
    280                                    "MaxTessEvaluationTextureImageUnits 16\n"
    281                                    "MaxTessEvaluationUniformComponents 1024\n"
    282                                    "MaxTessPatchComponents 120\n"
    283                                    "MaxPatchVertices 32\n"
    284                                    "MaxTessGenLevel 64\n"
    285                                    "MaxViewports 16\n"
    286                                    "MaxVertexAtomicCounters 0\n"
    287                                    "MaxTessControlAtomicCounters 0\n"
    288                                    "MaxTessEvaluationAtomicCounters 0\n"
    289                                    "MaxGeometryAtomicCounters 0\n"
    290                                    "MaxFragmentAtomicCounters 8\n"
    291                                    "MaxCombinedAtomicCounters 8\n"
    292                                    "MaxAtomicCounterBindings 1\n"
    293                                    "MaxVertexAtomicCounterBuffers 0\n"
    294                                    "MaxTessControlAtomicCounterBuffers 0\n"
    295                                    "MaxTessEvaluationAtomicCounterBuffers 0\n"
    296                                    "MaxGeometryAtomicCounterBuffers 0\n"
    297                                    "MaxFragmentAtomicCounterBuffers 1\n"
    298                                    "MaxCombinedAtomicCounterBuffers 1\n"
    299                                    "MaxAtomicCounterBufferSize 16384\n"
    300                                    "MaxTransformFeedbackBuffers 4\n"
    301                                    "MaxTransformFeedbackInterleavedComponents 64\n"
    302                                    "MaxCullDistances 8\n"
    303                                    "MaxCombinedClipAndCullDistances 8\n"
    304                                    "MaxSamples 4\n"
    305 
    306                                    "nonInductiveForLoops 1\n"
    307                                    "whileLoops 1\n"
    308                                    "doWhileLoops 1\n"
    309                                    "generalUniformIndexing 1\n"
    310                                    "generalAttributeMatrixVectorIndexing 1\n"
    311                                    "generalVaryingIndexing 1\n"
    312                                    "generalSamplerIndexing 1\n"
    313                                    "generalVariableIndexing 1\n"
    314                                    "generalConstantMatrixVectorIndexing 1\n";
    315 
    316 //
    317 // *.conf => this is a config file that can set limits/resources
    318 //
    319 bool VkTestFramework::SetConfigFile(const std::string &name) {
    320     if (name.size() < 5)
    321         return false;
    322 
    323     if (name.compare(name.size() - 5, 5, ".conf") == 0) {
    324         ConfigFile = name;
    325         return true;
    326     }
    327 
    328     return false;
    329 }
    330 
    331 //
    332 // Parse either a .conf file provided by the user or the default string above.
    333 //
    334 void VkTestFramework::ProcessConfigFile() {
    335     char **configStrings = 0;
    336     char *config = 0;
    337     if (ConfigFile.size() > 0) {
    338         configStrings = ReadFileData(ConfigFile.c_str());
    339         if (configStrings)
    340             config = *configStrings;
    341         else {
    342             printf("Error opening configuration file; will instead use the "
    343                    "default configuration\n");
    344         }
    345     }
    346 
    347     if (config == 0) {
    348         config = (char *)alloca(strlen(DefaultConfig) + 1);
    349         strcpy(config, DefaultConfig);
    350     }
    351 
    352     const char *delims = " \t\n\r";
    353     const char *token = strtok(config, delims);
    354     while (token) {
    355         const char *valueStr = strtok(0, delims);
    356         if (valueStr == 0 || !(valueStr[0] == '-' || (valueStr[0] >= '0' && valueStr[0] <= '9'))) {
    357             printf("Error: '%s' bad .conf file.  Each name must be followed by "
    358                    "one number.\n",
    359                    valueStr ? valueStr : "");
    360             return;
    361         }
    362         int value = atoi(valueStr);
    363 
    364         if (strcmp(token, "MaxLights") == 0)
    365             Resources.maxLights = value;
    366         else if (strcmp(token, "MaxClipPlanes") == 0)
    367             Resources.maxClipPlanes = value;
    368         else if (strcmp(token, "MaxTextureUnits") == 0)
    369             Resources.maxTextureUnits = value;
    370         else if (strcmp(token, "MaxTextureCoords") == 0)
    371             Resources.maxTextureCoords = value;
    372         else if (strcmp(token, "MaxVertexAttribs") == 0)
    373             Resources.maxVertexAttribs = value;
    374         else if (strcmp(token, "MaxVertexUniformComponents") == 0)
    375             Resources.maxVertexUniformComponents = value;
    376         else if (strcmp(token, "MaxVaryingFloats") == 0)
    377             Resources.maxVaryingFloats = value;
    378         else if (strcmp(token, "MaxVertexTextureImageUnits") == 0)
    379             Resources.maxVertexTextureImageUnits = value;
    380         else if (strcmp(token, "MaxCombinedTextureImageUnits") == 0)
    381             Resources.maxCombinedTextureImageUnits = value;
    382         else if (strcmp(token, "MaxTextureImageUnits") == 0)
    383             Resources.maxTextureImageUnits = value;
    384         else if (strcmp(token, "MaxFragmentUniformComponents") == 0)
    385             Resources.maxFragmentUniformComponents = value;
    386         else if (strcmp(token, "MaxDrawBuffers") == 0)
    387             Resources.maxDrawBuffers = value;
    388         else if (strcmp(token, "MaxVertexUniformVectors") == 0)
    389             Resources.maxVertexUniformVectors = value;
    390         else if (strcmp(token, "MaxVaryingVectors") == 0)
    391             Resources.maxVaryingVectors = value;
    392         else if (strcmp(token, "MaxFragmentUniformVectors") == 0)
    393             Resources.maxFragmentUniformVectors = value;
    394         else if (strcmp(token, "MaxVertexOutputVectors") == 0)
    395             Resources.maxVertexOutputVectors = value;
    396         else if (strcmp(token, "MaxFragmentInputVectors") == 0)
    397             Resources.maxFragmentInputVectors = value;
    398         else if (strcmp(token, "MinProgramTexelOffset") == 0)
    399             Resources.minProgramTexelOffset = value;
    400         else if (strcmp(token, "MaxProgramTexelOffset") == 0)
    401             Resources.maxProgramTexelOffset = value;
    402         else if (strcmp(token, "MaxClipDistances") == 0)
    403             Resources.maxClipDistances = value;
    404         else if (strcmp(token, "MaxComputeWorkGroupCountX") == 0)
    405             Resources.maxComputeWorkGroupCountX = value;
    406         else if (strcmp(token, "MaxComputeWorkGroupCountY") == 0)
    407             Resources.maxComputeWorkGroupCountY = value;
    408         else if (strcmp(token, "MaxComputeWorkGroupCountZ") == 0)
    409             Resources.maxComputeWorkGroupCountZ = value;
    410         else if (strcmp(token, "MaxComputeWorkGroupSizeX") == 0)
    411             Resources.maxComputeWorkGroupSizeX = value;
    412         else if (strcmp(token, "MaxComputeWorkGroupSizeY") == 0)
    413             Resources.maxComputeWorkGroupSizeY = value;
    414         else if (strcmp(token, "MaxComputeWorkGroupSizeZ") == 0)
    415             Resources.maxComputeWorkGroupSizeZ = value;
    416         else if (strcmp(token, "MaxComputeUniformComponents") == 0)
    417             Resources.maxComputeUniformComponents = value;
    418         else if (strcmp(token, "MaxComputeTextureImageUnits") == 0)
    419             Resources.maxComputeTextureImageUnits = value;
    420         else if (strcmp(token, "MaxComputeImageUniforms") == 0)
    421             Resources.maxComputeImageUniforms = value;
    422         else if (strcmp(token, "MaxComputeAtomicCounters") == 0)
    423             Resources.maxComputeAtomicCounters = value;
    424         else if (strcmp(token, "MaxComputeAtomicCounterBuffers") == 0)
    425             Resources.maxComputeAtomicCounterBuffers = value;
    426         else if (strcmp(token, "MaxVaryingComponents") == 0)
    427             Resources.maxVaryingComponents = value;
    428         else if (strcmp(token, "MaxVertexOutputComponents") == 0)
    429             Resources.maxVertexOutputComponents = value;
    430         else if (strcmp(token, "MaxGeometryInputComponents") == 0)
    431             Resources.maxGeometryInputComponents = value;
    432         else if (strcmp(token, "MaxGeometryOutputComponents") == 0)
    433             Resources.maxGeometryOutputComponents = value;
    434         else if (strcmp(token, "MaxFragmentInputComponents") == 0)
    435             Resources.maxFragmentInputComponents = value;
    436         else if (strcmp(token, "MaxImageUnits") == 0)
    437             Resources.maxImageUnits = value;
    438         else if (strcmp(token, "MaxCombinedImageUnitsAndFragmentOutputs") == 0)
    439             Resources.maxCombinedImageUnitsAndFragmentOutputs = value;
    440         else if (strcmp(token, "MaxCombinedShaderOutputResources") == 0)
    441             Resources.maxCombinedShaderOutputResources = value;
    442         else if (strcmp(token, "MaxImageSamples") == 0)
    443             Resources.maxImageSamples = value;
    444         else if (strcmp(token, "MaxVertexImageUniforms") == 0)
    445             Resources.maxVertexImageUniforms = value;
    446         else if (strcmp(token, "MaxTessControlImageUniforms") == 0)
    447             Resources.maxTessControlImageUniforms = value;
    448         else if (strcmp(token, "MaxTessEvaluationImageUniforms") == 0)
    449             Resources.maxTessEvaluationImageUniforms = value;
    450         else if (strcmp(token, "MaxGeometryImageUniforms") == 0)
    451             Resources.maxGeometryImageUniforms = value;
    452         else if (strcmp(token, "MaxFragmentImageUniforms") == 0)
    453             Resources.maxFragmentImageUniforms = value;
    454         else if (strcmp(token, "MaxCombinedImageUniforms") == 0)
    455             Resources.maxCombinedImageUniforms = value;
    456         else if (strcmp(token, "MaxGeometryTextureImageUnits") == 0)
    457             Resources.maxGeometryTextureImageUnits = value;
    458         else if (strcmp(token, "MaxGeometryOutputVertices") == 0)
    459             Resources.maxGeometryOutputVertices = value;
    460         else if (strcmp(token, "MaxGeometryTotalOutputComponents") == 0)
    461             Resources.maxGeometryTotalOutputComponents = value;
    462         else if (strcmp(token, "MaxGeometryUniformComponents") == 0)
    463             Resources.maxGeometryUniformComponents = value;
    464         else if (strcmp(token, "MaxGeometryVaryingComponents") == 0)
    465             Resources.maxGeometryVaryingComponents = value;
    466         else if (strcmp(token, "MaxTessControlInputComponents") == 0)
    467             Resources.maxTessControlInputComponents = value;
    468         else if (strcmp(token, "MaxTessControlOutputComponents") == 0)
    469             Resources.maxTessControlOutputComponents = value;
    470         else if (strcmp(token, "MaxTessControlTextureImageUnits") == 0)
    471             Resources.maxTessControlTextureImageUnits = value;
    472         else if (strcmp(token, "MaxTessControlUniformComponents") == 0)
    473             Resources.maxTessControlUniformComponents = value;
    474         else if (strcmp(token, "MaxTessControlTotalOutputComponents") == 0)
    475             Resources.maxTessControlTotalOutputComponents = value;
    476         else if (strcmp(token, "MaxTessEvaluationInputComponents") == 0)
    477             Resources.maxTessEvaluationInputComponents = value;
    478         else if (strcmp(token, "MaxTessEvaluationOutputComponents") == 0)
    479             Resources.maxTessEvaluationOutputComponents = value;
    480         else if (strcmp(token, "MaxTessEvaluationTextureImageUnits") == 0)
    481             Resources.maxTessEvaluationTextureImageUnits = value;
    482         else if (strcmp(token, "MaxTessEvaluationUniformComponents") == 0)
    483             Resources.maxTessEvaluationUniformComponents = value;
    484         else if (strcmp(token, "MaxTessPatchComponents") == 0)
    485             Resources.maxTessPatchComponents = value;
    486         else if (strcmp(token, "MaxPatchVertices") == 0)
    487             Resources.maxPatchVertices = value;
    488         else if (strcmp(token, "MaxTessGenLevel") == 0)
    489             Resources.maxTessGenLevel = value;
    490         else if (strcmp(token, "MaxViewports") == 0)
    491             Resources.maxViewports = value;
    492         else if (strcmp(token, "MaxVertexAtomicCounters") == 0)
    493             Resources.maxVertexAtomicCounters = value;
    494         else if (strcmp(token, "MaxTessControlAtomicCounters") == 0)
    495             Resources.maxTessControlAtomicCounters = value;
    496         else if (strcmp(token, "MaxTessEvaluationAtomicCounters") == 0)
    497             Resources.maxTessEvaluationAtomicCounters = value;
    498         else if (strcmp(token, "MaxGeometryAtomicCounters") == 0)
    499             Resources.maxGeometryAtomicCounters = value;
    500         else if (strcmp(token, "MaxFragmentAtomicCounters") == 0)
    501             Resources.maxFragmentAtomicCounters = value;
    502         else if (strcmp(token, "MaxCombinedAtomicCounters") == 0)
    503             Resources.maxCombinedAtomicCounters = value;
    504         else if (strcmp(token, "MaxAtomicCounterBindings") == 0)
    505             Resources.maxAtomicCounterBindings = value;
    506         else if (strcmp(token, "MaxVertexAtomicCounterBuffers") == 0)
    507             Resources.maxVertexAtomicCounterBuffers = value;
    508         else if (strcmp(token, "MaxTessControlAtomicCounterBuffers") == 0)
    509             Resources.maxTessControlAtomicCounterBuffers = value;
    510         else if (strcmp(token, "MaxTessEvaluationAtomicCounterBuffers") == 0)
    511             Resources.maxTessEvaluationAtomicCounterBuffers = value;
    512         else if (strcmp(token, "MaxGeometryAtomicCounterBuffers") == 0)
    513             Resources.maxGeometryAtomicCounterBuffers = value;
    514         else if (strcmp(token, "MaxFragmentAtomicCounterBuffers") == 0)
    515             Resources.maxFragmentAtomicCounterBuffers = value;
    516         else if (strcmp(token, "MaxCombinedAtomicCounterBuffers") == 0)
    517             Resources.maxCombinedAtomicCounterBuffers = value;
    518         else if (strcmp(token, "MaxAtomicCounterBufferSize") == 0)
    519             Resources.maxAtomicCounterBufferSize = value;
    520         else if (strcmp(token, "MaxTransformFeedbackBuffers") == 0)
    521             Resources.maxTransformFeedbackBuffers = value;
    522         else if (strcmp(token, "MaxTransformFeedbackInterleavedComponents") == 0)
    523             Resources.maxTransformFeedbackInterleavedComponents = value;
    524         else if (strcmp(token, "MaxCullDistances") == 0)
    525             Resources.maxCullDistances = value;
    526         else if (strcmp(token, "MaxCombinedClipAndCullDistances") == 0)
    527             Resources.maxCombinedClipAndCullDistances = value;
    528         else if (strcmp(token, "MaxSamples") == 0)
    529             Resources.maxSamples = value;
    530 
    531         else if (strcmp(token, "nonInductiveForLoops") == 0)
    532             Resources.limits.nonInductiveForLoops = (value != 0);
    533         else if (strcmp(token, "whileLoops") == 0)
    534             Resources.limits.whileLoops = (value != 0);
    535         else if (strcmp(token, "doWhileLoops") == 0)
    536             Resources.limits.doWhileLoops = (value != 0);
    537         else if (strcmp(token, "generalUniformIndexing") == 0)
    538             Resources.limits.generalUniformIndexing = (value != 0);
    539         else if (strcmp(token, "generalAttributeMatrixVectorIndexing") == 0)
    540             Resources.limits.generalAttributeMatrixVectorIndexing = (value != 0);
    541         else if (strcmp(token, "generalVaryingIndexing") == 0)
    542             Resources.limits.generalVaryingIndexing = (value != 0);
    543         else if (strcmp(token, "generalSamplerIndexing") == 0)
    544             Resources.limits.generalSamplerIndexing = (value != 0);
    545         else if (strcmp(token, "generalVariableIndexing") == 0)
    546             Resources.limits.generalVariableIndexing = (value != 0);
    547         else if (strcmp(token, "generalConstantMatrixVectorIndexing") == 0)
    548             Resources.limits.generalConstantMatrixVectorIndexing = (value != 0);
    549         else
    550             printf("Warning: unrecognized limit (%s) in configuration file.\n", token);
    551 
    552         token = strtok(0, delims);
    553     }
    554     if (configStrings)
    555         FreeFileData(configStrings);
    556 }
    557 
    558 void VkTestFramework::SetMessageOptions(EShMessages &messages) {
    559     if (m_compile_options & EOptionRelaxedErrors)
    560         messages = (EShMessages)(messages | EShMsgRelaxedErrors);
    561     if (m_compile_options & EOptionIntermediate)
    562         messages = (EShMessages)(messages | EShMsgAST);
    563     if (m_compile_options & EOptionSuppressWarnings)
    564         messages = (EShMessages)(messages | EShMsgSuppressWarnings);
    565 }
    566 
    567 //
    568 //   Malloc a string of sufficient size and read a string into it.
    569 //
    570 char **VkTestFramework::ReadFileData(const char *fileName) {
    571     FILE *in;
    572 #if defined(_WIN32) && defined(__GNUC__)
    573     in = fopen(fileName, "r");
    574     int errorCode = in ? 0 : 1;
    575 #else
    576     int errorCode = fopen_s(&in, fileName, "r");
    577 #endif
    578 
    579     char *fdata;
    580     size_t count = 0;
    581     const int maxSourceStrings = 5;
    582     char **return_data = (char **)malloc(sizeof(char *) * (maxSourceStrings + 1));
    583 
    584     if (errorCode) {
    585         printf("Error: unable to open input file: %s\n", fileName);
    586         return 0;
    587     }
    588 
    589     while (fgetc(in) != EOF)
    590         count++;
    591 
    592     fseek(in, 0, SEEK_SET);
    593 
    594     if (!(fdata = (char *)malloc(count + 2))) {
    595         printf("Error allocating memory\n");
    596         return 0;
    597     }
    598     if (fread(fdata, 1, count, in) != count) {
    599         printf("Error reading input file: %s\n", fileName);
    600         return 0;
    601     }
    602     fdata[count] = '\0';
    603     fclose(in);
    604     if (count == 0) {
    605         return_data[0] = (char *)malloc(count + 2);
    606         return_data[0][0] = '\0';
    607         m_num_shader_strings = 0;
    608         return return_data;
    609     } else
    610         m_num_shader_strings = 1;
    611 
    612     size_t len = (int)(ceil)((float)count / (float)m_num_shader_strings);
    613     size_t ptr_len = 0, i = 0;
    614     while (count > 0) {
    615         return_data[i] = (char *)malloc(len + 2);
    616         memcpy(return_data[i], fdata + ptr_len, len);
    617         return_data[i][len] = '\0';
    618         count -= (len);
    619         ptr_len += (len);
    620         if (count < len) {
    621             if (count == 0) {
    622                 m_num_shader_strings = (i + 1);
    623                 break;
    624             }
    625             len = count;
    626         }
    627         ++i;
    628     }
    629     return return_data;
    630 }
    631 
    632 void VkTestFramework::FreeFileData(char **data) {
    633     for (int i = 0; i < m_num_shader_strings; i++)
    634         free(data[i]);
    635 }
    636 
    637 //
    638 //   Deduce the language from the filename.  Files must end in one of the
    639 //   following extensions:
    640 //
    641 //   .vert = vertex
    642 //   .tesc = tessellation control
    643 //   .tese = tessellation evaluation
    644 //   .geom = geometry
    645 //   .frag = fragment
    646 //   .comp = compute
    647 //
    648 EShLanguage VkTestFramework::FindLanguage(const std::string &name) {
    649     size_t ext = name.rfind('.');
    650     if (ext == std::string::npos) {
    651         return EShLangVertex;
    652     }
    653 
    654     std::string suffix = name.substr(ext + 1, std::string::npos);
    655     if (suffix == "vert")
    656         return EShLangVertex;
    657     else if (suffix == "tesc")
    658         return EShLangTessControl;
    659     else if (suffix == "tese")
    660         return EShLangTessEvaluation;
    661     else if (suffix == "geom")
    662         return EShLangGeometry;
    663     else if (suffix == "frag")
    664         return EShLangFragment;
    665     else if (suffix == "comp")
    666         return EShLangCompute;
    667 
    668     return EShLangVertex;
    669 }
    670 
    671 //
    672 // Convert VK shader type to compiler's
    673 //
    674 EShLanguage VkTestFramework::FindLanguage(const VkShaderStageFlagBits shader_type) {
    675     switch (shader_type) {
    676     case VK_SHADER_STAGE_VERTEX_BIT:
    677         return EShLangVertex;
    678 
    679     case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT:
    680         return EShLangTessControl;
    681 
    682     case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT:
    683         return EShLangTessEvaluation;
    684 
    685     case VK_SHADER_STAGE_GEOMETRY_BIT:
    686         return EShLangGeometry;
    687 
    688     case VK_SHADER_STAGE_FRAGMENT_BIT:
    689         return EShLangFragment;
    690 
    691     case VK_SHADER_STAGE_COMPUTE_BIT:
    692         return EShLangCompute;
    693 
    694     default:
    695         return EShLangVertex;
    696     }
    697 }
    698 
    699 //
    700 // Compile a given string containing GLSL into SPV for use by VK
    701 // Return value of false means an error was encountered.
    702 //
    703 bool VkTestFramework::GLSLtoSPV(const VkShaderStageFlagBits shader_type, const char *pshader, std::vector<unsigned int> &spirv) {
    704     glslang::TProgram program;
    705     const char *shaderStrings[1];
    706 
    707     // TODO: Do we want to load a special config file depending on the
    708     // shader source? Optional name maybe?
    709     //    SetConfigFile(fileName);
    710 
    711     ProcessConfigFile();
    712 
    713     EShMessages messages = EShMsgDefault;
    714     SetMessageOptions(messages);
    715     messages = static_cast<EShMessages>(messages | EShMsgSpvRules | EShMsgVulkanRules);
    716 
    717     EShLanguage stage = FindLanguage(shader_type);
    718     glslang::TShader *shader = new glslang::TShader(stage);
    719 
    720     shaderStrings[0] = pshader;
    721     shader->setStrings(shaderStrings, 1);
    722 
    723     if (!shader->parse(&Resources, (m_compile_options & EOptionDefaultDesktop) ? 110 : 100, false, messages)) {
    724 
    725         if (!(m_compile_options & EOptionSuppressInfolog)) {
    726             puts(shader->getInfoLog());
    727             puts(shader->getInfoDebugLog());
    728         }
    729 
    730         return false; // something didn't work
    731     }
    732 
    733     program.addShader(shader);
    734 
    735     //
    736     // Program-level processing...
    737     //
    738 
    739     if (!program.link(messages)) {
    740 
    741         if (!(m_compile_options & EOptionSuppressInfolog)) {
    742             puts(shader->getInfoLog());
    743             puts(shader->getInfoDebugLog());
    744         }
    745 
    746         return false;
    747     }
    748 
    749     if (m_compile_options & EOptionDumpReflection) {
    750         program.buildReflection();
    751         program.dumpReflection();
    752     }
    753 
    754     glslang::GlslangToSpv(*program.getIntermediate(stage), spirv);
    755 
    756     //
    757     // Test the different modes of SPIR-V modification
    758     //
    759     if (this->m_canonicalize_spv) {
    760         spv::spirvbin_t(0).remap(spirv, spv::spirvbin_t::ALL_BUT_STRIP);
    761     }
    762 
    763     if (this->m_strip_spv) {
    764         spv::spirvbin_t(0).remap(spirv, spv::spirvbin_t::STRIP);
    765     }
    766 
    767     if (this->m_do_everything_spv) {
    768         spv::spirvbin_t(0).remap(spirv, spv::spirvbin_t::DO_EVERYTHING);
    769     }
    770 
    771     delete shader;
    772 
    773     return true;
    774 }
    775