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