• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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@gmail.com>
19  * Author: Courtney Goeltzenleuchter <courtney@LunarG.com>
20  * Author: Tony Barbour <tony@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 
fopen_s(FILE ** pFile,const char * filename,const char * mode)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
SetUp()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 
TearDown()125 void TestEnvironment::TearDown() { glslang::FinalizeProcess(); }
126 
VkTestFramework()127 VkTestFramework::VkTestFramework() : m_compile_options(0), m_num_shader_strings(0) {}
128 
~VkTestFramework()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 
optionMatch(const char * option,char * optionLine)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 
InitArgs(int * argc,char * argv[])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 
GetFormat(VkInstance instance,vk_testing::Device * device)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 
Finish()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 //
SetConfigFile(const std::string & name)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 //
ProcessConfigFile()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 
SetMessageOptions(EShMessages & messages)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 //
ReadFileData(const char * fileName)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 
FreeFileData(char ** data)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 //
FindLanguage(const std::string & name)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 //
FindLanguage(const VkShaderStageFlagBits shader_type)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 //
GLSLtoSPV(const VkShaderStageFlagBits shader_type,const char * pshader,std::vector<unsigned int> & spirv)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