• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2015-2019 The Khronos Group Inc.
3  * Copyright (c) 2015-2019 Valve Corporation
4  * Copyright (c) 2015-2019 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 
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 
fopen_s(FILE ** pFile,const char * filename,const char * mode)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
SetUp()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 
TearDown()136 void TestEnvironment::TearDown() { glslang::FinalizeProcess(); }
137 
VkTestFramework()138 VkTestFramework::VkTestFramework() : m_compile_options(0), m_num_shader_strings(0) {}
139 
~VkTestFramework()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 
optionMatch(const char * option,char * optionLine)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 
InitArgs(int * argc,char * argv[])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 
GetFormat(VkInstance instance,vk_testing::Device * device)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 
Finish()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     "MaxMeshOutputVerticesNV 256\n"
319     "MaxMeshOutputPrimitivesNV 512\n"
320     "MaxMeshWorkGroupSizeX_NV 32\n"
321     "MaxMeshWorkGroupSizeY_NV 1\n"
322     "MaxMeshWorkGroupSizeZ_NV 1\n"
323     "MaxTaskWorkGroupSizeX_NV 32\n"
324     "MaxTaskWorkGroupSizeY_NV 1\n"
325     "MaxTaskWorkGroupSizeZ_NV 1\n"
326     "MaxMeshViewCountNV 4\n"
327 
328     "nonInductiveForLoops 1\n"
329     "whileLoops 1\n"
330     "doWhileLoops 1\n"
331     "generalUniformIndexing 1\n"
332     "generalAttributeMatrixVectorIndexing 1\n"
333     "generalVaryingIndexing 1\n"
334     "generalSamplerIndexing 1\n"
335     "generalVariableIndexing 1\n"
336     "generalConstantMatrixVectorIndexing 1\n";
337 
338 //
339 // *.conf => this is a config file that can set limits/resources
340 //
SetConfigFile(const std::string & name)341 bool VkTestFramework::SetConfigFile(const std::string &name) {
342     if (name.size() < 5) return false;
343 
344     if (name.compare(name.size() - 5, 5, ".conf") == 0) {
345         ConfigFile = name;
346         return true;
347     }
348 
349     return false;
350 }
351 
352 //
353 // Parse either a .conf file provided by the user or the default string above.
354 //
ProcessConfigFile()355 void VkTestFramework::ProcessConfigFile() {
356     char **configStrings = 0;
357     char *config = 0;
358     if (ConfigFile.size() > 0) {
359         configStrings = ReadFileData(ConfigFile.c_str());
360         if (configStrings)
361             config = *configStrings;
362         else {
363             printf("Error opening configuration file; will instead use the default configuration\n");
364         }
365     }
366 
367     if (config == 0) {
368         config = (char *)alloca(strlen(DefaultConfig) + 1);
369         strcpy(config, DefaultConfig);
370     }
371 
372     const char *delims = " \t\n\r";
373     const char *token = strtok(config, delims);
374     while (token) {
375         const char *valueStr = strtok(0, delims);
376         if (valueStr == 0 || !(valueStr[0] == '-' || (valueStr[0] >= '0' && valueStr[0] <= '9'))) {
377             printf("Error: '%s' bad .conf file.  Each name must be followed by one number.\n", valueStr ? valueStr : "");
378             return;
379         }
380         int value = atoi(valueStr);
381 
382         if (strcmp(token, "MaxLights") == 0)
383             Resources.maxLights = value;
384         else if (strcmp(token, "MaxClipPlanes") == 0)
385             Resources.maxClipPlanes = value;
386         else if (strcmp(token, "MaxTextureUnits") == 0)
387             Resources.maxTextureUnits = value;
388         else if (strcmp(token, "MaxTextureCoords") == 0)
389             Resources.maxTextureCoords = value;
390         else if (strcmp(token, "MaxVertexAttribs") == 0)
391             Resources.maxVertexAttribs = value;
392         else if (strcmp(token, "MaxVertexUniformComponents") == 0)
393             Resources.maxVertexUniformComponents = value;
394         else if (strcmp(token, "MaxVaryingFloats") == 0)
395             Resources.maxVaryingFloats = value;
396         else if (strcmp(token, "MaxVertexTextureImageUnits") == 0)
397             Resources.maxVertexTextureImageUnits = value;
398         else if (strcmp(token, "MaxCombinedTextureImageUnits") == 0)
399             Resources.maxCombinedTextureImageUnits = value;
400         else if (strcmp(token, "MaxTextureImageUnits") == 0)
401             Resources.maxTextureImageUnits = value;
402         else if (strcmp(token, "MaxFragmentUniformComponents") == 0)
403             Resources.maxFragmentUniformComponents = value;
404         else if (strcmp(token, "MaxDrawBuffers") == 0)
405             Resources.maxDrawBuffers = value;
406         else if (strcmp(token, "MaxVertexUniformVectors") == 0)
407             Resources.maxVertexUniformVectors = value;
408         else if (strcmp(token, "MaxVaryingVectors") == 0)
409             Resources.maxVaryingVectors = value;
410         else if (strcmp(token, "MaxFragmentUniformVectors") == 0)
411             Resources.maxFragmentUniformVectors = value;
412         else if (strcmp(token, "MaxVertexOutputVectors") == 0)
413             Resources.maxVertexOutputVectors = value;
414         else if (strcmp(token, "MaxFragmentInputVectors") == 0)
415             Resources.maxFragmentInputVectors = value;
416         else if (strcmp(token, "MinProgramTexelOffset") == 0)
417             Resources.minProgramTexelOffset = value;
418         else if (strcmp(token, "MaxProgramTexelOffset") == 0)
419             Resources.maxProgramTexelOffset = value;
420         else if (strcmp(token, "MaxClipDistances") == 0)
421             Resources.maxClipDistances = value;
422         else if (strcmp(token, "MaxComputeWorkGroupCountX") == 0)
423             Resources.maxComputeWorkGroupCountX = value;
424         else if (strcmp(token, "MaxComputeWorkGroupCountY") == 0)
425             Resources.maxComputeWorkGroupCountY = value;
426         else if (strcmp(token, "MaxComputeWorkGroupCountZ") == 0)
427             Resources.maxComputeWorkGroupCountZ = value;
428         else if (strcmp(token, "MaxComputeWorkGroupSizeX") == 0)
429             Resources.maxComputeWorkGroupSizeX = value;
430         else if (strcmp(token, "MaxComputeWorkGroupSizeY") == 0)
431             Resources.maxComputeWorkGroupSizeY = value;
432         else if (strcmp(token, "MaxComputeWorkGroupSizeZ") == 0)
433             Resources.maxComputeWorkGroupSizeZ = value;
434         else if (strcmp(token, "MaxComputeUniformComponents") == 0)
435             Resources.maxComputeUniformComponents = value;
436         else if (strcmp(token, "MaxComputeTextureImageUnits") == 0)
437             Resources.maxComputeTextureImageUnits = value;
438         else if (strcmp(token, "MaxComputeImageUniforms") == 0)
439             Resources.maxComputeImageUniforms = value;
440         else if (strcmp(token, "MaxComputeAtomicCounters") == 0)
441             Resources.maxComputeAtomicCounters = value;
442         else if (strcmp(token, "MaxComputeAtomicCounterBuffers") == 0)
443             Resources.maxComputeAtomicCounterBuffers = value;
444         else if (strcmp(token, "MaxVaryingComponents") == 0)
445             Resources.maxVaryingComponents = value;
446         else if (strcmp(token, "MaxVertexOutputComponents") == 0)
447             Resources.maxVertexOutputComponents = value;
448         else if (strcmp(token, "MaxGeometryInputComponents") == 0)
449             Resources.maxGeometryInputComponents = value;
450         else if (strcmp(token, "MaxGeometryOutputComponents") == 0)
451             Resources.maxGeometryOutputComponents = value;
452         else if (strcmp(token, "MaxFragmentInputComponents") == 0)
453             Resources.maxFragmentInputComponents = value;
454         else if (strcmp(token, "MaxImageUnits") == 0)
455             Resources.maxImageUnits = value;
456         else if (strcmp(token, "MaxCombinedImageUnitsAndFragmentOutputs") == 0)
457             Resources.maxCombinedImageUnitsAndFragmentOutputs = value;
458         else if (strcmp(token, "MaxCombinedShaderOutputResources") == 0)
459             Resources.maxCombinedShaderOutputResources = value;
460         else if (strcmp(token, "MaxImageSamples") == 0)
461             Resources.maxImageSamples = value;
462         else if (strcmp(token, "MaxVertexImageUniforms") == 0)
463             Resources.maxVertexImageUniforms = value;
464         else if (strcmp(token, "MaxTessControlImageUniforms") == 0)
465             Resources.maxTessControlImageUniforms = value;
466         else if (strcmp(token, "MaxTessEvaluationImageUniforms") == 0)
467             Resources.maxTessEvaluationImageUniforms = value;
468         else if (strcmp(token, "MaxGeometryImageUniforms") == 0)
469             Resources.maxGeometryImageUniforms = value;
470         else if (strcmp(token, "MaxFragmentImageUniforms") == 0)
471             Resources.maxFragmentImageUniforms = value;
472         else if (strcmp(token, "MaxCombinedImageUniforms") == 0)
473             Resources.maxCombinedImageUniforms = value;
474         else if (strcmp(token, "MaxGeometryTextureImageUnits") == 0)
475             Resources.maxGeometryTextureImageUnits = value;
476         else if (strcmp(token, "MaxGeometryOutputVertices") == 0)
477             Resources.maxGeometryOutputVertices = value;
478         else if (strcmp(token, "MaxGeometryTotalOutputComponents") == 0)
479             Resources.maxGeometryTotalOutputComponents = value;
480         else if (strcmp(token, "MaxGeometryUniformComponents") == 0)
481             Resources.maxGeometryUniformComponents = value;
482         else if (strcmp(token, "MaxGeometryVaryingComponents") == 0)
483             Resources.maxGeometryVaryingComponents = value;
484         else if (strcmp(token, "MaxTessControlInputComponents") == 0)
485             Resources.maxTessControlInputComponents = value;
486         else if (strcmp(token, "MaxTessControlOutputComponents") == 0)
487             Resources.maxTessControlOutputComponents = value;
488         else if (strcmp(token, "MaxTessControlTextureImageUnits") == 0)
489             Resources.maxTessControlTextureImageUnits = value;
490         else if (strcmp(token, "MaxTessControlUniformComponents") == 0)
491             Resources.maxTessControlUniformComponents = value;
492         else if (strcmp(token, "MaxTessControlTotalOutputComponents") == 0)
493             Resources.maxTessControlTotalOutputComponents = value;
494         else if (strcmp(token, "MaxTessEvaluationInputComponents") == 0)
495             Resources.maxTessEvaluationInputComponents = value;
496         else if (strcmp(token, "MaxTessEvaluationOutputComponents") == 0)
497             Resources.maxTessEvaluationOutputComponents = value;
498         else if (strcmp(token, "MaxTessEvaluationTextureImageUnits") == 0)
499             Resources.maxTessEvaluationTextureImageUnits = value;
500         else if (strcmp(token, "MaxTessEvaluationUniformComponents") == 0)
501             Resources.maxTessEvaluationUniformComponents = value;
502         else if (strcmp(token, "MaxTessPatchComponents") == 0)
503             Resources.maxTessPatchComponents = value;
504         else if (strcmp(token, "MaxPatchVertices") == 0)
505             Resources.maxPatchVertices = value;
506         else if (strcmp(token, "MaxTessGenLevel") == 0)
507             Resources.maxTessGenLevel = value;
508         else if (strcmp(token, "MaxViewports") == 0)
509             Resources.maxViewports = value;
510         else if (strcmp(token, "MaxVertexAtomicCounters") == 0)
511             Resources.maxVertexAtomicCounters = value;
512         else if (strcmp(token, "MaxTessControlAtomicCounters") == 0)
513             Resources.maxTessControlAtomicCounters = value;
514         else if (strcmp(token, "MaxTessEvaluationAtomicCounters") == 0)
515             Resources.maxTessEvaluationAtomicCounters = value;
516         else if (strcmp(token, "MaxGeometryAtomicCounters") == 0)
517             Resources.maxGeometryAtomicCounters = value;
518         else if (strcmp(token, "MaxFragmentAtomicCounters") == 0)
519             Resources.maxFragmentAtomicCounters = value;
520         else if (strcmp(token, "MaxCombinedAtomicCounters") == 0)
521             Resources.maxCombinedAtomicCounters = value;
522         else if (strcmp(token, "MaxAtomicCounterBindings") == 0)
523             Resources.maxAtomicCounterBindings = value;
524         else if (strcmp(token, "MaxVertexAtomicCounterBuffers") == 0)
525             Resources.maxVertexAtomicCounterBuffers = value;
526         else if (strcmp(token, "MaxTessControlAtomicCounterBuffers") == 0)
527             Resources.maxTessControlAtomicCounterBuffers = value;
528         else if (strcmp(token, "MaxTessEvaluationAtomicCounterBuffers") == 0)
529             Resources.maxTessEvaluationAtomicCounterBuffers = value;
530         else if (strcmp(token, "MaxGeometryAtomicCounterBuffers") == 0)
531             Resources.maxGeometryAtomicCounterBuffers = value;
532         else if (strcmp(token, "MaxFragmentAtomicCounterBuffers") == 0)
533             Resources.maxFragmentAtomicCounterBuffers = value;
534         else if (strcmp(token, "MaxCombinedAtomicCounterBuffers") == 0)
535             Resources.maxCombinedAtomicCounterBuffers = value;
536         else if (strcmp(token, "MaxAtomicCounterBufferSize") == 0)
537             Resources.maxAtomicCounterBufferSize = value;
538         else if (strcmp(token, "MaxTransformFeedbackBuffers") == 0)
539             Resources.maxTransformFeedbackBuffers = value;
540         else if (strcmp(token, "MaxTransformFeedbackInterleavedComponents") == 0)
541             Resources.maxTransformFeedbackInterleavedComponents = value;
542         else if (strcmp(token, "MaxCullDistances") == 0)
543             Resources.maxCullDistances = value;
544         else if (strcmp(token, "MaxCombinedClipAndCullDistances") == 0)
545             Resources.maxCombinedClipAndCullDistances = value;
546         else if (strcmp(token, "MaxSamples") == 0)
547             Resources.maxSamples = value;
548         else if (strcmp(token, "MaxMeshOutputVerticesNV") == 0)
549             Resources.maxMeshOutputVerticesNV = value;
550         else if (strcmp(token, "MaxMeshOutputPrimitivesNV") == 0)
551             Resources.maxMeshOutputPrimitivesNV = value;
552         else if (strcmp(token, "MaxMeshWorkGroupSizeX_NV") == 0)
553             Resources.maxMeshWorkGroupSizeX_NV = value;
554         else if (strcmp(token, "MaxMeshWorkGroupSizeY_NV") == 0)
555             Resources.maxMeshWorkGroupSizeY_NV = value;
556         else if (strcmp(token, "MaxMeshWorkGroupSizeZ_NV") == 0)
557             Resources.maxMeshWorkGroupSizeZ_NV = value;
558         else if (strcmp(token, "MaxTaskWorkGroupSizeX_NV") == 0)
559             Resources.maxTaskWorkGroupSizeX_NV = value;
560         else if (strcmp(token, "MaxTaskWorkGroupSizeY_NV") == 0)
561             Resources.maxTaskWorkGroupSizeY_NV = value;
562         else if (strcmp(token, "MaxTaskWorkGroupSizeZ_NV") == 0)
563             Resources.maxTaskWorkGroupSizeZ_NV = value;
564         else if (strcmp(token, "MaxMeshViewCountNV") == 0)
565             Resources.maxMeshViewCountNV = value;
566 
567         else if (strcmp(token, "nonInductiveForLoops") == 0)
568             Resources.limits.nonInductiveForLoops = (value != 0);
569         else if (strcmp(token, "whileLoops") == 0)
570             Resources.limits.whileLoops = (value != 0);
571         else if (strcmp(token, "doWhileLoops") == 0)
572             Resources.limits.doWhileLoops = (value != 0);
573         else if (strcmp(token, "generalUniformIndexing") == 0)
574             Resources.limits.generalUniformIndexing = (value != 0);
575         else if (strcmp(token, "generalAttributeMatrixVectorIndexing") == 0)
576             Resources.limits.generalAttributeMatrixVectorIndexing = (value != 0);
577         else if (strcmp(token, "generalVaryingIndexing") == 0)
578             Resources.limits.generalVaryingIndexing = (value != 0);
579         else if (strcmp(token, "generalSamplerIndexing") == 0)
580             Resources.limits.generalSamplerIndexing = (value != 0);
581         else if (strcmp(token, "generalVariableIndexing") == 0)
582             Resources.limits.generalVariableIndexing = (value != 0);
583         else if (strcmp(token, "generalConstantMatrixVectorIndexing") == 0)
584             Resources.limits.generalConstantMatrixVectorIndexing = (value != 0);
585         else
586             printf("Warning: unrecognized limit (%s) in configuration file.\n", token);
587 
588         token = strtok(0, delims);
589     }
590     if (configStrings) FreeFileData(configStrings);
591 }
592 
SetMessageOptions(EShMessages & messages)593 void VkTestFramework::SetMessageOptions(EShMessages &messages) {
594     if (m_compile_options & EOptionRelaxedErrors) messages = (EShMessages)(messages | EShMsgRelaxedErrors);
595     if (m_compile_options & EOptionIntermediate) messages = (EShMessages)(messages | EShMsgAST);
596     if (m_compile_options & EOptionSuppressWarnings) messages = (EShMessages)(messages | EShMsgSuppressWarnings);
597 }
598 
599 //
600 //   Malloc a string of sufficient size and read a string into it.
601 //
ReadFileData(const char * fileName)602 char **VkTestFramework::ReadFileData(const char *fileName) {
603     FILE *in;
604 #if defined(_WIN32) && defined(__GNUC__)
605     in = fopen(fileName, "r");
606     int errorCode = in ? 0 : 1;
607 #else
608     int errorCode = fopen_s(&in, fileName, "r");
609 #endif
610 
611     char *fdata;
612     size_t count = 0;
613     const int maxSourceStrings = 5;
614     char **return_data = (char **)malloc(sizeof(char *) * (maxSourceStrings + 1));
615 
616     if (errorCode) {
617         printf("Error: unable to open input file: %s\n", fileName);
618         return 0;
619     }
620 
621     while (fgetc(in) != EOF) count++;
622 
623     fseek(in, 0, SEEK_SET);
624 
625     if (!(fdata = (char *)malloc(count + 2))) {
626         printf("Error allocating memory\n");
627         return 0;
628     }
629     if (fread(fdata, 1, count, in) != count) {
630         printf("Error reading input file: %s\n", fileName);
631         return 0;
632     }
633     fdata[count] = '\0';
634     fclose(in);
635     if (count == 0) {
636         return_data[0] = (char *)malloc(count + 2);
637         return_data[0][0] = '\0';
638         m_num_shader_strings = 0;
639         return return_data;
640     } else
641         m_num_shader_strings = 1;
642 
643     size_t len = (int)(ceil)((float)count / (float)m_num_shader_strings);
644     size_t ptr_len = 0, i = 0;
645     while (count > 0) {
646         return_data[i] = (char *)malloc(len + 2);
647         memcpy(return_data[i], fdata + ptr_len, len);
648         return_data[i][len] = '\0';
649         count -= (len);
650         ptr_len += (len);
651         if (count < len) {
652             if (count == 0) {
653                 m_num_shader_strings = (i + 1);
654                 break;
655             }
656             len = count;
657         }
658         ++i;
659     }
660     return return_data;
661 }
662 
FreeFileData(char ** data)663 void VkTestFramework::FreeFileData(char **data) {
664     for (int i = 0; i < m_num_shader_strings; i++) free(data[i]);
665 }
666 
667 //
668 //   Deduce the language from the filename.  Files must end in one of the
669 //   following extensions:
670 //
671 //   .vert = vertex
672 //   .tesc = tessellation control
673 //   .tese = tessellation evaluation
674 //   .geom = geometry
675 //   .frag = fragment
676 //   .comp = compute
677 //
FindLanguage(const std::string & name)678 EShLanguage VkTestFramework::FindLanguage(const std::string &name) {
679     size_t ext = name.rfind('.');
680     if (ext == std::string::npos) {
681         return EShLangVertex;
682     }
683 
684     std::string suffix = name.substr(ext + 1, std::string::npos);
685     if (suffix == "vert")
686         return EShLangVertex;
687     else if (suffix == "tesc")
688         return EShLangTessControl;
689     else if (suffix == "tese")
690         return EShLangTessEvaluation;
691     else if (suffix == "geom")
692         return EShLangGeometry;
693     else if (suffix == "frag")
694         return EShLangFragment;
695     else if (suffix == "comp")
696         return EShLangCompute;
697 
698     return EShLangVertex;
699 }
700 
701 //
702 // Convert VK shader type to compiler's
703 //
FindLanguage(const VkShaderStageFlagBits shader_type)704 EShLanguage VkTestFramework::FindLanguage(const VkShaderStageFlagBits shader_type) {
705     switch (shader_type) {
706         case VK_SHADER_STAGE_VERTEX_BIT:
707             return EShLangVertex;
708 
709         case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT:
710             return EShLangTessControl;
711 
712         case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT:
713             return EShLangTessEvaluation;
714 
715         case VK_SHADER_STAGE_GEOMETRY_BIT:
716             return EShLangGeometry;
717 
718         case VK_SHADER_STAGE_FRAGMENT_BIT:
719             return EShLangFragment;
720 
721         case VK_SHADER_STAGE_COMPUTE_BIT:
722             return EShLangCompute;
723 
724         case VK_SHADER_STAGE_RAYGEN_BIT_NV:
725             return EShLangRayGenNV;
726 
727         case VK_SHADER_STAGE_ANY_HIT_BIT_NV:
728             return EShLangAnyHitNV;
729 
730         case VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV:
731             return EShLangClosestHitNV;
732 
733         case VK_SHADER_STAGE_MISS_BIT_NV:
734             return EShLangMissNV;
735 
736         case VK_SHADER_STAGE_INTERSECTION_BIT_NV:
737             return EShLangIntersectNV;
738 
739         case VK_SHADER_STAGE_CALLABLE_BIT_NV:
740             return EShLangCallableNV;
741 
742         case VK_SHADER_STAGE_TASK_BIT_NV:
743             return EShLangTaskNV;
744 
745         case VK_SHADER_STAGE_MESH_BIT_NV:
746             return EShLangMeshNV;
747 
748         default:
749             return EShLangVertex;
750     }
751 }
752 
753 //
754 // Compile a given string containing GLSL into SPV for use by VK
755 // Return value of false means an error was encountered.
756 //
GLSLtoSPV(const VkShaderStageFlagBits shader_type,const char * pshader,std::vector<unsigned int> & spirv,bool debug)757 bool VkTestFramework::GLSLtoSPV(const VkShaderStageFlagBits shader_type, const char *pshader, std::vector<unsigned int> &spirv,
758                                 bool debug) {
759     glslang::TProgram program;
760     const char *shaderStrings[1];
761 
762     // TODO: Do we want to load a special config file depending on the
763     // shader source? Optional name maybe?
764     //    SetConfigFile(fileName);
765 
766     ProcessConfigFile();
767 
768     EShMessages messages = EShMsgDefault;
769     SetMessageOptions(messages);
770     messages = static_cast<EShMessages>(messages | EShMsgSpvRules | EShMsgVulkanRules);
771     if (debug) {
772         messages = static_cast<EShMessages>(messages | EShMsgDebugInfo);
773     }
774 
775     EShLanguage stage = FindLanguage(shader_type);
776     glslang::TShader *shader = new glslang::TShader(stage);
777 
778     shaderStrings[0] = pshader;
779     shader->setStrings(shaderStrings, 1);
780 
781     if (!shader->parse(&Resources, (m_compile_options & EOptionDefaultDesktop) ? 110 : 100, false, messages)) {
782         if (!(m_compile_options & EOptionSuppressInfolog)) {
783             puts(shader->getInfoLog());
784             puts(shader->getInfoDebugLog());
785         }
786 
787         return false;  // something didn't work
788     }
789 
790     program.addShader(shader);
791 
792     //
793     // Program-level processing...
794     //
795 
796     if (!program.link(messages)) {
797         if (!(m_compile_options & EOptionSuppressInfolog)) {
798             puts(shader->getInfoLog());
799             puts(shader->getInfoDebugLog());
800         }
801 
802         return false;
803     }
804 
805     if (m_compile_options & EOptionDumpReflection) {
806         program.buildReflection();
807         program.dumpReflection();
808     }
809 
810     glslang::SpvOptions spv_options;
811     if (debug) {
812         spv_options.generateDebugInfo = true;
813     }
814     glslang::GlslangToSpv(*program.getIntermediate(stage), spirv, &spv_options);
815 
816     //
817     // Test the different modes of SPIR-V modification
818     //
819     if (this->m_canonicalize_spv) {
820         spv::spirvbin_t(0).remap(spirv, spv::spirvbin_t::ALL_BUT_STRIP);
821     }
822 
823     if (this->m_strip_spv) {
824         spv::spirvbin_t(0).remap(spirv, spv::spirvbin_t::STRIP);
825     }
826 
827     if (this->m_do_everything_spv) {
828         spv::spirvbin_t(0).remap(spirv, spv::spirvbin_t::DO_EVERYTHING);
829     }
830 
831     delete shader;
832 
833     return true;
834 }
835 
836 //
837 // Compile a given string containing SPIR-V assembly into SPV for use by VK
838 // Return value of false means an error was encountered.
839 //
ASMtoSPV(const spv_target_env target_env,const uint32_t options,const char * pasm,std::vector<unsigned int> & spv)840 bool VkTestFramework::ASMtoSPV(const spv_target_env target_env, const uint32_t options, const char *pasm,
841                                std::vector<unsigned int> &spv) {
842     spv_binary binary;
843     spv_diagnostic diagnostic = nullptr;
844     spv_context context = spvContextCreate(target_env);
845     spv_result_t error = spvTextToBinaryWithOptions(context, pasm, strlen(pasm), options, &binary, &diagnostic);
846     spvContextDestroy(context);
847     if (error) {
848         spvDiagnosticPrint(diagnostic);
849         spvDiagnosticDestroy(diagnostic);
850         return false;
851     }
852     spv.insert(spv.end(), binary->code, binary->code + binary->wordCount);
853     spvBinaryDestroy(binary);
854 
855     return true;
856 }
857